import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; part 'evenement_model.g.dart'; /// Modèle de données pour un événement UnionFlow /// Aligné avec l'entité Evenement du serveur API @JsonSerializable() class EvenementModel extends Equatable { /// ID unique de l'événement final String? id; /// Titre de l'événement final String titre; /// Description détaillée final String? description; /// Date et heure de début @JsonKey(name: 'dateDebut') final DateTime dateDebut; /// Date et heure de fin @JsonKey(name: 'dateFin') final DateTime? dateFin; /// Lieu de l'événement final String? lieu; /// Adresse complète final String? adresse; /// Type d'événement @JsonKey(name: 'typeEvenement') final TypeEvenement typeEvenement; /// Statut de l'événement final StatutEvenement statut; /// Capacité maximale @JsonKey(name: 'capaciteMax') final int? capaciteMax; /// Prix de participation final double? prix; /// Inscription requise @JsonKey(name: 'inscriptionRequise') final bool inscriptionRequise; /// Date limite d'inscription @JsonKey(name: 'dateLimiteInscription') final DateTime? dateLimiteInscription; /// Instructions particulières @JsonKey(name: 'instructionsParticulieres') final String? instructionsParticulieres; /// Contact organisateur @JsonKey(name: 'contactOrganisateur') final String? contactOrganisateur; /// Matériel requis @JsonKey(name: 'materielRequis') final String? materielRequis; /// Visible au public @JsonKey(name: 'visiblePublic') final bool visiblePublic; /// Événement actif final bool actif; /// Créé par @JsonKey(name: 'creePar') final String? creePar; /// Date de création @JsonKey(name: 'dateCreation') final DateTime? dateCreation; /// Modifié par @JsonKey(name: 'modifiePar') final String? modifiePar; /// Date de modification @JsonKey(name: 'dateModification') final DateTime? dateModification; /// Organisation associée (ID) @JsonKey(name: 'organisationId') final String? organisationId; /// Organisateur (ID) @JsonKey(name: 'organisateurId') final String? organisateurId; const EvenementModel({ this.id, required this.titre, this.description, required this.dateDebut, this.dateFin, this.lieu, this.adresse, required this.typeEvenement, required this.statut, this.capaciteMax, this.prix, required this.inscriptionRequise, this.dateLimiteInscription, this.instructionsParticulieres, this.contactOrganisateur, this.materielRequis, required this.visiblePublic, required this.actif, this.creePar, this.dateCreation, this.modifiePar, this.dateModification, this.organisationId, this.organisateurId, }); /// Factory pour créer depuis JSON factory EvenementModel.fromJson(Map json) => _$EvenementModelFromJson(json); /// Convertir vers JSON Map toJson() => _$EvenementModelToJson(this); /// Copie avec modifications EvenementModel copyWith({ String? id, String? titre, String? description, DateTime? dateDebut, DateTime? dateFin, String? lieu, String? adresse, TypeEvenement? typeEvenement, StatutEvenement? statut, int? capaciteMax, double? prix, bool? inscriptionRequise, DateTime? dateLimiteInscription, String? instructionsParticulieres, String? contactOrganisateur, String? materielRequis, bool? visiblePublic, bool? actif, String? creePar, DateTime? dateCreation, String? modifiePar, DateTime? dateModification, String? organisationId, String? organisateurId, }) { return EvenementModel( id: id ?? this.id, titre: titre ?? this.titre, description: description ?? this.description, dateDebut: dateDebut ?? this.dateDebut, dateFin: dateFin ?? this.dateFin, lieu: lieu ?? this.lieu, adresse: adresse ?? this.adresse, typeEvenement: typeEvenement ?? this.typeEvenement, statut: statut ?? this.statut, capaciteMax: capaciteMax ?? this.capaciteMax, prix: prix ?? this.prix, inscriptionRequise: inscriptionRequise ?? this.inscriptionRequise, dateLimiteInscription: dateLimiteInscription ?? this.dateLimiteInscription, instructionsParticulieres: instructionsParticulieres ?? this.instructionsParticulieres, contactOrganisateur: contactOrganisateur ?? this.contactOrganisateur, materielRequis: materielRequis ?? this.materielRequis, visiblePublic: visiblePublic ?? this.visiblePublic, actif: actif ?? this.actif, creePar: creePar ?? this.creePar, dateCreation: dateCreation ?? this.dateCreation, modifiePar: modifiePar ?? this.modifiePar, dateModification: dateModification ?? this.dateModification, organisationId: organisationId ?? this.organisationId, organisateurId: organisateurId ?? this.organisateurId, ); } /// Méthodes utilitaires /// Vérifie si l'événement est à venir bool get estAVenir => dateDebut.isAfter(DateTime.now()); /// Vérifie si l'événement est en cours bool get estEnCours { final maintenant = DateTime.now(); return dateDebut.isBefore(maintenant) && (dateFin?.isAfter(maintenant) ?? false); } /// Vérifie si l'événement est terminé bool get estTermine { final maintenant = DateTime.now(); return dateFin?.isBefore(maintenant) ?? dateDebut.isBefore(maintenant); } /// Vérifie si les inscriptions sont ouvertes bool get inscriptionsOuvertes { if (!inscriptionRequise) return false; if (dateLimiteInscription == null) return estAVenir; return dateLimiteInscription!.isAfter(DateTime.now()) && estAVenir; } /// Durée de l'événement Duration? get duree { if (dateFin == null) return null; return dateFin!.difference(dateDebut); } /// Formatage de la durée String get dureeFormatee { final d = duree; if (d == null) return 'Non spécifiée'; if (d.inDays > 0) { return '${d.inDays} jour${d.inDays > 1 ? 's' : ''}'; } else if (d.inHours > 0) { return '${d.inHours}h${d.inMinutes.remainder(60) > 0 ? '${d.inMinutes.remainder(60)}' : ''}'; } else { return '${d.inMinutes} min'; } } @override List get props => [ id, titre, description, dateDebut, dateFin, lieu, adresse, typeEvenement, statut, capaciteMax, prix, inscriptionRequise, dateLimiteInscription, instructionsParticulieres, contactOrganisateur, materielRequis, visiblePublic, actif, creePar, dateCreation, modifiePar, dateModification, organisationId, organisateurId, ]; } /// Types d'événements disponibles @JsonEnum() enum TypeEvenement { @JsonValue('ASSEMBLEE_GENERALE') assembleeGenerale, @JsonValue('REUNION') reunion, @JsonValue('FORMATION') formation, @JsonValue('CONFERENCE') conference, @JsonValue('ATELIER') atelier, @JsonValue('SEMINAIRE') seminaire, @JsonValue('EVENEMENT_SOCIAL') evenementSocial, @JsonValue('MANIFESTATION') manifestation, @JsonValue('CELEBRATION') celebration, @JsonValue('AUTRE') autre, } /// Extension pour les libellés des types extension TypeEvenementExtension on TypeEvenement { String get libelle { switch (this) { case TypeEvenement.assembleeGenerale: return 'Assemblée Générale'; case TypeEvenement.reunion: return 'Réunion'; case TypeEvenement.formation: return 'Formation'; case TypeEvenement.conference: return 'Conférence'; case TypeEvenement.atelier: return 'Atelier'; case TypeEvenement.seminaire: return 'Séminaire'; case TypeEvenement.evenementSocial: return 'Événement Social'; case TypeEvenement.manifestation: return 'Manifestation'; case TypeEvenement.celebration: return 'Célébration'; case TypeEvenement.autre: return 'Autre'; } } String get icone { switch (this) { case TypeEvenement.assembleeGenerale: return '🏛️'; case TypeEvenement.reunion: return '👥'; case TypeEvenement.formation: return '📚'; case TypeEvenement.conference: return '🎤'; case TypeEvenement.atelier: return '🔧'; case TypeEvenement.seminaire: return '🎓'; case TypeEvenement.evenementSocial: return '🎉'; case TypeEvenement.manifestation: return '📢'; case TypeEvenement.celebration: return '🎊'; case TypeEvenement.autre: return '📅'; } } } /// Statuts d'événements disponibles @JsonEnum() enum StatutEvenement { @JsonValue('PLANIFIE') planifie, @JsonValue('CONFIRME') confirme, @JsonValue('EN_COURS') enCours, @JsonValue('TERMINE') termine, @JsonValue('ANNULE') annule, @JsonValue('REPORTE') reporte, } /// Extension pour les libellés des statuts extension StatutEvenementExtension on StatutEvenement { String get libelle { switch (this) { case StatutEvenement.planifie: return 'Planifié'; case StatutEvenement.confirme: return 'Confirmé'; case StatutEvenement.enCours: return 'En cours'; case StatutEvenement.termine: return 'Terminé'; case StatutEvenement.annule: return 'Annulé'; case StatutEvenement.reporte: return 'Reporté'; } } String get couleur { switch (this) { case StatutEvenement.planifie: return '#FFA500'; // Orange case StatutEvenement.confirme: return '#4CAF50'; // Vert case StatutEvenement.enCours: return '#2196F3'; // Bleu case StatutEvenement.termine: return '#9E9E9E'; // Gris case StatutEvenement.annule: return '#F44336'; // Rouge case StatutEvenement.reporte: return '#FF9800'; // Orange foncé } } }