Pantallas y ruteo
Ruteo tipado
Toda pantalla es un standalone component lazy-loaded desde una ruta declarada con typesafe-routes. Cada nivel tiene dos objetos: uno typed (para construir paths sin strings) y uno de Angular.
// pages/<feature>/<feature>.routes.ts
export const depositTypedRoutes = createRoutes({
stats: { path: ['stats'] },
authorizations: { path: ['authorizations'] },
detail: { path: ['detail', int('id')] },
});
export const depositRoutes: Routes = [
{
path: template(depositTypedRoutes.stats),
loadComponent: () =>
import('./deposit-stats/deposit-stats.component').then(m => m.DepositStatsComponent),
},
];
template(typedRoute)→ elpath:de Angular.renderPath(typedRoute, params)→ la URL pararouterLink/router.navigate.- Params:
int('id'),str('name').
Nunca armes la URL a mano donde existe la ruta tipada.
La composición es app.routes.ts → pages/private.routes.ts + pages/public.routes.ts →
<feature>.routes.ts. appTypedRoutes funde los tres, así renderPath(appTypedRoutes.x.y, {})
funciona desde cualquier lado.
typesafe-routes también se usa para URLs de API (src/app/api/api.routes.ts), con la
convención método + nombre (GET_pdf, POST_receive). Hoy solo están migrados los endpoints de
delivery-note; el resto arma strings en los servicios.
Los tres shells
| Shell | Cuándo | Guard |
|---|---|---|
LayoutComponent | App autenticada (header + menú) | redirectUnauthorizedToLogin() |
PublicLayoutComponent | Login, recuperar contraseña | redirectLoggedInToHome() |
LayoutWithoutHeaderComponent | Landing de descarga de BullStock (/download/mobile/bullstock) | autenticado |
La ruta privada '' redirige a deposit/authorizations: esa es la home real de la app.
Mapa de pantallas
| Ruta | Carpeta | Qué es |
|---|---|---|
deposit/* | pages/deposit/ | La feature más grande. Autorizaciones, estadísticas, ingreso de mercadería, transferencias, recepciones, movimientos de stock, facturación, carga de remito de despacho. Servicios propios: deposit.service.ts y stock.service.ts |
patients/* | pages/patients/ | Padrón (registry) y atenciones |
delivery-notes | pages/delivery-notes/ | Listado de remitos; desde acá se abren aceptar y recibir de los tres tipos |
dispatch-notes | pages/delivery-dispatchs/ | Hojas de ruta (envíos) |
dispatch-delivery-notes/* | pages/dispatch-delivery-notes/ | Flujo de despacho con escáner |
receive-delivery-notes/* | pages/receive-delivery-notes/ | Flujo de recepción con escáner, por pasos |
staff/* | pages/vehicles/ | Flota: asignaciones, inspecciones VTV/RTO/seguro, eventos. Ojo: la ruta es staff, la carpeta es vehicles |
configuration/* | pages/configuration/ | ABM de Elementos y Productos (+ hijos e imágenes). Gateado por rol ADMIN estricto |
call-center | pages/call-center/ | Atención telefónica |
messages | pages/messages/ | |
reports | pages/reports/ | Descarga de reportes Excel |
surveys | pages/surveys/ | Encuestas |
notifications | pages/notifications/ | Centro de notificaciones, con vista tipo mail y preview del PDF del remito |
map | pages/map/ | Visualización geográfica |
user/history | pages/user/ | "Mi actividad" |
pages/table/es una página demo con datos hardcodeados ({ name: 'John Doe', … }). Está ruteada en/tablepero no figura en el menú. No la uses de molde: no representa cómo se hace una tabla real acá.pages/register/existe como componente pero su ruta no está registrada: es inalcanzable.
Menú
services/menu.service.ts devuelve el árbol de MenuItem[] de PrimeNG para header y sidebar.
- Hay bastante menú comentado; el vigente arranca en "Estadísticas".
- El grupo Configuración se agrega condicionalmente con
userAccessService.isAdmin(), que compararole.name === 'ADMIN'— el mismo criterio estricto que usa el backend. Si desalineás uno de los dos, el menú muestra una sección que la API rechaza. - El grupo Mercadería todavía usa iconos FontAwesome (
fa fa-…); el resto usa PrimeIcons.
Guards
| Guard | Qué hace |
|---|---|
auth.guard.ts | redirectUnauthorizedToLogin() / redirectLoggedInToHome() sobre el estado de Clerk |
permission.guard.ts | requirePermission(code) y requireRole(name). Al fallar: toast "Acceso denegado" + navegación a deposit/authorizations |
CanDeactivate locales | Por feature, para formularios con cambios sin guardar (attention-form-can-deactivate.guard.ts, dispatch-scanner-can-deactivate.guard.ts) |
Ver Permisos y roles.
Estado de la tabla entre navegaciones
El estado de una p-table (orden, página, filtros) se persiste en sessionStorage con claves de
enums/table-state-key.enum.ts; la pestaña activa va a localStorage con
enums/local-storage.enum.ts.
Si agregás una tabla que tenga que "volver como estaba", sumá tu clave a esos enums en vez de inventar un string suelto.