415 lines
14 KiB
Dart
415 lines
14 KiB
Dart
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<String, String>? parametres;
|
|
final bool fermeNotification;
|
|
final bool necessiteConfirmation;
|
|
final bool estDestructive;
|
|
final int ordre;
|
|
final bool estActivee;
|
|
|
|
factory ActionNotification.fromJson(Map<String, dynamic> json) =>
|
|
_$ActionNotificationFromJson(json);
|
|
|
|
Map<String, dynamic> toJson() => _$ActionNotificationToJson(this);
|
|
|
|
@override
|
|
List<Object?> 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<String, String>? 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<String> destinatairesIds;
|
|
final String? organisationId;
|
|
final Map<String, dynamic>? donneesPersonnalisees;
|
|
final String? imageUrl;
|
|
final String? iconeUrl;
|
|
final String? actionClic;
|
|
final Map<String, String>? parametresAction;
|
|
final List<ActionNotification>? 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<String>? tags;
|
|
final String? campagneId;
|
|
final String? plateforme;
|
|
final String? tokenFCM;
|
|
|
|
factory NotificationEntity.fromJson(Map<String, dynamic> json) =>
|
|
_$NotificationEntityFromJson(json);
|
|
|
|
Map<String, dynamic> toJson() => _$NotificationEntityToJson(this);
|
|
|
|
@override
|
|
List<Object?> 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<String>? destinatairesIds,
|
|
String? organisationId,
|
|
Map<String, dynamic>? donneesPersonnalisees,
|
|
String? imageUrl,
|
|
String? iconeUrl,
|
|
String? actionClic,
|
|
Map<String, String>? parametresAction,
|
|
List<ActionNotification>? actionsRapides,
|
|
DateTime? dateCreation,
|
|
DateTime? dateEnvoiProgramme,
|
|
DateTime? dateEnvoi,
|
|
DateTime? dateExpiration,
|
|
DateTime? dateDerniereLecture,
|
|
int? priorite,
|
|
bool? estLue,
|
|
bool? estImportante,
|
|
bool? estArchivee,
|
|
int? nombreAffichages,
|
|
int? nombreClics,
|
|
List<String>? 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<ActionNotification> 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;
|
|
}
|
|
}
|