sapenlinea-components 0.13.100 → 0.13.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +400 -14
- package/fesm2022/sapenlinea-components.mjs +60 -37
- package/fesm2022/sapenlinea-components.mjs.map +1 -1
- package/index.d.ts +22 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -482,7 +482,7 @@ Componente de **paginación** para tablas o listas, con opción de selector de t
|
|
|
482
482
|
### 10. `lib-table` (Table)
|
|
483
483
|
|
|
484
484
|
**Qué hace**
|
|
485
|
-
Componente de **tabla dinámica** con soporte de ordenamiento, acciones por fila, estados con tonos configurables y traducción de estados mediante enum.
|
|
485
|
+
Componente de **tabla dinámica** con soporte de ordenamiento, acciones por fila, filas expandibles, selección múltiple, totales, column groups, estados con tonos configurables y traducción de estados mediante enum.
|
|
486
486
|
|
|
487
487
|
**Selector:** `lib-table`
|
|
488
488
|
|
|
@@ -495,8 +495,14 @@ Componente de **tabla dinámica** con soporte de ordenamiento, acciones por fila
|
|
|
495
495
|
- `subColumns: SubColumn[]` – Columnas de las sub-filas expandibles.
|
|
496
496
|
- `subActions: TableAction[] | ((row: TableRow) => TableAction[])` – Acciones por sub-fila.
|
|
497
497
|
- `showSubActions: boolean = false` – Muestra/oculta acciones en sub-filas.
|
|
498
|
+
- `isRowExpandable: (row: TableRow) => boolean = () => false` – Determina si una fila puede expandirse.
|
|
499
|
+
- `expandedChildren: (row: TableRow) => TableRow[] | null = () => null` – Proveedor de sub-filas al expandir.
|
|
500
|
+
- `rowIdKey: string = 'id'` – Propiedad del row usada como identificador para expansión y selección.
|
|
501
|
+
- `showSelection: boolean = false` – Muestra columna de checkboxes para selección múltiple.
|
|
502
|
+
- `showTotals: boolean = false` – Muestra fila de totales (columnas `money` con `totalizable: true`).
|
|
503
|
+
- `columnGroups: ColumnGroup[] = []` – Grupos de columnas adicionales (checkbox, número, icon-button, porcentaje).
|
|
498
504
|
- `statusToneMap: StatusToneMap` – Mapa de estado normalizado → tono visual.
|
|
499
|
-
- `statusEnumMap: Record<string, string>` – Traduce el valor crudo del estado a la etiqueta visible.
|
|
505
|
+
- `statusEnumMap: Record<number | string, string>` – Traduce el valor crudo del estado a la etiqueta visible.
|
|
500
506
|
|
|
501
507
|
**Tipos de columna (`type`):**
|
|
502
508
|
|
|
@@ -554,9 +560,70 @@ subColumns: SubColumn[] = [
|
|
|
554
560
|
{ key: 'placa', label: 'PLACA', type: 'text', widthProfile: 'fixed', maxWidth: 120 }
|
|
555
561
|
```
|
|
556
562
|
|
|
557
|
-
`columnGroups`
|
|
563
|
+
**Column groups (`columnGroups`):**
|
|
558
564
|
|
|
559
|
-
|
|
565
|
+
Grupos de columnas adicionales al final de la tabla (anexos, checkboxes, acciones inline). Mantienen celdas estrechas fijas (~56px) sin configuración adicional.
|
|
566
|
+
|
|
567
|
+
```ts
|
|
568
|
+
export interface ColumnGroup {
|
|
569
|
+
groupLabel: string;
|
|
570
|
+
columns: ColumnGroupItem[];
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
export interface ColumnGroupItem {
|
|
574
|
+
key: string;
|
|
575
|
+
label: string;
|
|
576
|
+
description: string;
|
|
577
|
+
type?: 'checkbox' | 'number' | 'icon-button' | 'percentage';
|
|
578
|
+
icon?: string;
|
|
579
|
+
iconAlternate?: string;
|
|
580
|
+
iconActiveKey?: string;
|
|
581
|
+
isIconActive?: (row: TableRow) => boolean;
|
|
582
|
+
disabledKey?: string;
|
|
583
|
+
isIconDisabled?: (row: TableRow) => boolean;
|
|
584
|
+
iconColor?: string;
|
|
585
|
+
iconAlternateColor?: string;
|
|
586
|
+
/** Key del row con URL(s) del archivo a visualizar al hacer clic en checkbox marcado */
|
|
587
|
+
fileUrlKey?: string;
|
|
588
|
+
/** Key del row para el nombre del archivo en el visor (default: label de la columna) */
|
|
589
|
+
fileNameKey?: string;
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
- Checkbox marcado con `fileUrlKey` (o valor string en la celda) abre el visor PDF/imagen vía `PdfViewerService`.
|
|
594
|
+
- Cambios en checkbox emiten `columnGroupChange`.
|
|
595
|
+
|
|
596
|
+
**Filas expandibles:**
|
|
597
|
+
|
|
598
|
+
```html
|
|
599
|
+
<lib-table
|
|
600
|
+
[columns]="columns"
|
|
601
|
+
[data]="rows"
|
|
602
|
+
[subColumns]="subColumns"
|
|
603
|
+
[isRowExpandable]="canExpand"
|
|
604
|
+
[expandedChildren]="getChildren"
|
|
605
|
+
rowIdKey="id"
|
|
606
|
+
/>
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
```ts
|
|
610
|
+
canExpand = (row: TableRow) => !!row.hasChildren;
|
|
611
|
+
getChildren = (row: TableRow) => row.children ?? [];
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
**Selección múltiple (`showSelection`):**
|
|
615
|
+
|
|
616
|
+
Activa checkboxes en encabezado y filas. El estado interno (`selectedRows`) se gestiona en el componente; expone métodos `toggleRow`, `toggleAllRows`, `isRowSelected`, `isAllSelected` vía la instancia.
|
|
617
|
+
|
|
618
|
+
**Fila de totales (`showTotals`):**
|
|
619
|
+
|
|
620
|
+
Suma automáticamente columnas con `type: 'money'` y `totalizable: true`.
|
|
621
|
+
|
|
622
|
+
**Menú de acciones:**
|
|
623
|
+
|
|
624
|
+
El panel contextual se renderiza con `position: fixed` adjunto a `document.body`, se reposiciona en scroll/resize y elige abrir hacia arriba o abajo según el espacio disponible.
|
|
625
|
+
|
|
626
|
+
Helpers exportados: `resolveTableColumnLayout`, `getTableMinWidth`, `buildChildGridTemplateColumns`, `isMultilineHeaderLabel`, `ColumnWidthProfile`, `ResolvedTableColumnLayout`.
|
|
560
627
|
|
|
561
628
|
**Iconos en acciones y columnas `icon-button`:**
|
|
562
629
|
|
|
@@ -588,7 +655,8 @@ Propiedades de columna `icon-button`: `icon`, `iconAlternate`, `iconActiveKey`,
|
|
|
588
655
|
|
|
589
656
|
- `optionSelected: EventEmitter<{ action: string; row: TableRow }>` – Emite la acción seleccionada y la fila principal.
|
|
590
657
|
- `subOptionSelected: EventEmitter<{ action: string; row: TableRow }>` – Emite la acción seleccionada y la sub-fila.
|
|
591
|
-
- `iconAction: EventEmitter<{ action: string; row: TableRow }>` – Emite al hacer clic en un `icon-button
|
|
658
|
+
- `iconAction: EventEmitter<{ action: string; row: TableRow }>` – Emite al hacer clic en un `icon-button` (columnas o column groups).
|
|
659
|
+
- `columnGroupChange: EventEmitter<{ key: string; row: TableRow; value: any }>` – Emite al cambiar un valor en `columnGroups` (p. ej. checkbox).
|
|
592
660
|
|
|
593
661
|
**Sub-filas con acciones (`subActions` + `showSubActions`):**
|
|
594
662
|
|
|
@@ -954,7 +1022,7 @@ Carrusel horizontal de tarjetas de dispositivo con estado (batería, geocerca, c
|
|
|
954
1022
|
### 23. `lib-title-filters` (TitleFilters)
|
|
955
1023
|
|
|
956
1024
|
**Qué hace**
|
|
957
|
-
Encabezado de sección con título, botones de acción configurables y grupo de filtros (texto, número, select, fecha, hora).
|
|
1025
|
+
Encabezado de sección con título, botones de acción configurables y grupo de filtros (texto, número, select, fecha, datetime, hora).
|
|
958
1026
|
|
|
959
1027
|
**Selector:** `lib-title-filters`
|
|
960
1028
|
|
|
@@ -963,16 +1031,18 @@ Encabezado de sección con título, botones de acción configurables y grupo de
|
|
|
963
1031
|
| Valor | Descripción |
|
|
964
1032
|
|---|---|
|
|
965
1033
|
| `'toggle'` | Botón "Filtros" que muestra/oculta el panel de filtros (default) |
|
|
966
|
-
| `'action'` | Botón "Ir al Mapa"
|
|
967
|
-
| `'click'` | Botón primario
|
|
1034
|
+
| `'action'` | Botón "Ir al Mapa" con ícono SVG fijo; emite `filterButtonClicked` |
|
|
1035
|
+
| `'click'` | Botón primario (`lib-button`) con ícono y texto configurables; emite `filterButtonClicked` |
|
|
1036
|
+
| `'clickRight'` | Igual que `click`, pero el botón primario se renderiza al final de la fila (junto a secundario/exportar) |
|
|
1037
|
+
| `'none'` | No muestra botón de acción/filtros en la barra del título |
|
|
968
1038
|
|
|
969
1039
|
**Inputs:**
|
|
970
1040
|
|
|
971
1041
|
- `title: string = 'Listado'`
|
|
972
1042
|
- `filtersConfig: TitleFilterConfig[]`
|
|
973
|
-
- `buttonMode: 'toggle' | 'action' | 'click' = 'toggle'`
|
|
974
|
-
- `clickButtonLabel: string = 'Acción'` — texto del botón en modo `click`
|
|
975
|
-
- `clickButtonIcon: string = ''` — clase CSS del ícono en modo `click`
|
|
1043
|
+
- `buttonMode: 'toggle' | 'action' | 'click' | 'clickRight' | 'none' = 'toggle'`
|
|
1044
|
+
- `clickButtonLabel: string = 'Acción'` — texto del botón en modo `click` / `clickRight`
|
|
1045
|
+
- `clickButtonIcon: string = ''` — clase CSS del ícono en modo `click` / `clickRight`
|
|
976
1046
|
- `alwaysShowFilters: boolean = false` — muestra los filtros permanentemente sin necesidad de toggle
|
|
977
1047
|
- `showSecondaryButton: boolean = false` — muestra un botón secundario (ej. "Exportar PDF")
|
|
978
1048
|
- `secondaryButtonLabel: string = 'Exportar PDF'`
|
|
@@ -981,7 +1051,7 @@ Encabezado de sección con título, botones de acción configurables y grupo de
|
|
|
981
1051
|
- `exportButtonLabel: string = 'Exportar CSV'`
|
|
982
1052
|
- `exportButtonIcon: string = 'icon-export'`
|
|
983
1053
|
- `showButtonBack: boolean = false`
|
|
984
|
-
- `initialFilters: Record<string, string | number | Date | null> = {}` — estado previo de filtros para restaurar al volver a la pantalla. La estructura es la misma que emite `filtersChange`. Soporta todos los tipos de filtro: texto, número, select (por value) y
|
|
1054
|
+
- `initialFilters: Record<string, string | number | Date | null> = {}` — estado previo de filtros para restaurar al volver a la pantalla. La estructura es la misma que emite `filtersChange`. Soporta todos los tipos de filtro: texto, número, select (por value), fecha, datetime y hora.
|
|
985
1055
|
|
|
986
1056
|
> Los botones secundario y de exportación se agrupan automáticamente al final de la fila del título.
|
|
987
1057
|
|
|
@@ -1016,7 +1086,7 @@ onFiltersChange(filters: Record<string, string | number | Date | null>) {
|
|
|
1016
1086
|
- `filtersChange: Record<string, string | number | Date | null>`
|
|
1017
1087
|
- `applyFilters: void`
|
|
1018
1088
|
- `clearFilters: void`
|
|
1019
|
-
- `filterButtonClicked: void` — emitido al hacer clic en el botón `click` o `action`
|
|
1089
|
+
- `filterButtonClicked: void` — emitido al hacer clic en el botón `click`, `clickRight` o `action`
|
|
1020
1090
|
- `secondaryButtonClicked: void`
|
|
1021
1091
|
- `exportButtonClicked: void`
|
|
1022
1092
|
- `clickButtonBack: void`
|
|
@@ -1053,11 +1123,37 @@ onFiltersChange(filters: Record<string, string | number | Date | null>) {
|
|
|
1053
1123
|
|
|
1054
1124
|
```ts
|
|
1055
1125
|
export interface TitleFilterConfig {
|
|
1056
|
-
type: 'text' | 'number' | 'select' | 'date' | 'datetime' | 'time'
|
|
1126
|
+
type: FilterType; // 'text' | 'number' | 'select' | 'date' | 'datetime' | 'time'
|
|
1057
1127
|
filters: FilterItem[];
|
|
1058
1128
|
}
|
|
1059
1129
|
```
|
|
1060
1130
|
|
|
1131
|
+
Cada entrada de `filtersConfig` renderiza un componente de filtro según su `type`:
|
|
1132
|
+
|
|
1133
|
+
| `type` | Componente interno |
|
|
1134
|
+
|---|---|
|
|
1135
|
+
| `text` | `lib-input-text-filter` |
|
|
1136
|
+
| `number` | `lib-input-number-filter` |
|
|
1137
|
+
| `select` | `lib-input-select-filter` |
|
|
1138
|
+
| `date` / `datetime` | `lib-date-time-filter` |
|
|
1139
|
+
| `time` | `lib-input-time-filter` |
|
|
1140
|
+
|
|
1141
|
+
**Navegación con Enter:** al presionar Enter en un filtro, el foco avanza al siguiente campo visible; en el último filtro se dispara `applyFilters`.
|
|
1142
|
+
|
|
1143
|
+
**Ejemplo — modo `clickRight` con botón de acción alineado a la derecha:**
|
|
1144
|
+
|
|
1145
|
+
```html
|
|
1146
|
+
<lib-title-filters
|
|
1147
|
+
title="Reportes"
|
|
1148
|
+
buttonMode="clickRight"
|
|
1149
|
+
clickButtonLabel="Nuevo reporte"
|
|
1150
|
+
clickButtonIcon="icon-add"
|
|
1151
|
+
[showSecondaryButton]="true"
|
|
1152
|
+
(filterButtonClicked)="onNuevoReporte()"
|
|
1153
|
+
(secondaryButtonClicked)="onExportPDF()"
|
|
1154
|
+
/>
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1061
1157
|
---
|
|
1062
1158
|
|
|
1063
1159
|
### 24. `lib-notification-modal` (NotificationModal)
|
|
@@ -2341,3 +2437,293 @@ readonly brandColors = ['#596300', '#006D2F', '#CF0707', ...];
|
|
|
2341
2437
|
```
|
|
2342
2438
|
|
|
2343
2439
|
---
|
|
2440
|
+
|
|
2441
|
+
### 49. `lib-sidebar` (Sidebar) y `SidebarService`
|
|
2442
|
+
|
|
2443
|
+
**Qué hace**
|
|
2444
|
+
Barra lateral reutilizable de tres niveles (módulo → submódulo → aplicativo). Recibe ítems por `@Input`, delega navegación y acciones al contenedor, y es compatible con `ModuleData` de `lib-module-card-list`.
|
|
2445
|
+
|
|
2446
|
+
**Selector:** `lib-sidebar`
|
|
2447
|
+
|
|
2448
|
+
> **Documentación detallada:** [`src/lib/components/sidebar/README.md`](./src/lib/components/sidebar/README.md)
|
|
2449
|
+
|
|
2450
|
+
**Inputs principales:**
|
|
2451
|
+
|
|
2452
|
+
| Input | Default | Descripción |
|
|
2453
|
+
|---|---|---|
|
|
2454
|
+
| `menuItems` | `[]` | Menú principal |
|
|
2455
|
+
| `userMenuItems` | `[]` | Ítems inferiores (configuración, logout, etc.) |
|
|
2456
|
+
| `expanded` | `false` | Two-way: estado expandido/colapsado |
|
|
2457
|
+
| `autoNavigate` | `false` | Navega con `Router` internamente |
|
|
2458
|
+
| `closeOnNavigate` | `true` | Colapsa al navegar |
|
|
2459
|
+
| `closeOnOutsideClick` | `true` | Colapsa al clic fuera |
|
|
2460
|
+
| `closeOnEscape` | `true` | Colapsa con Escape |
|
|
2461
|
+
| `hoverExpand` | `true` | Expansión temporal al mantener hover |
|
|
2462
|
+
| `hoverExpandDelay` | `1000` | Retardo en ms antes de expandir por hover |
|
|
2463
|
+
| `topOffset` | `'75px'` | Distancia desde el borde superior |
|
|
2464
|
+
| `expandedWidth` | `'280px'` | Ancho expandido |
|
|
2465
|
+
| `collapsedWidth` | `'70px'` | Ancho colapsado |
|
|
2466
|
+
| `dangerAction` | `'logout'` | `action` del menú inferior pintado en rojo |
|
|
2467
|
+
| `iconColor` | `'#454733'` | Color de iconos |
|
|
2468
|
+
|
|
2469
|
+
**Outputs:**
|
|
2470
|
+
|
|
2471
|
+
| Output | Descripción |
|
|
2472
|
+
|---|---|
|
|
2473
|
+
| `navigate` | Clic en ítem con `route` |
|
|
2474
|
+
| `userAction` | Clic en ítem del menú inferior con `action` |
|
|
2475
|
+
| `itemClick` | Cualquier clic (auditoría / analytics) |
|
|
2476
|
+
|
|
2477
|
+
**Utilidades exportadas:**
|
|
2478
|
+
|
|
2479
|
+
```ts
|
|
2480
|
+
import {
|
|
2481
|
+
mapModuleDataToSidebarItems,
|
|
2482
|
+
markActiveSidebarItems,
|
|
2483
|
+
filterVisibleSidebarItems,
|
|
2484
|
+
getInitialOpenState,
|
|
2485
|
+
submoduleOpenKey,
|
|
2486
|
+
SidebarMenuItem,
|
|
2487
|
+
SidebarRouteResolver,
|
|
2488
|
+
} from 'sapenlinea-components';
|
|
2489
|
+
```
|
|
2490
|
+
|
|
2491
|
+
**`SidebarService`** — estado compartido opcional (solo expandido/colapsado):
|
|
2492
|
+
|
|
2493
|
+
```ts
|
|
2494
|
+
readonly sidebar = inject(SidebarService);
|
|
2495
|
+
sidebar.toggleSidebar();
|
|
2496
|
+
sidebar.sidebarExpanded();
|
|
2497
|
+
```
|
|
2498
|
+
|
|
2499
|
+
**Ejemplo mínimo:**
|
|
2500
|
+
|
|
2501
|
+
```html
|
|
2502
|
+
<lib-sidebar
|
|
2503
|
+
[menuItems]="menuItems()"
|
|
2504
|
+
[userMenuItems]="userMenuItems"
|
|
2505
|
+
[(expanded)]="sidebarExpanded"
|
|
2506
|
+
[topOffset]="'75px'"
|
|
2507
|
+
(navigate)="onNavigate($event)"
|
|
2508
|
+
(userAction)="onUserAction($event)"
|
|
2509
|
+
/>
|
|
2510
|
+
```
|
|
2511
|
+
|
|
2512
|
+
---
|
|
2513
|
+
|
|
2514
|
+
### 50. `lib-header` (Header)
|
|
2515
|
+
|
|
2516
|
+
**Qué hace**
|
|
2517
|
+
Encabezado de aplicación con menú hamburguesa, título activo, acción contextual configurable por microfrontend, campana de notificaciones y menú de usuario. Todas las entradas son opcionales para uso como custom element, module federation o dentro del monolito.
|
|
2518
|
+
|
|
2519
|
+
**Selector:** `lib-header`
|
|
2520
|
+
|
|
2521
|
+
**Interfaz:**
|
|
2522
|
+
|
|
2523
|
+
```ts
|
|
2524
|
+
export interface HeaderAction {
|
|
2525
|
+
/** Texto del botón, p. ej. "Nuevo Usuario". */
|
|
2526
|
+
label: string;
|
|
2527
|
+
/** Ruta interna; si se define, el header emite `navigateTo`. */
|
|
2528
|
+
route?: string;
|
|
2529
|
+
/** Nombre del CustomEvent a despachar en `window` (para abrir modales en MFs remotos). */
|
|
2530
|
+
customEvent?: string;
|
|
2531
|
+
}
|
|
2532
|
+
```
|
|
2533
|
+
|
|
2534
|
+
**Inputs:**
|
|
2535
|
+
|
|
2536
|
+
| Input | Default | Descripción |
|
|
2537
|
+
|---|---|---|
|
|
2538
|
+
| `isExpanded` | `false` | Estado del sidebar (cambia ícono ☰ / ✕) |
|
|
2539
|
+
| `activeTitle` | `''` | Título de la pantalla activa |
|
|
2540
|
+
| `action` | `null` | Acción contextual del botón `+` (recomendado). Ver `HeaderAction` |
|
|
2541
|
+
| `mfId` | `''` | Identificador del MF. **Deprecated** como driver de la acción; usar `[action]` |
|
|
2542
|
+
| `isMfFailed` | `false` | Oculta la acción si el MF falló al cargar |
|
|
2543
|
+
| `userRole` | `'Administrador'` | Rol mostrado en el menú de usuario |
|
|
2544
|
+
| `notifications` | `[]` | Lista de notificaciones (`LibNotification[]`) |
|
|
2545
|
+
| `notificationsLoading` | `false` | Indica carga de página de notificaciones |
|
|
2546
|
+
| `notificationsHasMore` | `false` | Indica si hay más notificaciones por cargar |
|
|
2547
|
+
| `unreadCount` | `null` | Total real de no leídas (prevalece sobre conteo derivado) |
|
|
2548
|
+
|
|
2549
|
+
**Outputs:**
|
|
2550
|
+
|
|
2551
|
+
| Output | Descripción |
|
|
2552
|
+
|---|---|
|
|
2553
|
+
| `navigateTo` | Navegación a ruta (p. ej. `/home`, `/child/infractions/register`) |
|
|
2554
|
+
| `menuClick` | Clic en botón hamburguesa |
|
|
2555
|
+
| `profileClick` | Clic en perfil de usuario |
|
|
2556
|
+
| `logoutClick` | Clic en cerrar sesión |
|
|
2557
|
+
| `actionClick` | Clic en acción contextual (emite `mfId`) |
|
|
2558
|
+
| `markAllRead` | Marcar todas las notificaciones como leídas |
|
|
2559
|
+
| `notificationClick` | Clic en una notificación |
|
|
2560
|
+
| `loadMoreNotifications` | Solicitud de siguiente página de notificaciones |
|
|
2561
|
+
|
|
2562
|
+
**Acción contextual (`[action]`)**
|
|
2563
|
+
|
|
2564
|
+
El botón `+` se configura desde el **shell host** sin modificar la librería. Al hacer clic:
|
|
2565
|
+
|
|
2566
|
+
1. Si `action.route` está definido → emite `navigateTo` con esa ruta.
|
|
2567
|
+
2. Si `action.customEvent` está definido → despacha `window.dispatchEvent(new CustomEvent(...))` para que el MF remoto abra un modal.
|
|
2568
|
+
3. Siempre emite `actionClick` con el valor de `mfId`.
|
|
2569
|
+
|
|
2570
|
+
**Prioridad:** `[action]` prevalece sobre el mapa legacy interno por `mfId`. El mapa legacy se mantiene solo por compatibilidad con integraciones existentes.
|
|
2571
|
+
|
|
2572
|
+
**Ejemplo — navegación por ruta:**
|
|
2573
|
+
|
|
2574
|
+
```html
|
|
2575
|
+
<lib-header
|
|
2576
|
+
[activeTitle]="pageTitle()"
|
|
2577
|
+
[mfId]="currentMfId()"
|
|
2578
|
+
[action]="{ label: 'Nueva Infracción', route: '/child/infractions/register' }"
|
|
2579
|
+
(navigateTo)="router.navigateByUrl($event)"
|
|
2580
|
+
/>
|
|
2581
|
+
```
|
|
2582
|
+
|
|
2583
|
+
**Ejemplo — abrir modal en MF remoto (CustomEvent):**
|
|
2584
|
+
|
|
2585
|
+
Configuración en el shell:
|
|
2586
|
+
|
|
2587
|
+
```html
|
|
2588
|
+
<lib-header
|
|
2589
|
+
[activeTitle]="'Usuarios'"
|
|
2590
|
+
[mfId]="'users'"
|
|
2591
|
+
[action]="{ label: 'Nuevo Usuario', customEvent: 'mf-action-user-nuevo' }"
|
|
2592
|
+
/>
|
|
2593
|
+
```
|
|
2594
|
+
|
|
2595
|
+
Escucha en el MF hijo:
|
|
2596
|
+
|
|
2597
|
+
```ts
|
|
2598
|
+
@HostListener('window:mf-action-user-nuevo')
|
|
2599
|
+
onNuevoDesdeShell(): void {
|
|
2600
|
+
this.abrirModalNuevoUsuario();
|
|
2601
|
+
}
|
|
2602
|
+
```
|
|
2603
|
+
|
|
2604
|
+
**Ejemplo — config centralizada en el shell:**
|
|
2605
|
+
|
|
2606
|
+
```ts
|
|
2607
|
+
import { HeaderAction } from 'sapenlinea-components';
|
|
2608
|
+
|
|
2609
|
+
const HEADER_ACTIONS: Record<string, HeaderAction> = {
|
|
2610
|
+
users: { label: 'Nuevo Usuario', customEvent: 'mf-action-user-nuevo' },
|
|
2611
|
+
infractions: { label: 'Nueva Infracción', route: '/child/infractions/register' },
|
|
2612
|
+
paymentAgreementParameters: { label: 'Nuevo Parámetro', customEvent: 'mf-action-register-parameter' },
|
|
2613
|
+
};
|
|
2614
|
+
|
|
2615
|
+
headerAction = computed(() => HEADER_ACTIONS[this.currentMfId()] ?? null);
|
|
2616
|
+
```
|
|
2617
|
+
|
|
2618
|
+
```html
|
|
2619
|
+
<lib-header
|
|
2620
|
+
[isExpanded]="sidebarExpanded()"
|
|
2621
|
+
[activeTitle]="pageTitle()"
|
|
2622
|
+
[mfId]="currentMfId()"
|
|
2623
|
+
[action]="headerAction()"
|
|
2624
|
+
[notifications]="notifications()"
|
|
2625
|
+
[unreadCount]="unreadTotal()"
|
|
2626
|
+
[notificationsHasMore]="hasMore()"
|
|
2627
|
+
(menuClick)="toggleSidebar()"
|
|
2628
|
+
(navigateTo)="router.navigateByUrl($event)"
|
|
2629
|
+
(logoutClick)="onLogout()"
|
|
2630
|
+
(notificationClick)="onNotification($event)"
|
|
2631
|
+
(loadMoreNotifications)="loadNextPage()"
|
|
2632
|
+
/>
|
|
2633
|
+
```
|
|
2634
|
+
|
|
2635
|
+
**Compatibilidad legacy (`mfId` sin `[action]`)**
|
|
2636
|
+
|
|
2637
|
+
Si no se pasa `[action]`, el header resuelve la acción desde mapas internos según `mfId`:
|
|
2638
|
+
|
|
2639
|
+
| `mfId` | Comportamiento |
|
|
2640
|
+
|---|---|
|
|
2641
|
+
| `infractions` | Navega a `/child/infractions/register` |
|
|
2642
|
+
| `paymentAgreements` | Navega a `/child/paymentAgreements/register` |
|
|
2643
|
+
| `trainingCourses-programar` | Navega a `/child/trainingCourses/programacion` |
|
|
2644
|
+
| `paymentAgreementParameters` | Despacha `mf-action-register-parameter` |
|
|
2645
|
+
| `trainingCourses-administrar` | Despacha `mf-action-training-course-nuevo` |
|
|
2646
|
+
| `trainingCourses-catalogos-cia` | Despacha `mf-action-catalogo-cia-nuevo` |
|
|
2647
|
+
| `trainingCourses-catalogos-salones` | Despacha `mf-action-catalogo-salon-nuevo` |
|
|
2648
|
+
| `trainingCourses-catalogos-instructores` | Despacha `mf-action-catalogo-instructor-nuevo` |
|
|
2649
|
+
|
|
2650
|
+
Para nuevos MFs, usar siempre `[action]` desde el shell.
|
|
2651
|
+
|
|
2652
|
+
---
|
|
2653
|
+
|
|
2654
|
+
### 51. `lib-notification-center` (NotificationCenter)
|
|
2655
|
+
|
|
2656
|
+
**Qué hace**
|
|
2657
|
+
Panel desplegable de notificaciones con filtro por categoría, scroll infinito y acción "Marcar todas como leídas". Se usa internamente en `lib-header` pero también puede consumirse de forma independiente.
|
|
2658
|
+
|
|
2659
|
+
**Selector:** `lib-notification-center`
|
|
2660
|
+
|
|
2661
|
+
**Interfaz:**
|
|
2662
|
+
|
|
2663
|
+
```ts
|
|
2664
|
+
export interface LibNotification {
|
|
2665
|
+
id: string;
|
|
2666
|
+
title: string;
|
|
2667
|
+
description: string;
|
|
2668
|
+
category: string;
|
|
2669
|
+
timeAgo: string;
|
|
2670
|
+
isRead: boolean;
|
|
2671
|
+
}
|
|
2672
|
+
```
|
|
2673
|
+
|
|
2674
|
+
**Inputs:**
|
|
2675
|
+
|
|
2676
|
+
| Input | Default | Descripción |
|
|
2677
|
+
|---|---|---|
|
|
2678
|
+
| `notifications` | `[]` | Lista de notificaciones |
|
|
2679
|
+
| `isOpen` | `false` | Controla visibilidad del panel |
|
|
2680
|
+
| `loading` | `false` | Indica carga de página en curso |
|
|
2681
|
+
| `hasMore` | `false` | Indica si quedan más registros por cargar |
|
|
2682
|
+
|
|
2683
|
+
**Outputs:**
|
|
2684
|
+
|
|
2685
|
+
| Output | Descripción |
|
|
2686
|
+
|---|---|
|
|
2687
|
+
| `markAllRead` | Usuario solicita marcar todas como leídas |
|
|
2688
|
+
| `notificationClick` | Clic en una notificación |
|
|
2689
|
+
| `close` | Cierre del panel |
|
|
2690
|
+
| `loadMore` | El sentinel al final de la lista entró en viewport (scroll infinito) |
|
|
2691
|
+
|
|
2692
|
+
**Comportamiento:**
|
|
2693
|
+
|
|
2694
|
+
- Pestañas de categoría generadas automáticamente desde `category` de cada notificación, más "Todas".
|
|
2695
|
+
- Colores e iconos por categoría inferidos por palabras clave (`ACUERDO`, `FINAN`, `INFRAC`, `SISTEMA`).
|
|
2696
|
+
- `IntersectionObserver` en un sentinel al final de la lista dispara `loadMore` cuando `hasMore` es `true` y no hay carga en curso.
|
|
2697
|
+
|
|
2698
|
+
---
|
|
2699
|
+
|
|
2700
|
+
### 52. `lib-bell-with-badge` (BellWithBadge)
|
|
2701
|
+
|
|
2702
|
+
**Qué hace**
|
|
2703
|
+
Icono de campana con badge numérico de notificaciones no leídas. Componente atómico usado por `lib-header`.
|
|
2704
|
+
|
|
2705
|
+
**Selector:** `lib-bell-with-badge`
|
|
2706
|
+
|
|
2707
|
+
**Inputs:**
|
|
2708
|
+
|
|
2709
|
+
| Input | Default | Descripción |
|
|
2710
|
+
|---|---|---|
|
|
2711
|
+
| `count` | `0` | Número a mostrar en el badge (oculto si es 0) |
|
|
2712
|
+
| `active` | `false` | Estado visual activo (panel abierto) |
|
|
2713
|
+
| `ariaLabel` | `'Notificaciones'` | Etiqueta de accesibilidad |
|
|
2714
|
+
|
|
2715
|
+
**Outputs:**
|
|
2716
|
+
|
|
2717
|
+
- `bellClick: void` — emitido al hacer clic en la campana.
|
|
2718
|
+
|
|
2719
|
+
**Ejemplo:**
|
|
2720
|
+
|
|
2721
|
+
```html
|
|
2722
|
+
<lib-bell-with-badge
|
|
2723
|
+
[count]="unreadCount()"
|
|
2724
|
+
[active]="panelOpen()"
|
|
2725
|
+
(bellClick)="togglePanel()"
|
|
2726
|
+
/>
|
|
2727
|
+
```
|
|
2728
|
+
|
|
2729
|
+
---
|