# Notifications

Módulo de notificaciones: panel lateral del navbar (notification center) + página de preferencias por canal/módulo. Cubre dos dominios distintos consumiendo la misma API base:

- **Notification Center** (`/notification-center/*`) — listado del bell, mark-as-read, deep-link a destino.
- **Notification Preferences** (`/notification-preferences/*`) — toggles de canales (PUSH / BELL / MAIL) por módulo + feed email notifications config.

---

## Pantallas y flujos

| Pantalla / flujo | Descripción | Entrada | Ruta |
|---|---|---|---|
| Notifications Config | Página de preferencias: toggles de canales por módulo, configuración de email del feed | `NotificationsConfig/index.tsx` | `/notifications-config` |
| Side panel (bell) | Panel lateral montado desde el navbar; lista paginada de notificaciones con mark-as-read, deep-link y settings | `sidepanel/NotificationsSidePanelAdapter.tsx` | No route — mounted from `DashboardNavbar` via `lazyRetry` |

---

## Componentes y hooks clave

| Nombre | Descripción | Ubicación |
|---|---|---|
| `NotificationsSidePanelAdapter` | Entry lazy del side panel; punto de montaje desde el navbar | `sidepanel/NotificationsSidePanelAdapter.tsx` |
| `NotificationSidePanel` | Panel propiamente dicho (header + content + states) | `sidepanel/components/NotificationSidePanel.tsx` |
| `useNotificationSidePanelController` | Controla queries paginadas, mark-as-read y refetches del bell | `sidepanel/useNotificationSidePanelController.tsx` |
| `usePanelMountState` | Maneja mount/unmount delayed del side panel para animaciones de salida | `sidepanel/usePanelMountState.ts` |
| `useNotificationLogoutCleanup` | Borra el FCM token antes del logout (registra `beforeLogoutCallback`) | `hooks/useNotificationLogoutCleanup.ts` |
| `useNotificationsBellOpenState` | Estado de apertura del bell con callback `onBeforeToggle` | `hooks.ts` |
| `useNotificationsConfigPageQueries` / `useThrottle` | Queries de la página de settings + helper de throttle | `hooks.ts` |
| `NotificationChannels` / `NotificationModuleCard` | UI cards de la página de settings | `components/` |

---

## Archivos compartidos del módulo

| Archivo | Contenido |
|---|---|
| `routes.ts` | URL builders del módulo (`notificationsRoutes.config()`) |
| `services.ts` | Llamados a la API: notification center, preferences, FCM token management |
| `queries.ts` | Dos sets de keys disjuntos: `notificationsKeys` (preferences) + `notificationCenterKeys` (bell). Apuntan a APIs distintas — no fusionar |
| `constants.ts` | Module codes (`NotificationModuleCodes`), channels (`NotificationChannelCodes`), icons (`moduleIcons`), config del side panel (`NOTIFICATION_PANEL_WIDTH`, `SKELETON_KEYS`, …) |
| `types.ts` | Tipos de dominio (`NotificationItem`, `ChannelPreferences`, `NotificationsStatsData`, …) |
| `utils.ts` | Utilidades del dominio settings + cross-cutting de tab title/badge (`formatNotificationCountForTitle`, `updateTitleAndBadgeFromCount`, `hasUnreadNotifications`) |
| `sidepanel/utils.ts` | Utilidades específicas del notification center: overlay rendering, deep link translation, Amplitude incidence mapping |
| `hooks/` | Hooks de scope módulo (actualmente solo `useNotificationLogoutCleanup`). El resto convive en `hooks.ts` por compatibilidad histórica |

---

## Estructura de directorios

```
notifications/
├── NotificationsConfig/
│   └── index.tsx                       # Página de preferencias (/notifications-config)
├── sidepanel/                          # Notification center (bell)
│   ├── NotificationsSidePanelAdapter.tsx
│   ├── useNotificationSidePanelController.tsx
│   ├── usePanelMountState.ts
│   ├── utils.ts                        # Sidepanel-specific helpers
│   └── components/                     # Items, states, header, content
├── components/                         # Componentes de la página de settings
│   ├── NotificationChannels.tsx
│   ├── NotificationModuleCard.tsx
│   └── NotificationsConfigLoading.tsx
├── hooks/
│   └── useNotificationLogoutCleanup.ts
├── hooks.ts                            # Hooks compartidos (queries de settings + bell open state)
├── routes.ts
├── services.ts
├── queries.ts
├── constants.ts
├── types.ts
└── utils.ts
```

---

## Wiring externo

- `src/routes.tsx` monta `NotificationsConfig` en `/notifications-config` con `Loadable + lazyRetry` (legacy pattern, sin `routeConfig`).
- `src/components/dashboard/navbar/DashboardNavbar.tsx` monta `NotificationsSidePanelAdapter` con `lazyRetry`; usa `notificationCenterKeys.stats()` para el badge y `updateTitleAndBadgeFromCount` para tab title.
- `src/components/dashboard/GlobalHelmetTitlePrefix.tsx` lee `notificationCenterKeys.stats()` y `formatNotificationCountForTitle` para el prefijo de title.
- `src/contexts/NotificationsContext.tsx` (provider global): mantiene el FCM token en estado de App y consume `useNotificationLogoutCleanup`. Se queda en `src/contexts/` porque es un provider montado a nivel App, no scoped a la página.
- `src/contexts/NewPostNotificationContext.tsx`: separate concern (feed-scoped); también global.

---

## Known issues / deuda técnica

- `hooks.ts` (legacy) convive con la carpeta `hooks/`. La skill `/migrate-module` sugiere split a `hooks/*.ts` individuales — se difiere hasta que haya un cambio sustantivo en los hooks existentes para evitar churn sin valor.
- `src/utils/sidebar.ts` y `src/utils/navbar.ts` matchean `/notifications-config/` con regex; podrían tomar `notificationsRoutes.config()` pero el patrón es cross-module y se mantiene como regex por consistencia.

---

> Actualizar este README cuando se agreguen pantallas, se reorganicen carpetas o cambie el dominio del side panel vs settings.
