xpeditis2.0/apps/backend/src/domain/services/notification-target.ts
2026-09-07 21:40:55 +02:00

60 lines
2.3 KiB
TypeScript

import { NotificationType } from '../entities/notification.entity';
/**
* Ou mene une notification.
*
* Une notification n'est pas un message : c'est un pointeur vers quelque chose
* qui a change. Le lien est donc derive du type et des metadonnees, ici et nulle
* part ailleurs — l'interface se contente de suivre.
*
* Les liens etaient jusqu'ici ecrits a la main a chaque appel, et deux d'entre
* eux visaient des routes qui n'existent pas : `/bookings/{id}` (la vraie route
* est `/dashboard/bookings/{id}`) et `/dashboard/admin/organizations` (l'espace
* d'administration a depuis son propre segment `/admin`). Les regrouper permet
* de les eprouver contre les routes reelles, en une seule fois.
*
* Les liens sont **relatifs et sans prefixe de langue** : le frontend est
* localise (`/fr`, `/en`) et ajoute le sien.
*/
export function notificationTarget(
type: NotificationType,
metadata: Record<string, unknown> | undefined
): string | null {
const bookingId = asId(metadata?.bookingId);
switch (type) {
// Toutes les notifications de reservation menent au dossier concerne.
case NotificationType.BOOKING_CREATED:
case NotificationType.BOOKING_UPDATED:
case NotificationType.BOOKING_CONFIRMED:
case NotificationType.BOOKING_CANCELLED:
case NotificationType.CSV_BOOKING_ACCEPTED:
case NotificationType.CSV_BOOKING_REJECTED:
case NotificationType.CSV_BOOKING_REQUEST_SENT:
case NotificationType.DOCUMENT_UPLOADED:
return bookingId ? `/dashboard/bookings/${bookingId}` : '/dashboard/bookings';
case NotificationType.RATE_QUOTE_EXPIRING:
return '/dashboard/search-advanced';
case NotificationType.USER_INVITED:
return '/dashboard/settings/users';
case NotificationType.ORGANIZATION_UPDATE:
return '/dashboard/settings/organization';
// Une annonce ne pointe vers rien : la ligne ne doit pas se presenter comme
// cliquable pour n'aboutir nulle part.
case NotificationType.SYSTEM_ANNOUNCEMENT:
return null;
}
}
/** Un identifiant utilisable dans une URL, ou rien. */
function asId(value: unknown): string | null {
if (typeof value !== 'string') return null;
const trimmed = value.trim();
// Les metadonnees sont du JSON libre : refuser ce qui sortirait du segment.
return trimmed && /^[A-Za-z0-9_-]{1,64}$/.test(trimmed) ? trimmed : null;
}