modularisation utilitaire agenda events
This commit is contained in:
parent
0401b8a1aa
commit
26e35e6c68
441
assets/js/modules/agenda-event-mapper.js
Normal file
441
assets/js/modules/agenda-event-mapper.js
Normal file
@ -0,0 +1,441 @@
|
|||||||
|
// Module de mapping des événements pour FullCalendar
|
||||||
|
// Contient toute la logique de transformation des données API vers le format FullCalendar
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calcule la luminosité d'une couleur hexadécimale
|
||||||
|
* @param {string} hexColor - Couleur au format #RRGGBB
|
||||||
|
* @returns {number} - Luminosité entre 0 et 1
|
||||||
|
*/
|
||||||
|
function getLuminance(hexColor) {
|
||||||
|
// Vérifier que hexColor n'est pas null ou undefined
|
||||||
|
if (!hexColor || typeof hexColor !== 'string') {
|
||||||
|
console.warn('⚠️ [getLuminance] Valeur hexColor invalide:', hexColor);
|
||||||
|
return 0.5; // Retourner une valeur moyenne par défaut
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convertir hex en RGB
|
||||||
|
const hex = hexColor.replace('#', '');
|
||||||
|
const r = parseInt(hex.substr(0, 2), 16);
|
||||||
|
const g = parseInt(hex.substr(2, 2), 16);
|
||||||
|
const b = parseInt(hex.substr(4, 2), 16);
|
||||||
|
|
||||||
|
// Calculer la luminosité relative selon WCAG
|
||||||
|
return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Détermine la couleur de texte optimale selon le contraste
|
||||||
|
* @param {string} backgroundColor - Couleur de fond au format #RRGGBB
|
||||||
|
* @returns {string} - Couleur de texte (#000000 ou #ffffff)
|
||||||
|
*/
|
||||||
|
function getTextColor(backgroundColor) {
|
||||||
|
// Vérifier que backgroundColor n'est pas null ou undefined
|
||||||
|
if (!backgroundColor || typeof backgroundColor !== 'string') {
|
||||||
|
console.warn('⚠️ [getTextColor] Valeur backgroundColor invalide:', backgroundColor);
|
||||||
|
return '#000000'; // Retourner noir par défaut
|
||||||
|
}
|
||||||
|
|
||||||
|
const luminance = getLuminance(backgroundColor);
|
||||||
|
return luminance > 0.5 ? '#000000' : '#ffffff';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mappe un événement API vers le format FullCalendar
|
||||||
|
* @param {Object} ev - Événement depuis l'API
|
||||||
|
* @returns {Object} - Événement au format FullCalendar
|
||||||
|
*/
|
||||||
|
export function mapEventToFullCalendar(ev) {
|
||||||
|
// Hiérarchie de détermination des couleurs :
|
||||||
|
// 1) Pour RDV assignés (individuel/groupe) avec type d'intervention : couleur du type d'intervention
|
||||||
|
// 2) Pour RDV assignés (individuel/groupe) sans type d'intervention : orange (par défaut)
|
||||||
|
// 3) Pour permanences : couleur selon le type (assignée, non attribuée, non disponible)
|
||||||
|
|
||||||
|
let backgroundColor = null;
|
||||||
|
let textColor = null;
|
||||||
|
|
||||||
|
// Vérifier si l'événement est assigné (a un intervenant et un local/beneficiaire)
|
||||||
|
const isEventAssigned = ev.id_intervenant && (ev.id_local || ev.id_beneficiaire);
|
||||||
|
|
||||||
|
// Pour les RDV (individuel/groupe) assignés
|
||||||
|
if (ev.type && ev.type !== 'permanence' && isEventAssigned) {
|
||||||
|
// Vérifier si l'événement a un type d'intervention défini
|
||||||
|
let typeInterventionId = null;
|
||||||
|
if (ev.id_type_intervention) {
|
||||||
|
typeInterventionId = parseInt(ev.id_type_intervention);
|
||||||
|
} else if (ev.type_intervention && ev.type_intervention.id) {
|
||||||
|
typeInterventionId = parseInt(ev.type_intervention.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si l'événement a un type d'intervention, utiliser sa couleur depuis crviAjax
|
||||||
|
if (typeInterventionId && !isNaN(typeInterventionId) && window.crviAjax && window.crviAjax.couleurs_types_intervention) {
|
||||||
|
const couleurTypeIntervention = window.crviAjax.couleurs_types_intervention[typeInterventionId];
|
||||||
|
if (couleurTypeIntervention) {
|
||||||
|
backgroundColor = couleurTypeIntervention;
|
||||||
|
textColor = getTextColor(couleurTypeIntervention);
|
||||||
|
console.log('🎨 [COULEUR] RDV assigné avec type d\'intervention:', {
|
||||||
|
eventId: ev.id,
|
||||||
|
type: ev.type,
|
||||||
|
typeInterventionId: typeInterventionId,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
textColor: textColor,
|
||||||
|
source: 'type_intervention'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si pas de couleur définie (pas de type d'intervention), garder orange par défaut
|
||||||
|
if (!backgroundColor) {
|
||||||
|
backgroundColor = '#ff9800'; // Orange pour les événements assignés sans type d'intervention
|
||||||
|
textColor = getTextColor(backgroundColor);
|
||||||
|
console.log('🎨 [COULEUR] RDV assigné sans type d\'intervention (défaut orange):', {
|
||||||
|
eventId: ev.id,
|
||||||
|
type: ev.type,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
textColor: textColor,
|
||||||
|
source: 'defaut_assigné'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pour les RDV non assignés : couleur selon type_de_local (bureau ou salle)
|
||||||
|
if (!backgroundColor && ev.type && ev.type !== 'permanence' && !isEventAssigned) {
|
||||||
|
// Vérifier si l'événement a un local avec un type_de_local
|
||||||
|
if (ev.local && ev.local.type_de_local) {
|
||||||
|
const typeLocal = ev.local.type_de_local.toLowerCase();
|
||||||
|
if (window.crviACFData && window.crviACFData.couleurs_rdv) {
|
||||||
|
const couleurRdv = window.crviACFData.couleurs_rdv[typeLocal];
|
||||||
|
if (couleurRdv) {
|
||||||
|
backgroundColor = couleurRdv;
|
||||||
|
textColor = getTextColor(couleurRdv);
|
||||||
|
console.log('🎨 [COULEUR] RDV non assigné selon type de local:', {
|
||||||
|
eventId: ev.id,
|
||||||
|
type: ev.type,
|
||||||
|
typeLocal: typeLocal,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
textColor: textColor,
|
||||||
|
source: 'type_local'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pour permanences (événements de type 'permanence') : logique simplifiée
|
||||||
|
// 1) Non attribuée : dispo ? couleur dispo : couleur indispo
|
||||||
|
// 2) Attribuée : a type intervention ? couleur type : couleur défaut
|
||||||
|
let isPermanenceDisabled = false;
|
||||||
|
if (!backgroundColor && ev.type === 'permanence') {
|
||||||
|
// Une permanence est assignée si elle a un bénéficiaire ET un local (assign = 1)
|
||||||
|
const isPermanenceAssigned = ev.assign === 1 || (ev.id_beneficiaire && ev.id_local);
|
||||||
|
|
||||||
|
// Une permanence est non attribuée si elle n'est pas assignée (assign = 0)
|
||||||
|
const isPermanenceNonAttribuee = ev.assign === 0 && !ev.id_beneficiaire && !ev.id_local;
|
||||||
|
|
||||||
|
// Vérifier si le bénéficiaire est en congé (indisponibilitee_ponctuelle)
|
||||||
|
let isPermanenceNonDisponible = false;
|
||||||
|
if (ev.beneficiaire && ev.beneficiaire.indisponibilitee_ponctuelle && Array.isArray(ev.beneficiaire.indisponibilitee_ponctuelle)) {
|
||||||
|
const eventDate = ev.date_rdv; // Format YYYY-MM-DD
|
||||||
|
const eventDateObj = new Date(eventDate + 'T00:00:00');
|
||||||
|
|
||||||
|
// Vérifier si la date de l'événement est dans une période d'indisponibilité
|
||||||
|
for (const indispo of ev.beneficiaire.indisponibilitee_ponctuelle) {
|
||||||
|
if (indispo.debut && indispo.fin) {
|
||||||
|
let debutDate, finDate;
|
||||||
|
|
||||||
|
// Gérer le format d/m/Y (format ACF)
|
||||||
|
if (typeof indispo.debut === 'string' && indispo.debut.includes('/')) {
|
||||||
|
const debutParts = indispo.debut.split('/');
|
||||||
|
const finParts = indispo.fin.split('/');
|
||||||
|
|
||||||
|
if (debutParts.length === 3 && finParts.length === 3) {
|
||||||
|
// Format d/m/Y
|
||||||
|
debutDate = new Date(parseInt(debutParts[2]), parseInt(debutParts[1]) - 1, parseInt(debutParts[0]));
|
||||||
|
finDate = new Date(parseInt(finParts[2]), parseInt(finParts[1]) - 1, parseInt(finParts[0]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Format YYYY-MM-DD ou timestamp
|
||||||
|
debutDate = new Date(indispo.debut);
|
||||||
|
finDate = new Date(indispo.fin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debutDate && finDate && !isNaN(debutDate.getTime()) && !isNaN(finDate.getTime())) {
|
||||||
|
// Ajuster pour inclure toute la journée
|
||||||
|
debutDate.setHours(0, 0, 0, 0);
|
||||||
|
finDate.setHours(23, 59, 59, 999);
|
||||||
|
|
||||||
|
if (eventDateObj >= debutDate && eventDateObj <= finDate) {
|
||||||
|
isPermanenceNonDisponible = true;
|
||||||
|
isPermanenceDisabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier si l'intervenant est indisponible (congés ou jour non disponible)
|
||||||
|
if (!isPermanenceNonDisponible && ev.id_intervenant && window.crviACFData && window.crviACFData.indisponibilites_intervenants) {
|
||||||
|
const intervenantId = parseInt(ev.id_intervenant);
|
||||||
|
const intervenantDispo = window.crviACFData.indisponibilites_intervenants[intervenantId];
|
||||||
|
|
||||||
|
if (intervenantDispo) {
|
||||||
|
const eventDate = ev.date_rdv; // Format YYYY-MM-DD
|
||||||
|
const eventDateObj = new Date(eventDate + 'T00:00:00');
|
||||||
|
|
||||||
|
// Vérifier les jours de disponibilité (0 = dimanche, 1 = lundi, etc.)
|
||||||
|
const dayOfWeek = eventDateObj.getDay();
|
||||||
|
const dayNames = ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'];
|
||||||
|
const dayName = dayNames[dayOfWeek];
|
||||||
|
|
||||||
|
// Si l'intervenant a des jours de disponibilité définis et que ce jour n'en fait pas partie
|
||||||
|
if (intervenantDispo.jours_dispo && Array.isArray(intervenantDispo.jours_dispo) &&
|
||||||
|
intervenantDispo.jours_dispo.length > 0 &&
|
||||||
|
!intervenantDispo.jours_dispo.includes(dayName)) {
|
||||||
|
console.log('🚫 [PERMANENCE] Intervenant non disponible ce jour:', {
|
||||||
|
intervenantId,
|
||||||
|
date: eventDate,
|
||||||
|
dayName,
|
||||||
|
joursDisponibles: intervenantDispo.jours_dispo
|
||||||
|
});
|
||||||
|
isPermanenceNonDisponible = true;
|
||||||
|
isPermanenceDisabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier les congés/indisponibilités ponctuelles
|
||||||
|
if (!isPermanenceNonDisponible && intervenantDispo.conges && Array.isArray(intervenantDispo.conges)) {
|
||||||
|
for (const conge of intervenantDispo.conges) {
|
||||||
|
if (conge.debut && conge.fin) {
|
||||||
|
let debutDate, finDate;
|
||||||
|
|
||||||
|
// Gérer le format d/m/Y (format ACF)
|
||||||
|
if (typeof conge.debut === 'string' && conge.debut.includes('/')) {
|
||||||
|
const debutParts = conge.debut.split('/');
|
||||||
|
const finParts = conge.fin.split('/');
|
||||||
|
|
||||||
|
if (debutParts.length === 3 && finParts.length === 3) {
|
||||||
|
debutDate = new Date(parseInt(debutParts[2]), parseInt(debutParts[1]) - 1, parseInt(debutParts[0]));
|
||||||
|
finDate = new Date(parseInt(finParts[2]), parseInt(finParts[1]) - 1, parseInt(finParts[0]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Format YYYY-MM-DD ou timestamp
|
||||||
|
debutDate = new Date(conge.debut);
|
||||||
|
finDate = new Date(conge.fin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debutDate && finDate && !isNaN(debutDate.getTime()) && !isNaN(finDate.getTime())) {
|
||||||
|
debutDate.setHours(0, 0, 0, 0);
|
||||||
|
finDate.setHours(23, 59, 59, 999);
|
||||||
|
|
||||||
|
if (eventDateObj >= debutDate && eventDateObj <= finDate) {
|
||||||
|
console.log('🚫 [PERMANENCE] Intervenant en congé:', {
|
||||||
|
intervenantId,
|
||||||
|
date: eventDate,
|
||||||
|
congeDebut: conge.debut,
|
||||||
|
congeFin: conge.fin,
|
||||||
|
congeType: conge.type
|
||||||
|
});
|
||||||
|
isPermanenceNonDisponible = true;
|
||||||
|
isPermanenceDisabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier aussi le statut si pas déjà déterminé
|
||||||
|
if (!isPermanenceNonDisponible && ev.statut && ['annule', 'non_tenu', 'absence'].includes(ev.statut)) {
|
||||||
|
isPermanenceNonDisponible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOGIQUE SIMPLIFIÉE
|
||||||
|
if (isPermanenceNonAttribuee) {
|
||||||
|
// 1) Non attribuée : dispo ? couleur dispo : couleur indispo
|
||||||
|
if (isPermanenceNonDisponible && window.crviAjax && window.crviAjax.couleur_permanence_non_disponible) {
|
||||||
|
backgroundColor = window.crviAjax.couleur_permanence_non_disponible;
|
||||||
|
console.log('🎨 [COULEUR] Permanence non attribuée - indisponible:', {
|
||||||
|
eventId: ev.id,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
source: 'permanence_non_attribuee_indispo'
|
||||||
|
});
|
||||||
|
} else if (window.crviAjax && window.crviAjax.couleur_permanence_non_attribuee) {
|
||||||
|
backgroundColor = window.crviAjax.couleur_permanence_non_attribuee;
|
||||||
|
console.log('🎨 [COULEUR] Permanence non attribuée - disponible:', {
|
||||||
|
eventId: ev.id,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
source: 'permanence_non_attribuee_dispo'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (isPermanenceAssigned) {
|
||||||
|
// 2) Attribuée : a type intervention ? couleur type : couleur défaut
|
||||||
|
let typeInterventionId = null;
|
||||||
|
if (ev.id_type_intervention) {
|
||||||
|
typeInterventionId = parseInt(ev.id_type_intervention);
|
||||||
|
} else if (ev.type_intervention && ev.type_intervention.id) {
|
||||||
|
typeInterventionId = parseInt(ev.type_intervention.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeInterventionId && !isNaN(typeInterventionId) && window.crviAjax && window.crviAjax.couleurs_types_intervention) {
|
||||||
|
const couleurTypeIntervention = window.crviAjax.couleurs_types_intervention[typeInterventionId];
|
||||||
|
if (couleurTypeIntervention) {
|
||||||
|
backgroundColor = couleurTypeIntervention;
|
||||||
|
console.log('🎨 [COULEUR] Permanence assignée - avec type intervention:', {
|
||||||
|
eventId: ev.id,
|
||||||
|
typeInterventionId: typeInterventionId,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
source: 'permanence_assignee_type'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si pas de type d'intervention, utiliser couleur défaut
|
||||||
|
if (!backgroundColor) {
|
||||||
|
backgroundColor = (window.crviACFData && window.crviACFData.couleurs_permanence && window.crviACFData.couleurs_permanence.permanence)
|
||||||
|
? window.crviACFData.couleurs_permanence.permanence
|
||||||
|
: '#9e9e9e';
|
||||||
|
console.log('🎨 [COULEUR] Permanence assignée - défaut:', {
|
||||||
|
eventId: ev.id,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
source: 'permanence_assignee_defaut'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// S'assurer que backgroundColor n'est pas null avant d'appeler getTextColor
|
||||||
|
if (backgroundColor) {
|
||||||
|
textColor = getTextColor(backgroundColor);
|
||||||
|
} else {
|
||||||
|
textColor = '#000000'; // Par défaut
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couleur par défaut si aucune condition n'est remplie
|
||||||
|
if (!backgroundColor) {
|
||||||
|
backgroundColor = '#6c757d'; // Gris par défaut
|
||||||
|
textColor = getTextColor(backgroundColor);
|
||||||
|
console.log('🎨 [COULEUR] Couleur par défaut (gris):', {
|
||||||
|
eventId: ev.id,
|
||||||
|
type: ev.type,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
textColor: textColor,
|
||||||
|
source: 'defaut_general'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log final de la couleur appliquée
|
||||||
|
console.log('🎨 [COULEUR FINALE] Événement:', {
|
||||||
|
eventId: ev.id,
|
||||||
|
title: ev.type || 'Sans type',
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
borderColor: backgroundColor,
|
||||||
|
textColor: textColor,
|
||||||
|
isAssigned: isEventAssigned,
|
||||||
|
type: ev.type
|
||||||
|
});
|
||||||
|
|
||||||
|
// Générer un titre plus explicite
|
||||||
|
let title = ev.type || 'Sans type';
|
||||||
|
|
||||||
|
// Gestion spéciale pour les permanences
|
||||||
|
if (ev.type === 'permanence') {
|
||||||
|
if (ev.intervenant) {
|
||||||
|
const intervenant = ev.intervenant;
|
||||||
|
const nomComplet = `${intervenant.prenom || ''} ${intervenant.nom || ''}`.trim();
|
||||||
|
title = 'p. ' + (nomComplet || 'Intervenant');
|
||||||
|
} else {
|
||||||
|
title = 'p. Intervenant';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Utiliser le nom de l'intervenant comme titre principal pour les autres événements
|
||||||
|
if (ev.intervenant) {
|
||||||
|
const intervenant = ev.intervenant;
|
||||||
|
const nomComplet = `${intervenant.prenom || ''} ${intervenant.nom || ''}`.trim();
|
||||||
|
if (nomComplet) {
|
||||||
|
title = nomComplet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ajouter le type d'intervention principal si disponible
|
||||||
|
if (ev.intervenant && ev.intervenant.types_intervention_noms && ev.intervenant.types_intervention_noms.length > 0) {
|
||||||
|
const primaryType = ev.intervenant.types_intervention_noms[0]; // Premier type d'intervention
|
||||||
|
title += ` - ${primaryType}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ajouter le commentaire si disponible
|
||||||
|
if (ev.commentaire) {
|
||||||
|
title += ' - ' + ev.commentaire;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// S'assurer que les couleurs sont toujours définies
|
||||||
|
if (!backgroundColor || typeof backgroundColor !== 'string') {
|
||||||
|
console.warn('⚠️ [Mapping] backgroundColor invalide pour l\'événement:', ev.id, backgroundColor);
|
||||||
|
backgroundColor = '#6c757d'; // Gris par défaut
|
||||||
|
}
|
||||||
|
if (!textColor || typeof textColor !== 'string') {
|
||||||
|
textColor = getTextColor(backgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier si l'événement est passé
|
||||||
|
const eventStartDate = new Date(ev.date_rdv + 'T' + ev.heure_rdv);
|
||||||
|
const now = new Date();
|
||||||
|
const isEventPast = eventStartDate < now;
|
||||||
|
|
||||||
|
// Un événement est éditable seulement si :
|
||||||
|
// 1. Il n'est pas désactivé (permanence)
|
||||||
|
// 2. Il n'est pas passé
|
||||||
|
const isEditable = !isPermanenceDisabled && !isEventPast;
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: ev.id,
|
||||||
|
title: title,
|
||||||
|
start: ev.date_rdv + 'T' + ev.heure_rdv,
|
||||||
|
end: ev.date_fin + 'T' + ev.heure_fin,
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
borderColor: backgroundColor,
|
||||||
|
textColor: textColor,
|
||||||
|
editable: isEditable, // Désactiver l'édition si la permanence est désactivée OU si l'événement est passé
|
||||||
|
durationEditable: isEditable, // Désactiver le redimensionnement si la permanence est désactivée OU si l'événement est passé
|
||||||
|
startEditable: isEditable, // Désactiver le déplacement si la permanence est désactivée OU si l'événement est passé
|
||||||
|
classNames: isPermanenceDisabled ? ['permanence-disabled'] : (isEventPast ? ['event-past'] : []),
|
||||||
|
extendedProps: {
|
||||||
|
// Données de base
|
||||||
|
type: ev.type,
|
||||||
|
commentaire: ev.commentaire,
|
||||||
|
date_rdv: ev.date_rdv,
|
||||||
|
heure_rdv: ev.heure_rdv,
|
||||||
|
date_fin: ev.date_fin,
|
||||||
|
heure_fin: ev.heure_fin,
|
||||||
|
|
||||||
|
// Relations avec les entités
|
||||||
|
id_beneficiaire: ev.id_beneficiaire,
|
||||||
|
id_intervenant: ev.id_intervenant,
|
||||||
|
id_traducteur: ev.id_traducteur,
|
||||||
|
id_local: ev.id_local,
|
||||||
|
id_departement: ev.id_departement,
|
||||||
|
id_type_intervention: ev.id_type_intervention || (ev.type_intervention && ev.type_intervention.id ? ev.type_intervention.id : null),
|
||||||
|
langue: ev.langue,
|
||||||
|
langues_disponibles: ev.langues_disponibles || null,
|
||||||
|
|
||||||
|
// Données des entités (si disponibles)
|
||||||
|
beneficiaire: ev.beneficiaire,
|
||||||
|
intervenant: ev.intervenant,
|
||||||
|
traducteur: ev.traducteur,
|
||||||
|
local: ev.local,
|
||||||
|
|
||||||
|
// Données spécifiques aux groupes
|
||||||
|
nb_participants: ev.nb_participants,
|
||||||
|
nb_hommes: ev.nb_hommes,
|
||||||
|
nb_femmes: ev.nb_femmes,
|
||||||
|
|
||||||
|
// Autres données
|
||||||
|
statut: ev.statut,
|
||||||
|
assign: ev.assign || 0,
|
||||||
|
isDisabled: isPermanenceDisabled,
|
||||||
|
created_at: ev.created_at,
|
||||||
|
updated_at: ev.updated_at
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,46 +1,10 @@
|
|||||||
// Module de gestion des filtres dynamiques pour l'agenda
|
// Module de gestion des filtres dynamiques pour l'agenda
|
||||||
import { getEvents } from './agenda-api.js';
|
import { getEvents } from './agenda-api.js';
|
||||||
|
import { mapEventToFullCalendar } from './agenda-event-mapper.js';
|
||||||
|
|
||||||
let currentFilters = {};
|
let currentFilters = {};
|
||||||
let calendarInstance = null;
|
let calendarInstance = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Génère le titre d'un événement en utilisant les données enrichies
|
|
||||||
* @param {Object} event - Données de l'événement
|
|
||||||
* @returns {string} Titre de l'événement
|
|
||||||
*/
|
|
||||||
function getEventTitle(event) {
|
|
||||||
let title = '';
|
|
||||||
|
|
||||||
// Utiliser le nom du bénéficiaire si disponible
|
|
||||||
if (event.beneficiaire && event.beneficiaire.nom_complet) {
|
|
||||||
title = event.beneficiaire.nom_complet;
|
|
||||||
} else if (event.type === 'groupe') {
|
|
||||||
title = 'Groupe';
|
|
||||||
} else {
|
|
||||||
title = event.type || 'Sans type';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajouter le type d'intervention principal si disponible
|
|
||||||
if (event.intervenant && event.intervenant.types_intervention_noms && event.intervenant.types_intervention_noms.length > 0) {
|
|
||||||
const primaryType = event.intervenant.types_intervention_noms[0]; // Premier type d'intervention
|
|
||||||
title += ` - ${primaryType}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajouter le département si disponible (optionnel - décommenter si souhaité)
|
|
||||||
// if (event.intervenant && event.intervenant.departements_noms && event.intervenant.departements_noms.length > 0) {
|
|
||||||
// const departements = event.intervenant.departements_noms.join(', ');
|
|
||||||
// title += ` [${departements}]`;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Ajouter le commentaire si disponible
|
|
||||||
if (event.commentaire) {
|
|
||||||
title += ' - ' + event.commentaire;
|
|
||||||
}
|
|
||||||
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialise les filtres dynamiques
|
* Initialise les filtres dynamiques
|
||||||
* @param {Object} calendar - Instance FullCalendar
|
* @param {Object} calendar - Instance FullCalendar
|
||||||
@ -67,37 +31,7 @@ export function initializeFilters(calendar) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const apiEvents = await getEvents(params);
|
const apiEvents = await getEvents(params);
|
||||||
const events = apiEvents.map(ev => ({
|
const events = apiEvents.map(ev => mapEventToFullCalendar(ev));
|
||||||
id: ev.id,
|
|
||||||
title: getEventTitle(ev),
|
|
||||||
start: ev.date_rdv + 'T' + ev.heure_rdv,
|
|
||||||
end: ev.date_fin + 'T' + ev.heure_fin,
|
|
||||||
extendedProps: {
|
|
||||||
type: ev.type,
|
|
||||||
commentaire: ev.commentaire,
|
|
||||||
date_rdv: ev.date_rdv,
|
|
||||||
heure_rdv: ev.heure_rdv,
|
|
||||||
date_fin: ev.date_fin,
|
|
||||||
heure_fin: ev.heure_fin,
|
|
||||||
// Garder les IDs pour compatibilité
|
|
||||||
id_beneficiaire: ev.id_beneficiaire,
|
|
||||||
id_intervenant: ev.id_intervenant,
|
|
||||||
id_traducteur: ev.id_traducteur,
|
|
||||||
id_local: ev.id_local,
|
|
||||||
langue: ev.langue,
|
|
||||||
// Nouvelles données enrichies
|
|
||||||
beneficiaire: ev.beneficiaire,
|
|
||||||
intervenant: ev.intervenant,
|
|
||||||
traducteur: ev.traducteur,
|
|
||||||
local: ev.local,
|
|
||||||
nb_participants: ev.nb_participants,
|
|
||||||
nb_hommes: ev.nb_hommes,
|
|
||||||
nb_femmes: ev.nb_femmes,
|
|
||||||
statut: ev.statut,
|
|
||||||
created_at: ev.created_at,
|
|
||||||
updated_at: ev.updated_at
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
successCallback(events);
|
successCallback(events);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Erreur lors du chargement des événements:', e);
|
console.error('Erreur lors du chargement des événements:', e);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { openModal } from './agenda-modal.js';
|
|||||||
import { getEvents, updateEvent, getEvent } from './agenda-api.js';
|
import { getEvents, updateEvent, getEvent } from './agenda-api.js';
|
||||||
import { notifyError } from './agenda-notifications.js';
|
import { notifyError } from './agenda-notifications.js';
|
||||||
import { initializeFilters } from './agenda-filters.js';
|
import { initializeFilters } from './agenda-filters.js';
|
||||||
|
import { mapEventToFullCalendar } from './agenda-event-mapper.js';
|
||||||
import toastr from 'toastr';
|
import toastr from 'toastr';
|
||||||
import { Calendar } from '@fullcalendar/core';
|
import { Calendar } from '@fullcalendar/core';
|
||||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||||
@ -12,66 +13,6 @@ import interactionPlugin from '@fullcalendar/interaction';
|
|||||||
import { apiFetch } from './agenda-api.js';
|
import { apiFetch } from './agenda-api.js';
|
||||||
// Ajoutez d'autres plugins si besoin
|
// Ajoutez d'autres plugins si besoin
|
||||||
|
|
||||||
/**
|
|
||||||
* Calcule la luminosité d'une couleur hexadécimale
|
|
||||||
* @param {string} hexColor - Couleur au format #RRGGBB
|
|
||||||
* @returns {number} - Luminosité entre 0 et 1
|
|
||||||
*/
|
|
||||||
function getLuminance(hexColor) {
|
|
||||||
// Vérifier que hexColor n'est pas null ou undefined
|
|
||||||
if (!hexColor || typeof hexColor !== 'string') {
|
|
||||||
console.warn('⚠️ [getLuminance] Valeur hexColor invalide:', hexColor);
|
|
||||||
return 0.5; // Retourner une valeur moyenne par défaut
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convertir hex en RGB
|
|
||||||
const hex = hexColor.replace('#', '');
|
|
||||||
const r = parseInt(hex.substr(0, 2), 16);
|
|
||||||
const g = parseInt(hex.substr(2, 2), 16);
|
|
||||||
const b = parseInt(hex.substr(4, 2), 16);
|
|
||||||
|
|
||||||
// Calculer la luminosité relative selon WCAG
|
|
||||||
return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Détermine la couleur de texte optimale selon le contraste
|
|
||||||
* @param {string} backgroundColor - Couleur de fond au format #RRGGBB
|
|
||||||
* @returns {string} - Couleur de texte (#000000 ou #ffffff)
|
|
||||||
*/
|
|
||||||
function getTextColor(backgroundColor) {
|
|
||||||
// Vérifier que backgroundColor n'est pas null ou undefined
|
|
||||||
if (!backgroundColor || typeof backgroundColor !== 'string') {
|
|
||||||
console.warn('⚠️ [getTextColor] Valeur backgroundColor invalide:', backgroundColor);
|
|
||||||
return '#000000'; // Retourner noir par défaut
|
|
||||||
}
|
|
||||||
|
|
||||||
const luminance = getLuminance(backgroundColor);
|
|
||||||
return luminance > 0.5 ? '#000000' : '#ffffff';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convertit une couleur hexadécimale en RGBA avec opacité
|
|
||||||
* @param {string} hex - Couleur au format #RRGGBB
|
|
||||||
* @param {number} alpha - Opacité entre 0 et 1
|
|
||||||
* @returns {string} - Couleur au format rgba(r, g, b, a)
|
|
||||||
*/
|
|
||||||
function hexToRgba(hex, alpha) {
|
|
||||||
// Vérifier que hex n'est pas null ou undefined
|
|
||||||
if (!hex || typeof hex !== 'string') {
|
|
||||||
console.warn('⚠️ [hexToRgba] Valeur hex invalide:', hex);
|
|
||||||
return `rgba(108, 117, 125, ${alpha || 1})`; // Retourner gris par défaut
|
|
||||||
}
|
|
||||||
|
|
||||||
const hexClean = hex.replace('#', '');
|
|
||||||
const r = parseInt(hexClean.substr(0, 2), 16);
|
|
||||||
const g = parseInt(hexClean.substr(2, 2), 16);
|
|
||||||
const b = parseInt(hexClean.substr(4, 2), 16);
|
|
||||||
const rgbaValue = `rgba(${r}, ${g}, ${b}, ${alpha || 1})`;
|
|
||||||
console.log('🔧 [hexToRgba] Conversion:', { hex, alpha, result: rgbaValue });
|
|
||||||
return rgbaValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function initializeCalendar() {
|
export function initializeCalendar() {
|
||||||
console.log('🚀 Initialisation de FullCalendar...');
|
console.log('🚀 Initialisation de FullCalendar...');
|
||||||
const calendarEl = document.getElementById('agenda-calendar');
|
const calendarEl = document.getElementById('agenda-calendar');
|
||||||
@ -139,451 +80,7 @@ export function initializeCalendar() {
|
|||||||
};
|
};
|
||||||
const apiEvents = await getEvents(params);
|
const apiEvents = await getEvents(params);
|
||||||
// Mapping des objets API vers le format FullCalendar
|
// Mapping des objets API vers le format FullCalendar
|
||||||
const events = apiEvents.map(ev => {
|
const events = apiEvents.map(ev => mapEventToFullCalendar(ev));
|
||||||
// Fonction utilitaire pour trouver la configuration d'un intervenant
|
|
||||||
function findIntervenantConfig(intervenant) {
|
|
||||||
if (!intervenant || !crviACFData || !crviACFData.intervenants) {
|
|
||||||
// console.log('❌ Données manquantes - intervenant:', !!intervenant, 'crviACFData:', !!crviACFData, 'intervenants:', !!crviACFData?.intervenants);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log('Intervenants disponibles:', crviACFData.intervenants);
|
|
||||||
// console.log('Intervenant recherché:', intervenant);
|
|
||||||
|
|
||||||
// Vérifier que l'intervenant a un ID
|
|
||||||
if (!intervenant.id) {
|
|
||||||
// console.log('❌ ID d\'intervenant manquant:', intervenant);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const intervenantId = parseInt(intervenant.id);
|
|
||||||
if (isNaN(intervenantId)) {
|
|
||||||
// console.log('❌ ID d\'intervenant invalide:', intervenant.id);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chercher directement par ID
|
|
||||||
let intervenantConfig = null;
|
|
||||||
for (const key in crviACFData.intervenants) {
|
|
||||||
const config = crviACFData.intervenants[key];
|
|
||||||
|
|
||||||
// Vérifier que la config a un ID
|
|
||||||
if (!config || !config.id) {
|
|
||||||
// console.log('⚠️ Configuration invalide pour la clé:', key, 'config:', config);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log('Comparaison - ID recherché:', intervenantId, 'ID config:', config.id, 'Type config.id:', typeof config.id);
|
|
||||||
|
|
||||||
if (config.id == intervenantId) {
|
|
||||||
intervenantConfig = config;
|
|
||||||
// console.log('✅ Configuration trouvée pour ID:', intervenantId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!intervenantConfig) {
|
|
||||||
// console.log('❌ Aucune configuration trouvée pour l\'ID:', intervenantId);
|
|
||||||
// console.log('IDs disponibles:', Object.values(crviACFData.intervenants).map(c => c.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
return intervenantConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hiérarchie de détermination des couleurs :
|
|
||||||
// 1) Pour RDV assignés (individuel/groupe) avec type d'intervention : couleur du type d'intervention
|
|
||||||
// 2) Pour RDV assignés (individuel/groupe) sans type d'intervention : orange (par défaut)
|
|
||||||
// 3) Pour permanences : couleur selon le type (assignée, non attribuée, non disponible)
|
|
||||||
|
|
||||||
let backgroundColor = null;
|
|
||||||
let textColor = null;
|
|
||||||
|
|
||||||
// Vérifier si l'événement est assigné (a un intervenant et un local/beneficiaire)
|
|
||||||
const isEventAssigned = ev.id_intervenant && (ev.id_local || ev.id_beneficiaire);
|
|
||||||
|
|
||||||
// Pour les RDV (individuel/groupe) assignés
|
|
||||||
if (ev.type && ev.type !== 'permanence' && isEventAssigned) {
|
|
||||||
// Vérifier si l'événement a un type d'intervention défini
|
|
||||||
let typeInterventionId = null;
|
|
||||||
if (ev.id_type_intervention) {
|
|
||||||
typeInterventionId = parseInt(ev.id_type_intervention);
|
|
||||||
} else if (ev.type_intervention && ev.type_intervention.id) {
|
|
||||||
typeInterventionId = parseInt(ev.type_intervention.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si l'événement a un type d'intervention, utiliser sa couleur depuis crviAjax
|
|
||||||
if (typeInterventionId && !isNaN(typeInterventionId) && window.crviAjax && window.crviAjax.couleurs_types_intervention) {
|
|
||||||
const couleurTypeIntervention = window.crviAjax.couleurs_types_intervention[typeInterventionId];
|
|
||||||
if (couleurTypeIntervention) {
|
|
||||||
backgroundColor = couleurTypeIntervention;
|
|
||||||
textColor = getTextColor(couleurTypeIntervention);
|
|
||||||
console.log('🎨 [COULEUR] RDV assigné avec type d\'intervention:', {
|
|
||||||
eventId: ev.id,
|
|
||||||
type: ev.type,
|
|
||||||
typeInterventionId: typeInterventionId,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
textColor: textColor,
|
|
||||||
source: 'type_intervention'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si pas de couleur définie (pas de type d'intervention), garder orange par défaut
|
|
||||||
if (!backgroundColor) {
|
|
||||||
backgroundColor = '#ff9800'; // Orange pour les événements assignés sans type d'intervention
|
|
||||||
textColor = getTextColor(backgroundColor);
|
|
||||||
console.log('🎨 [COULEUR] RDV assigné sans type d\'intervention (défaut orange):', {
|
|
||||||
eventId: ev.id,
|
|
||||||
type: ev.type,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
textColor: textColor,
|
|
||||||
source: 'defaut_assigné'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pour les RDV non assignés : couleur selon type_de_local (bureau ou salle)
|
|
||||||
if (!backgroundColor && ev.type && ev.type !== 'permanence' && !isEventAssigned) {
|
|
||||||
// Vérifier si l'événement a un local avec un type_de_local
|
|
||||||
if (ev.local && ev.local.type_de_local) {
|
|
||||||
const typeLocal = ev.local.type_de_local.toLowerCase();
|
|
||||||
if (crviACFData && crviACFData.couleurs_rdv) {
|
|
||||||
const couleurRdv = crviACFData.couleurs_rdv[typeLocal];
|
|
||||||
if (couleurRdv) {
|
|
||||||
backgroundColor = couleurRdv;
|
|
||||||
textColor = getTextColor(couleurRdv);
|
|
||||||
console.log('🎨 [COULEUR] RDV non assigné selon type de local:', {
|
|
||||||
eventId: ev.id,
|
|
||||||
type: ev.type,
|
|
||||||
typeLocal: typeLocal,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
textColor: textColor,
|
|
||||||
source: 'type_local'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pour permanences (événements de type 'permanence') : logique simplifiée
|
|
||||||
// 1) Non attribuée : dispo ? couleur dispo : couleur indispo
|
|
||||||
// 2) Attribuée : a type intervention ? couleur type : couleur défaut
|
|
||||||
let isPermanenceDisabled = false;
|
|
||||||
if (!backgroundColor && ev.type === 'permanence') {
|
|
||||||
// Une permanence est assignée si elle a un bénéficiaire ET un local (assign = 1)
|
|
||||||
const isPermanenceAssigned = ev.assign === 1 || (ev.id_beneficiaire && ev.id_local);
|
|
||||||
|
|
||||||
// Une permanence est non attribuée si elle n'est pas assignée (assign = 0)
|
|
||||||
const isPermanenceNonAttribuee = ev.assign === 0 && !ev.id_beneficiaire && !ev.id_local;
|
|
||||||
|
|
||||||
// Vérifier si le bénéficiaire est en congé (indisponibilitee_ponctuelle)
|
|
||||||
let isPermanenceNonDisponible = false;
|
|
||||||
if (ev.beneficiaire && ev.beneficiaire.indisponibilitee_ponctuelle && Array.isArray(ev.beneficiaire.indisponibilitee_ponctuelle)) {
|
|
||||||
const eventDate = ev.date_rdv; // Format YYYY-MM-DD
|
|
||||||
const eventDateObj = new Date(eventDate + 'T00:00:00');
|
|
||||||
|
|
||||||
// Vérifier si la date de l'événement est dans une période d'indisponibilité
|
|
||||||
for (const indispo of ev.beneficiaire.indisponibilitee_ponctuelle) {
|
|
||||||
if (indispo.debut && indispo.fin) {
|
|
||||||
let debutDate, finDate;
|
|
||||||
|
|
||||||
// Gérer le format d/m/Y (format ACF)
|
|
||||||
if (typeof indispo.debut === 'string' && indispo.debut.includes('/')) {
|
|
||||||
const debutParts = indispo.debut.split('/');
|
|
||||||
const finParts = indispo.fin.split('/');
|
|
||||||
|
|
||||||
if (debutParts.length === 3 && finParts.length === 3) {
|
|
||||||
// Format d/m/Y
|
|
||||||
debutDate = new Date(parseInt(debutParts[2]), parseInt(debutParts[1]) - 1, parseInt(debutParts[0]));
|
|
||||||
finDate = new Date(parseInt(finParts[2]), parseInt(finParts[1]) - 1, parseInt(finParts[0]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Format YYYY-MM-DD ou timestamp
|
|
||||||
debutDate = new Date(indispo.debut);
|
|
||||||
finDate = new Date(indispo.fin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debutDate && finDate && !isNaN(debutDate.getTime()) && !isNaN(finDate.getTime())) {
|
|
||||||
// Ajuster pour inclure toute la journée
|
|
||||||
debutDate.setHours(0, 0, 0, 0);
|
|
||||||
finDate.setHours(23, 59, 59, 999);
|
|
||||||
|
|
||||||
if (eventDateObj >= debutDate && eventDateObj <= finDate) {
|
|
||||||
isPermanenceNonDisponible = true;
|
|
||||||
isPermanenceDisabled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier si l'intervenant est indisponible (congés ou jour non disponible)
|
|
||||||
if (!isPermanenceNonDisponible && ev.id_intervenant && window.crviACFData && window.crviACFData.indisponibilites_intervenants) {
|
|
||||||
const intervenantId = parseInt(ev.id_intervenant);
|
|
||||||
const intervenantDispo = window.crviACFData.indisponibilites_intervenants[intervenantId];
|
|
||||||
|
|
||||||
if (intervenantDispo) {
|
|
||||||
const eventDate = ev.date_rdv; // Format YYYY-MM-DD
|
|
||||||
const eventDateObj = new Date(eventDate + 'T00:00:00');
|
|
||||||
|
|
||||||
// Vérifier les jours de disponibilité (0 = dimanche, 1 = lundi, etc.)
|
|
||||||
const dayOfWeek = eventDateObj.getDay();
|
|
||||||
const dayNames = ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'];
|
|
||||||
const dayName = dayNames[dayOfWeek];
|
|
||||||
|
|
||||||
// Si l'intervenant a des jours de disponibilité définis et que ce jour n'en fait pas partie
|
|
||||||
if (intervenantDispo.jours_dispo && Array.isArray(intervenantDispo.jours_dispo) &&
|
|
||||||
intervenantDispo.jours_dispo.length > 0 &&
|
|
||||||
!intervenantDispo.jours_dispo.includes(dayName)) {
|
|
||||||
console.log('🚫 [PERMANENCE] Intervenant non disponible ce jour:', {
|
|
||||||
intervenantId,
|
|
||||||
date: eventDate,
|
|
||||||
dayName,
|
|
||||||
joursDisponibles: intervenantDispo.jours_dispo
|
|
||||||
});
|
|
||||||
isPermanenceNonDisponible = true;
|
|
||||||
isPermanenceDisabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier les congés/indisponibilités ponctuelles
|
|
||||||
if (!isPermanenceNonDisponible && intervenantDispo.conges && Array.isArray(intervenantDispo.conges)) {
|
|
||||||
for (const conge of intervenantDispo.conges) {
|
|
||||||
if (conge.debut && conge.fin) {
|
|
||||||
let debutDate, finDate;
|
|
||||||
|
|
||||||
// Gérer le format d/m/Y (format ACF)
|
|
||||||
if (typeof conge.debut === 'string' && conge.debut.includes('/')) {
|
|
||||||
const debutParts = conge.debut.split('/');
|
|
||||||
const finParts = conge.fin.split('/');
|
|
||||||
|
|
||||||
if (debutParts.length === 3 && finParts.length === 3) {
|
|
||||||
debutDate = new Date(parseInt(debutParts[2]), parseInt(debutParts[1]) - 1, parseInt(debutParts[0]));
|
|
||||||
finDate = new Date(parseInt(finParts[2]), parseInt(finParts[1]) - 1, parseInt(finParts[0]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Format YYYY-MM-DD ou timestamp
|
|
||||||
debutDate = new Date(conge.debut);
|
|
||||||
finDate = new Date(conge.fin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debutDate && finDate && !isNaN(debutDate.getTime()) && !isNaN(finDate.getTime())) {
|
|
||||||
debutDate.setHours(0, 0, 0, 0);
|
|
||||||
finDate.setHours(23, 59, 59, 999);
|
|
||||||
|
|
||||||
if (eventDateObj >= debutDate && eventDateObj <= finDate) {
|
|
||||||
console.log('🚫 [PERMANENCE] Intervenant en congé:', {
|
|
||||||
intervenantId,
|
|
||||||
date: eventDate,
|
|
||||||
congeDebut: conge.debut,
|
|
||||||
congeFin: conge.fin,
|
|
||||||
congeType: conge.type
|
|
||||||
});
|
|
||||||
isPermanenceNonDisponible = true;
|
|
||||||
isPermanenceDisabled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier aussi le statut si pas déjà déterminé
|
|
||||||
if (!isPermanenceNonDisponible && ev.statut && ['annule', 'non_tenu', 'absence'].includes(ev.statut)) {
|
|
||||||
isPermanenceNonDisponible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// LOGIQUE SIMPLIFIÉE
|
|
||||||
if (isPermanenceNonAttribuee) {
|
|
||||||
// 1) Non attribuée : dispo ? couleur dispo : couleur indispo
|
|
||||||
if (isPermanenceNonDisponible && window.crviAjax && window.crviAjax.couleur_permanence_non_disponible) {
|
|
||||||
backgroundColor = window.crviAjax.couleur_permanence_non_disponible;
|
|
||||||
console.log('🎨 [COULEUR] Permanence non attribuée - indisponible:', {
|
|
||||||
eventId: ev.id,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
source: 'permanence_non_attribuee_indispo'
|
|
||||||
});
|
|
||||||
} else if (window.crviAjax && window.crviAjax.couleur_permanence_non_attribuee) {
|
|
||||||
backgroundColor = window.crviAjax.couleur_permanence_non_attribuee;
|
|
||||||
console.log('🎨 [COULEUR] Permanence non attribuée - disponible:', {
|
|
||||||
eventId: ev.id,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
source: 'permanence_non_attribuee_dispo'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (isPermanenceAssigned) {
|
|
||||||
// 2) Attribuée : a type intervention ? couleur type : couleur défaut
|
|
||||||
let typeInterventionId = null;
|
|
||||||
if (ev.id_type_intervention) {
|
|
||||||
typeInterventionId = parseInt(ev.id_type_intervention);
|
|
||||||
} else if (ev.type_intervention && ev.type_intervention.id) {
|
|
||||||
typeInterventionId = parseInt(ev.type_intervention.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeInterventionId && !isNaN(typeInterventionId) && window.crviAjax && window.crviAjax.couleurs_types_intervention) {
|
|
||||||
const couleurTypeIntervention = window.crviAjax.couleurs_types_intervention[typeInterventionId];
|
|
||||||
if (couleurTypeIntervention) {
|
|
||||||
backgroundColor = couleurTypeIntervention;
|
|
||||||
console.log('🎨 [COULEUR] Permanence assignée - avec type intervention:', {
|
|
||||||
eventId: ev.id,
|
|
||||||
typeInterventionId: typeInterventionId,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
source: 'permanence_assignee_type'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si pas de type d'intervention, utiliser couleur défaut
|
|
||||||
if (!backgroundColor) {
|
|
||||||
backgroundColor = (crviACFData && crviACFData.couleurs_permanence && crviACFData.couleurs_permanence.permanence)
|
|
||||||
? crviACFData.couleurs_permanence.permanence
|
|
||||||
: '#9e9e9e';
|
|
||||||
console.log('🎨 [COULEUR] Permanence assignée - défaut:', {
|
|
||||||
eventId: ev.id,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
source: 'permanence_assignee_defaut'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// S'assurer que backgroundColor n'est pas null avant d'appeler getTextColor
|
|
||||||
if (backgroundColor) {
|
|
||||||
textColor = getTextColor(backgroundColor);
|
|
||||||
} else {
|
|
||||||
textColor = '#000000'; // Par défaut
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Couleur par défaut si aucune condition n'est remplie
|
|
||||||
if (!backgroundColor) {
|
|
||||||
backgroundColor = '#6c757d'; // Gris par défaut
|
|
||||||
textColor = getTextColor(backgroundColor);
|
|
||||||
console.log('🎨 [COULEUR] Couleur par défaut (gris):', {
|
|
||||||
eventId: ev.id,
|
|
||||||
type: ev.type,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
textColor: textColor,
|
|
||||||
source: 'defaut_general'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log final de la couleur appliquée
|
|
||||||
console.log('🎨 [COULEUR FINALE] Événement:', {
|
|
||||||
eventId: ev.id,
|
|
||||||
title: ev.type || 'Sans type',
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
borderColor: backgroundColor,
|
|
||||||
textColor: textColor,
|
|
||||||
isAssigned: isEventAssigned,
|
|
||||||
type: ev.type
|
|
||||||
});
|
|
||||||
|
|
||||||
// Générer un titre plus explicite
|
|
||||||
let title = ev.type || 'Sans type';
|
|
||||||
|
|
||||||
// Gestion spéciale pour les permanences
|
|
||||||
if (ev.type === 'permanence') {
|
|
||||||
if (ev.intervenant) {
|
|
||||||
const intervenant = ev.intervenant;
|
|
||||||
const nomComplet = `${intervenant.prenom || ''} ${intervenant.nom || ''}`.trim();
|
|
||||||
title = 'p. ' + (nomComplet || 'Intervenant');
|
|
||||||
} else {
|
|
||||||
title = 'p. Intervenant';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Utiliser le nom de l'intervenant comme titre principal pour les autres événements
|
|
||||||
if (ev.intervenant) {
|
|
||||||
const intervenant = ev.intervenant;
|
|
||||||
const nomComplet = `${intervenant.prenom || ''} ${intervenant.nom || ''}`.trim();
|
|
||||||
if (nomComplet) {
|
|
||||||
title = nomComplet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajouter le type d'intervention principal si disponible
|
|
||||||
if (ev.intervenant && ev.intervenant.types_intervention_noms && ev.intervenant.types_intervention_noms.length > 0) {
|
|
||||||
const primaryType = ev.intervenant.types_intervention_noms[0]; // Premier type d'intervention
|
|
||||||
title += ` - ${primaryType}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ajouter le commentaire si disponible
|
|
||||||
if (ev.commentaire) {
|
|
||||||
title += ' - ' + ev.commentaire;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// S'assurer que les couleurs sont toujours définies
|
|
||||||
if (!backgroundColor || typeof backgroundColor !== 'string') {
|
|
||||||
console.warn('⚠️ [Mapping] backgroundColor invalide pour l\'événement:', ev.id, backgroundColor);
|
|
||||||
backgroundColor = '#6c757d'; // Gris par défaut
|
|
||||||
}
|
|
||||||
if (!textColor || typeof textColor !== 'string') {
|
|
||||||
textColor = getTextColor(backgroundColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier si l'événement est passé
|
|
||||||
const eventStartDate = new Date(ev.date_rdv + 'T' + ev.heure_rdv);
|
|
||||||
const now = new Date();
|
|
||||||
const isEventPast = eventStartDate < now;
|
|
||||||
|
|
||||||
// Un événement est éditable seulement si :
|
|
||||||
// 1. Il n'est pas désactivé (permanence)
|
|
||||||
// 2. Il n'est pas passé
|
|
||||||
const isEditable = !isPermanenceDisabled && !isEventPast;
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: ev.id,
|
|
||||||
title: title,
|
|
||||||
start: ev.date_rdv + 'T' + ev.heure_rdv,
|
|
||||||
end: ev.date_fin + 'T' + ev.heure_fin,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
borderColor: backgroundColor,
|
|
||||||
textColor: textColor,
|
|
||||||
editable: isEditable, // Désactiver l'édition si la permanence est désactivée OU si l'événement est passé
|
|
||||||
durationEditable: isEditable, // Désactiver le redimensionnement si la permanence est désactivée OU si l'événement est passé
|
|
||||||
startEditable: isEditable, // Désactiver le déplacement si la permanence est désactivée OU si l'événement est passé
|
|
||||||
classNames: isPermanenceDisabled ? ['permanence-disabled'] : (isEventPast ? ['event-past'] : []),
|
|
||||||
extendedProps: {
|
|
||||||
// Données de base
|
|
||||||
type: ev.type,
|
|
||||||
commentaire: ev.commentaire,
|
|
||||||
date_rdv: ev.date_rdv,
|
|
||||||
heure_rdv: ev.heure_rdv,
|
|
||||||
date_fin: ev.date_fin,
|
|
||||||
heure_fin: ev.heure_fin,
|
|
||||||
|
|
||||||
// Relations avec les entités
|
|
||||||
id_beneficiaire: ev.id_beneficiaire,
|
|
||||||
id_intervenant: ev.id_intervenant,
|
|
||||||
id_traducteur: ev.id_traducteur,
|
|
||||||
id_local: ev.id_local,
|
|
||||||
id_departement: ev.id_departement,
|
|
||||||
id_type_intervention: ev.id_type_intervention || (ev.type_intervention && ev.type_intervention.id ? ev.type_intervention.id : null),
|
|
||||||
langue: ev.langue,
|
|
||||||
langues_disponibles: ev.langues_disponibles || null,
|
|
||||||
|
|
||||||
// Données des entités (si disponibles)
|
|
||||||
beneficiaire: ev.beneficiaire,
|
|
||||||
intervenant: ev.intervenant,
|
|
||||||
traducteur: ev.traducteur,
|
|
||||||
local: ev.local,
|
|
||||||
|
|
||||||
// Données spécifiques aux groupes
|
|
||||||
nb_participants: ev.nb_participants,
|
|
||||||
nb_hommes: ev.nb_hommes,
|
|
||||||
nb_femmes: ev.nb_femmes,
|
|
||||||
|
|
||||||
// Autres données
|
|
||||||
statut: ev.statut,
|
|
||||||
assign: ev.assign || 0,
|
|
||||||
isDisabled: isPermanenceDisabled,
|
|
||||||
created_at: ev.created_at,
|
|
||||||
updated_at: ev.updated_at
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
successCallback(events);
|
successCallback(events);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Erreur lors du chargement des événements:', e);
|
console.error('Erreur lors du chargement des événements:', e);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user