import { AppError } from '../errors/app-error'; import { countAnomaliesParStatut, countEmpruntsParStatut, countMaterielsParStatut, countNotificationsNonLues, findActiviteRecente, findAnomaliesResponsable, findEmpruntsResponsable, findHistoriqueResponsable, findMaterielsResponsable, findNotificationsResponsable, marquerNotificationLue, marquerNotificationsResponsableLues, StatutCount, ActiviteResponsable, AnomalieResponsable, EmpruntResponsable, HistoriqueResponsable, MaterielResponsable, NotificationResponsable, } from '../repositories/responsable.repository'; import { STATUT_ANOMALIE, STATUT_EMPRUNT, STATUT_MATERIEL, StatutAnomalie, StatutEmprunt, StatutMateriel, } from '../models/enums'; export interface DashboardResponsableData { materiels: StatutCount[]; emprunts: StatutCount[]; anomalies: StatutCount[]; notificationsNonLues: number; activiteRecente: ActiviteResponsable[]; } export interface ListerEmpruntsResponsableFiltres { statut?: StatutEmprunt; } export interface ListerMaterielsResponsableFiltres { statut?: StatutMateriel; categorieId?: number; recherche?: string; } export interface ListerAnomaliesResponsableFiltres { statut?: StatutAnomalie; type?: string; } export interface ListerNotificationsResponsableFiltres { lu?: boolean; } export interface ListerHistoriqueResponsableFiltres { action?: string; utilisateurId?: number; materielId?: number; empruntId?: number; dateDebut?: Date; dateFin?: Date; } function verifierResponsable(roleCode: string): void { if (roleCode !== 'RESPONSABLE') { throw new AppError(403, 'Acces reserve au responsable materiel'); } } export async function getDashboardResponsable( utilisateurId: number, roleCode: string, campusId: number, ): Promise { verifierResponsable(roleCode); const [materiels, emprunts, anomalies, notificationsNonLues, activiteRecente] = await Promise.all( [ countMaterielsParStatut(campusId), countEmpruntsParStatut(campusId), countAnomaliesParStatut(campusId), countNotificationsNonLues(utilisateurId), findActiviteRecente(campusId, 10), ], ); return { materiels, emprunts, anomalies, notificationsNonLues, activiteRecente, }; } export function parseStatutEmprunt(value: unknown): StatutEmprunt | undefined { if (value === undefined) { return undefined; } if (typeof value !== 'string' || !(STATUT_EMPRUNT as readonly string[]).includes(value)) { throw new AppError(400, 'statut invalide'); } return value as StatutEmprunt; } export function parseStatutMateriel(value: unknown): StatutMateriel | undefined { if (value === undefined) { return undefined; } if (typeof value !== 'string' || !(STATUT_MATERIEL as readonly string[]).includes(value)) { throw new AppError(400, 'statut invalide'); } return value as StatutMateriel; } export function parseStatutAnomalie(value: unknown): StatutAnomalie | undefined { if (value === undefined) { return undefined; } if (typeof value !== 'string' || !(STATUT_ANOMALIE as readonly string[]).includes(value)) { throw new AppError(400, 'statut invalide'); } return value as StatutAnomalie; } export function parseCategorieId(value: unknown): number | undefined { if (value === undefined) { return undefined; } const parsed = Number(value); if (!Number.isInteger(parsed) || parsed <= 0) { throw new AppError(400, 'categorieId invalide'); } return parsed; } export function parseNotificationId(value: unknown): number { if (typeof value !== 'string') { throw new AppError(400, 'notificationId invalide'); } const parsed = Number(value); if (!Number.isInteger(parsed) || parsed <= 0) { throw new AppError(400, 'notificationId invalide'); } return parsed; } export function parsePositiveIntQuery(value: unknown, champ: string): number | undefined { if (value === undefined) { return undefined; } if (typeof value !== 'string') { throw new AppError(400, `${champ} invalide`); } const parsed = Number(value); if (!Number.isInteger(parsed) || parsed <= 0) { throw new AppError(400, `${champ} invalide`); } return parsed; } export function parseDateQuery(value: unknown, champ: string): Date | undefined { if (value === undefined) { return undefined; } if (typeof value !== 'string') { throw new AppError(400, `${champ} invalide`); } const parsed = new Date(value); if (Number.isNaN(parsed.getTime())) { throw new AppError(400, `${champ} invalide`); } return parsed; } export function parseLu(value: unknown): boolean | undefined { if (value === undefined) { return undefined; } if (value === 'true') { return true; } if (value === 'false') { return false; } throw new AppError(400, 'lu invalide'); } export function listerEmpruntsResponsable( roleCode: string, campusId: number, filtres: ListerEmpruntsResponsableFiltres, ): Promise { verifierResponsable(roleCode); return findEmpruntsResponsable(campusId, filtres); } export function listerMaterielsResponsable( roleCode: string, campusId: number, filtres: ListerMaterielsResponsableFiltres, ): Promise { verifierResponsable(roleCode); return findMaterielsResponsable(campusId, filtres); } export function listerAnomaliesResponsable( roleCode: string, campusId: number, filtres: ListerAnomaliesResponsableFiltres, ): Promise { verifierResponsable(roleCode); return findAnomaliesResponsable(campusId, filtres); } export function listerNotificationsResponsable( utilisateurId: number, roleCode: string, filtres: ListerNotificationsResponsableFiltres, ): Promise { verifierResponsable(roleCode); return findNotificationsResponsable(utilisateurId, filtres); } export async function marquerNotificationResponsableLue( utilisateurId: number, roleCode: string, notificationId: number, ): Promise { verifierResponsable(roleCode); try { return await marquerNotificationLue(utilisateurId, notificationId); } catch { throw new AppError(404, 'Notification introuvable'); } } export function marquerToutesNotificationsResponsableLues( utilisateurId: number, roleCode: string, ): Promise { verifierResponsable(roleCode); return marquerNotificationsResponsableLues(utilisateurId); } export function listerHistoriqueResponsable( roleCode: string, campusId: number, filtres: ListerHistoriqueResponsableFiltres, ): Promise { verifierResponsable(roleCode); return findHistoriqueResponsable(campusId, filtres); }