import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; part 'notification.g.dart'; /// Énumération des types de notification enum TypeNotification { // Événements @JsonValue('NOUVEL_EVENEMENT') nouvelEvenement('Nouvel événement', 'evenements', 'info', 'event', '#FF9800'), @JsonValue('RAPPEL_EVENEMENT') rappelEvenement('Rappel d\'événement', 'evenements', 'reminder', 'schedule', '#2196F3'), @JsonValue('EVENEMENT_ANNULE') evenementAnnule('Événement annulé', 'evenements', 'warning', 'event_busy', '#F44336'), @JsonValue('INSCRIPTION_CONFIRMEE') inscriptionConfirmee('Inscription confirmée', 'evenements', 'success', 'check_circle', '#4CAF50'), // Cotisations @JsonValue('COTISATION_DUE') cotisationDue('Cotisation due', 'cotisations', 'reminder', 'payment', '#FF5722'), @JsonValue('COTISATION_PAYEE') cotisationPayee('Cotisation payée', 'cotisations', 'success', 'paid', '#4CAF50'), @JsonValue('PAIEMENT_CONFIRME') paiementConfirme('Paiement confirmé', 'cotisations', 'success', 'check_circle', '#4CAF50'), @JsonValue('PAIEMENT_ECHOUE') paiementEchoue('Paiement échoué', 'cotisations', 'error', 'error', '#F44336'), // Solidarité @JsonValue('NOUVELLE_DEMANDE_AIDE') nouvelleDemandeAide('Nouvelle demande d\'aide', 'solidarite', 'info', 'help', '#E91E63'), @JsonValue('DEMANDE_AIDE_APPROUVEE') demandeAideApprouvee('Demande d\'aide approuvée', 'solidarite', 'success', 'thumb_up', '#4CAF50'), @JsonValue('AIDE_DISPONIBLE') aideDisponible('Aide disponible', 'solidarite', 'info', 'volunteer_activism', '#E91E63'), // Membres @JsonValue('NOUVEAU_MEMBRE') nouveauMembre('Nouveau membre', 'membres', 'info', 'person_add', '#2196F3'), @JsonValue('ANNIVERSAIRE_MEMBRE') anniversaireMembre('Anniversaire de membre', 'membres', 'celebration', 'cake', '#FF9800'), // Organisation @JsonValue('ANNONCE_GENERALE') annonceGenerale('Annonce générale', 'organisation', 'info', 'campaign', '#2196F3'), @JsonValue('REUNION_PROGRAMMEE') reunionProgrammee('Réunion programmée', 'organisation', 'info', 'groups', '#2196F3'), // Messages @JsonValue('MESSAGE_PRIVE') messagePrive('Message privé', 'messages', 'info', 'mail', '#2196F3'), @JsonValue('MENTION') mention('Mention', 'messages', 'info', 'alternate_email', '#FF9800'), // Système @JsonValue('MISE_A_JOUR_APP') miseAJourApp('Mise à jour disponible', 'systeme', 'info', 'system_update', '#2196F3'), @JsonValue('MAINTENANCE_PROGRAMMEE') maintenanceProgrammee('Maintenance programmée', 'systeme', 'warning', 'build', '#FF9800'); const TypeNotification(this.libelle, this.categorie, this.priorite, this.icone, this.couleur); final String libelle; final String categorie; final String priorite; final String icone; final String couleur; bool get isCritique => priorite == 'urgent' || priorite == 'error'; bool get isRappel => priorite == 'reminder'; bool get isPositive => priorite == 'success' || priorite == 'celebration'; int get niveauPriorite { switch (priorite) { case 'urgent': return 1; case 'error': return 2; case 'warning': return 3; case 'important': return 4; case 'reminder': return 5; case 'info': return 6; case 'success': return 7; case 'celebration': return 8; default: return 6; } } } /// Énumération des statuts de notification enum StatutNotification { @JsonValue('BROUILLON') brouillon('Brouillon', 'draft', '#9E9E9E'), @JsonValue('PROGRAMMEE') programmee('Programmée', 'scheduled', '#FF9800'), @JsonValue('ENVOYEE') envoyee('Envoyée', 'sent', '#4CAF50'), @JsonValue('RECUE') recue('Reçue', 'received', '#4CAF50'), @JsonValue('AFFICHEE') affichee('Affichée', 'displayed', '#2196F3'), @JsonValue('OUVERTE') ouverte('Ouverte', 'opened', '#4CAF50'), @JsonValue('LUE') lue('Lue', 'read', '#4CAF50'), @JsonValue('NON_LUE') nonLue('Non lue', 'unread', '#FF9800'), @JsonValue('MARQUEE_IMPORTANTE') marqueeImportante('Marquée importante', 'starred', '#FF9800'), @JsonValue('SUPPRIMEE') supprimee('Supprimée', 'deleted', '#F44336'), @JsonValue('ARCHIVEE') archivee('Archivée', 'archived', '#9E9E9E'), @JsonValue('ECHEC_ENVOI') echecEnvoi('Échec d\'envoi', 'failed', '#F44336'); const StatutNotification(this.libelle, this.code, this.couleur); final String libelle; final String code; final String couleur; bool get isSucces => this == envoyee || this == recue || this == affichee || this == ouverte || this == lue; bool get isErreur => this == echecEnvoi; bool get isFinal => this == supprimee || this == archivee || isErreur; } /// Action rapide de notification @JsonSerializable() class ActionNotification extends Equatable { const ActionNotification({ required this.id, required this.libelle, required this.typeAction, this.description, this.icone, this.couleur, this.url, this.route, this.parametres, this.fermeNotification = true, this.necessiteConfirmation = false, this.estDestructive = false, this.ordre = 0, this.estActivee = true, }); final String id; final String libelle; final String? description; final String typeAction; final String? icone; final String? couleur; final String? url; final String? route; final Map? parametres; final bool fermeNotification; final bool necessiteConfirmation; final bool estDestructive; final int ordre; final bool estActivee; factory ActionNotification.fromJson(Map json) => _$ActionNotificationFromJson(json); Map toJson() => _$ActionNotificationToJson(this); @override List get props => [ id, libelle, description, typeAction, icone, couleur, url, route, parametres, fermeNotification, necessiteConfirmation, estDestructive, ordre, estActivee, ]; ActionNotification copyWith({ String? id, String? libelle, String? description, String? typeAction, String? icone, String? couleur, String? url, String? route, Map? parametres, bool? fermeNotification, bool? necessiteConfirmation, bool? estDestructive, int? ordre, bool? estActivee, }) { return ActionNotification( id: id ?? this.id, libelle: libelle ?? this.libelle, description: description ?? this.description, typeAction: typeAction ?? this.typeAction, icone: icone ?? this.icone, couleur: couleur ?? this.couleur, url: url ?? this.url, route: route ?? this.route, parametres: parametres ?? this.parametres, fermeNotification: fermeNotification ?? this.fermeNotification, necessiteConfirmation: necessiteConfirmation ?? this.necessiteConfirmation, estDestructive: estDestructive ?? this.estDestructive, ordre: ordre ?? this.ordre, estActivee: estActivee ?? this.estActivee, ); } } /// Entité principale de notification @JsonSerializable() class NotificationEntity extends Equatable { const NotificationEntity({ required this.id, required this.typeNotification, required this.statut, required this.titre, required this.message, this.messageCourt, this.expediteurId, this.expediteurNom, required this.destinatairesIds, this.organisationId, this.donneesPersonnalisees, this.imageUrl, this.iconeUrl, this.actionClic, this.parametresAction, this.actionsRapides, required this.dateCreation, this.dateEnvoiProgramme, this.dateEnvoi, this.dateExpiration, this.dateDerniereLecture, this.priorite = 3, this.estLue = false, this.estImportante = false, this.estArchivee = false, this.nombreAffichages = 0, this.nombreClics = 0, this.tags, this.campagneId, this.plateforme, this.tokenFCM, }); final String id; final TypeNotification typeNotification; final StatutNotification statut; final String titre; final String message; final String? messageCourt; final String? expediteurId; final String? expediteurNom; final List destinatairesIds; final String? organisationId; final Map? donneesPersonnalisees; final String? imageUrl; final String? iconeUrl; final String? actionClic; final Map? parametresAction; final List? actionsRapides; final DateTime dateCreation; final DateTime? dateEnvoiProgramme; final DateTime? dateEnvoi; final DateTime? dateExpiration; final DateTime? dateDerniereLecture; final int priorite; final bool estLue; final bool estImportante; final bool estArchivee; final int nombreAffichages; final int nombreClics; final List? tags; final String? campagneId; final String? plateforme; final String? tokenFCM; factory NotificationEntity.fromJson(Map json) => _$NotificationEntityFromJson(json); Map toJson() => _$NotificationEntityToJson(this); @override List get props => [ id, typeNotification, statut, titre, message, messageCourt, expediteurId, expediteurNom, destinatairesIds, organisationId, donneesPersonnalisees, imageUrl, iconeUrl, actionClic, parametresAction, actionsRapides, dateCreation, dateEnvoiProgramme, dateEnvoi, dateExpiration, dateDerniereLecture, priorite, estLue, estImportante, estArchivee, nombreAffichages, nombreClics, tags, campagneId, plateforme, tokenFCM, ]; NotificationEntity copyWith({ String? id, TypeNotification? typeNotification, StatutNotification? statut, String? titre, String? message, String? messageCourt, String? expediteurId, String? expediteurNom, List? destinatairesIds, String? organisationId, Map? donneesPersonnalisees, String? imageUrl, String? iconeUrl, String? actionClic, Map? parametresAction, List? actionsRapides, DateTime? dateCreation, DateTime? dateEnvoiProgramme, DateTime? dateEnvoi, DateTime? dateExpiration, DateTime? dateDerniereLecture, int? priorite, bool? estLue, bool? estImportante, bool? estArchivee, int? nombreAffichages, int? nombreClics, List? tags, String? campagneId, String? plateforme, String? tokenFCM, }) { return NotificationEntity( id: id ?? this.id, typeNotification: typeNotification ?? this.typeNotification, statut: statut ?? this.statut, titre: titre ?? this.titre, message: message ?? this.message, messageCourt: messageCourt ?? this.messageCourt, expediteurId: expediteurId ?? this.expediteurId, expediteurNom: expediteurNom ?? this.expediteurNom, destinatairesIds: destinatairesIds ?? this.destinatairesIds, organisationId: organisationId ?? this.organisationId, donneesPersonnalisees: donneesPersonnalisees ?? this.donneesPersonnalisees, imageUrl: imageUrl ?? this.imageUrl, iconeUrl: iconeUrl ?? this.iconeUrl, actionClic: actionClic ?? this.actionClic, parametresAction: parametresAction ?? this.parametresAction, actionsRapides: actionsRapides ?? this.actionsRapides, dateCreation: dateCreation ?? this.dateCreation, dateEnvoiProgramme: dateEnvoiProgramme ?? this.dateEnvoiProgramme, dateEnvoi: dateEnvoi ?? this.dateEnvoi, dateExpiration: dateExpiration ?? this.dateExpiration, dateDerniereLecture: dateDerniereLecture ?? this.dateDerniereLecture, priorite: priorite ?? this.priorite, estLue: estLue ?? this.estLue, estImportante: estImportante ?? this.estImportante, estArchivee: estArchivee ?? this.estArchivee, nombreAffichages: nombreAffichages ?? this.nombreAffichages, nombreClics: nombreClics ?? this.nombreClics, tags: tags ?? this.tags, campagneId: campagneId ?? this.campagneId, plateforme: plateforme ?? this.plateforme, tokenFCM: tokenFCM ?? this.tokenFCM, ); } /// Vérifie si la notification est expirée bool get isExpiree { if (dateExpiration == null) return false; return DateTime.now().isAfter(dateExpiration!); } /// Vérifie si la notification est récente (moins de 24h) bool get isRecente { final maintenant = DateTime.now(); final difference = maintenant.difference(dateCreation); return difference.inHours < 24; } /// Retourne le temps écoulé depuis la création String get tempsEcoule { final maintenant = DateTime.now(); final difference = maintenant.difference(dateCreation); if (difference.inMinutes < 1) { return 'À l\'instant'; } else if (difference.inMinutes < 60) { return 'Il y a ${difference.inMinutes}min'; } else if (difference.inHours < 24) { return 'Il y a ${difference.inHours}h'; } else if (difference.inDays < 7) { return 'Il y a ${difference.inDays}j'; } else { return 'Il y a ${(difference.inDays / 7).floor()}sem'; } } /// Retourne le message à afficher (court ou complet) String get messageAffichage => messageCourt ?? message; /// Retourne la couleur du type de notification String get couleurType => typeNotification.couleur; /// Retourne l'icône du type de notification String get iconeType => typeNotification.icone; /// Vérifie si la notification a des actions rapides bool get hasActionsRapides => actionsRapides != null && actionsRapides!.isNotEmpty; /// Retourne les actions rapides actives List get actionsRapidesActives { if (actionsRapides == null) return []; return actionsRapides!.where((action) => action.estActivee).toList(); } /// Calcule le taux d'engagement double get tauxEngagement { if (nombreAffichages == 0) return 0.0; return (nombreClics / nombreAffichages) * 100; } }