Reglas de componentes — Frontend
Componentes reutilizables del proyecto
Componentes compartidos entre varias pantallas o flujos. Ubicación y uso:
| Componente | Ruta | Uso |
|---|---|---|
| pin-modal | app/components/pin-modal/ |
Modal de código PIN (teclado numérico). Usado en Dashboard (elegir empleado, ajustes, informes), Time-control (iniciar/finalizar jornada), Staff (verificar PIN para editar/configurar). |
| address-modal | app/dashboard/address-modal/ |
Modal de dirección (mapa/geocoding). Usado en Dashboard (editar lugar) y Create-place (nuevo establecimiento). |
| settings-modal | app/dashboard/settings-modal/ |
Modal de Ajustes del lugar (licencia, idioma, bloqueo, etc.). Solo desde Dashboard. |
| create-place | app/dashboard/create-place/ |
Formulario/modal para crear un nuevo establecimiento. Solo desde Dashboard (selector de lugar). |
| edit-shift-modal | app/reports/edit-shift-modal/ |
Modal para editar una jornada (fecha/hora, motivo) en Informes. Solo desde Reports. |
Al añadir un componente que vaya a usarse en más de un feature, valorar ponerlo en app/components/ (como pin-modal) y documentarlo aquí.
Componentes nuevos
- Ubicación: páginas bajo
app/<feature>/; componentes reutilizables bajoapp/components/(ej.pin-modal). Un componente por carpeta con*.component.ts|html|scss. - Naming: selector con prefijo
app-, clase PascalCase +Component. Ej:app-pin-modal→PinModalComponent. - Estilos: usar solo variables de
theme/variables.scssy--ion-*; sin hex/rgb en el SCSS del componente (ver styles.md). - Data-testid: en elementos interactivos o clave para tests, usar
data-testid="gk-<componente>-<elemento>"(ver testing.md).
Observables y memoria
- En páginas y componentes que suscriban a
Observableo a servicios que exponen streams: usartakeUntil(this.destroy$)y enngOnDestroy()llamarthis.destroy$.next(); this.destroy$.complete();. No dejar suscripciones sin cancelar.
❌ Prohibido
ngOnInit() {
this.api.getPlaces().subscribe({ next: (p) => this.places = p });
}
// Sin ngOnDestroy → fuga si el componente se destruye
private destroy$ = new Subject<void>();
ngOnInit() {
this.api.getPlaces().pipe(takeUntil(this.destroy$)).subscribe({ next: (p) => this.places = p });
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
- Si el componente no tiene
ngOnDestroy, no debe tener suscripciones de larga duración (o debe usarasyncpipe en template).
Servicios nuevos
providedIn: 'root'salvo que el ámbito sea claramente un módulo/feature.- Exponer datos por
Observablecuando varios consumidores deban reaccionar; por método cuando sea una acción única (ej.login,uploadPhoto). - Documentar en el servicio si devuelve observables que el llamador debe cancelar (y en ese caso usar
takeUntilen el componente).
Checklist rápido
- Selector y clase con convención (app-, Component).
- Estilos con variables Ionic; sin colores hardcodeados.
- Suscripciones con
takeUntil(destroy$)yngOnDestroy. - Data-testid en botones/inputs críticos si el flujo se va a testear.