/**
* Module Agenda Intervenant
* Adapte l'agenda existant pour utiliser les endpoints intervenant
* Réutilise les modules agenda-fullcalendar.js, agenda-filters.js, etc.
*/
import { apiFetch, updateEvent, getEvent } from './agenda-api.js';
import { notifyError, notifySuccess } from './agenda-notifications.js';
import { openModal } from './agenda-modal.js';
import { Calendar } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import listPlugin from '@fullcalendar/list';
import interactionPlugin from '@fullcalendar/interaction';
// Mode de vue : 'mine' ou 'colleagues'
let currentViewMode = 'mine';
/**
* Initialise le calendrier pour l'intervenant (mon agenda)
*/
export function initializeIntervenantCalendar() {
console.log('🚀 Initialisation du calendrier intervenant (mon agenda)...');
const calendarEl = document.getElementById('agenda-calendar');
if (!calendarEl) {
console.error('❌ Élément agenda-calendar non trouvé');
return null;
}
currentViewMode = 'mine';
const calendar = new Calendar(calendarEl, {
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
initialView: 'dayGridMonth',
eventDisplay: 'block',
locale: 'fr',
firstDay: 1,
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
buttonText: {
today: 'Aujourd\'hui',
month: 'Mois',
week: 'Semaine',
day: 'Jour',
list: 'Liste'
},
height: 'auto',
// On active l'édition globalement, mais on contrôle au niveau de chaque
// événement + des permissions (is_mine + crviPermissions.can_edit)
editable: true,
eventStartEditable: true,
eventDurationEditable: true,
eventResizableFromStart: true,
selectable: true, // Activer la sélection pour créer des RDV
dayMaxEvents: 3,
weekends: true,
moreLinkClick: 'popover', // Afficher les événements cachés dans un popover
moreLinkContent: function(arg) {
// Personnaliser le texte du lien "+x plus"
const count = arg.num;
return `+${count} plus`;
},
// Gestionnaire de sélection de plage de dates pour créer un événement
select: function(arg) {
// Vérifier les permissions de création
const userCanCreate = window.crviPermissions && window.crviPermissions.can_create;
if (!userCanCreate) {
notifyError('Vous n\'êtes pas autorisé à créer des événements');
console.warn('❌ Utilisateur non autorisé à créer des événements (permissions WP)');
return;
}
// Vérifier que la date de début n'est pas dans le passé
if (arg.startStr) {
const startDateStr = arg.startStr.split('T')[0];
const today = new Date();
today.setHours(0, 0, 0, 0);
const selectedDate = new Date(startDateStr + 'T00:00:00');
selectedDate.setHours(0, 0, 0, 0);
if (selectedDate < today) {
notifyError('Impossible de créer un événement à une date passée');
console.warn('⚠️ Tentative de création d\'événement à une date passée:', startDateStr);
return;
}
}
// Préremplir avec l'intervenant actuel (utilisateur connecté)
const currentUserId = window.crviPermissions && window.crviPermissions.user_id;
// Ouvrir le modal de création avec l'intervenant prérempli
const eventData = {
...arg,
extendedProps: {
id_intervenant: currentUserId
}
};
openModal('create', eventData);
},
// Charger les événements depuis l'endpoint intervenant
events: async function(fetchInfo, successCallback, failureCallback) {
try {
const filters = collectIntervenantFilters();
const params = {
start: fetchInfo.startStr.split('T')[0],
end: fetchInfo.endStr.split('T')[0],
view_mode: 'mine', // Toujours en mode "mon agenda"
filters: JSON.stringify(filters)
};
const events = await apiFetch('intervenant/agenda?' + new URLSearchParams(params));
// Formater pour FullCalendar
const formattedEvents = events.map(event => {
// Extraire la date et l'heure depuis start si disponibles
let date_rdv = null;
let heure_rdv = null;
if (event.start) {
const startDate = new Date(event.start);
date_rdv = startDate.toISOString().split('T')[0];
heure_rdv = startDate.toTimeString().substring(0, 5);
}
return {
id: event.id,
title: event.title,
start: event.start,
end: event.end,
backgroundColor: getEventColor(event),
borderColor: getEventColor(event),
textColor: '#fff',
// Seuls les événements "à moi" sont éditables côté UI
editable: !!event.is_mine,
durationEditable: !!event.is_mine,
startEditable: !!event.is_mine,
extendedProps: {
type: event.type,
statut: event.statut,
is_mine: event.is_mine,
show_comments: event.show_comments,
commentaire: event.commentaire,
beneficiaire: event.beneficiaire,
local: event.local,
intervenant_nom: event.intervenant_nom,
date: date_rdv,
date_rdv: date_rdv,
heure: heure_rdv,
heure_rdv: heure_rdv,
langue: event.langue,
langues_disponibles: event.langues_disponibles || null
}
};
});
successCallback(formattedEvents);
} catch (error) {
console.error('Erreur lors du chargement de l\'agenda:', error);
failureCallback(error);
}
},
// Déplacement d'un événement (drag & drop)
eventDrop: async function(info) {
const props = info.event.extendedProps || {};
// Vérifier que l'événement appartient bien à l'intervenant
if (!props.is_mine) {
console.warn('❌ Tentative de déplacement d’un événement qui ne vous appartient pas');
info.revert();
notifyError('Vous ne pouvez déplacer que vos propres rendez-vous');
return;
}
// Vérifier les permissions globales
const userCanEdit = window.crviPermissions && window.crviPermissions.can_edit;
if (!userCanEdit) {
console.warn('❌ Utilisateur non autorisé à déplacer des événements (permissions WP)');
info.revert();
notifyError('Vous n\'êtes pas autorisé à modifier les événements');
return;
}
try {
const newStart = info.event.start;
const newEnd = info.event.end || new Date(newStart.getTime() + 60 * 60 * 1000); // +1h par défaut
const updateData = {
date_rdv: newStart.toISOString().split('T')[0],
heure_rdv: newStart.toTimeString().substring(0, 5),
date_fin: newEnd.toISOString().split('T')[0],
heure_fin: newEnd.toTimeString().substring(0, 5)
};
await updateEvent(info.event.id, updateData);
notifySuccess('Événement déplacé avec succès');
} catch (error) {
console.error('Erreur lors du déplacement de l\'événement (front intervenant):', error);
info.revert();
notifyError('Erreur lors du déplacement de l\'événement');
}
},
// Redimensionnement d'un événement (changement de durée)
eventResize: async function(info) {
const props = info.event.extendedProps || {};
if (!props.is_mine) {
console.warn('❌ Tentative de redimensionnement d’un événement qui ne vous appartient pas');
info.revert();
notifyError('Vous ne pouvez modifier que vos propres rendez-vous');
return;
}
const userCanEdit = window.crviPermissions && window.crviPermissions.can_edit;
if (!userCanEdit) {
console.warn('❌ Utilisateur non autorisé à redimensionner des événements (permissions WP)');
info.revert();
notifyError('Vous n\'êtes pas autorisé à modifier les événements');
return;
}
try {
const newEnd = info.event.end;
const updateData = {
date_fin: newEnd.toISOString().split('T')[0],
heure_fin: newEnd.toTimeString().substring(0, 5)
};
await updateEvent(info.event.id, updateData);
notifySuccess('Événement redimensionné avec succès');
} catch (error) {
console.error('Erreur lors du redimensionnement de l\'événement (front intervenant):', error);
info.revert();
notifyError('Erreur lors du redimensionnement de l\'événement');
}
},
eventClick: function(info) {
// Ouvrir le modal avec les détails (adapter le modal existant)
openIntervenantEventModal(info.event);
},
// Ajouter les popovers Bootstrap sur les événements
eventDidMount: function(arg) {
const eventEl = arg.el;
const event = arg.event;
const eventProps = event.extendedProps || {};
// Fonction utilitaire pour formater une date au format français
function formatDateToFrench(dateString) {
if (!dateString) return '';
try {
const date = new Date(dateString);
if (isNaN(date.getTime())) {
// Si ce n'est pas une date valide, essayer le format YYYY-MM-DD
const parts = dateString.split('-');
if (parts.length === 3) {
return `${parts[2]}/${parts[1]}/${parts[0]}`;
}
return dateString;
}
return date.toLocaleDateString('fr-FR');
} catch (error) {
console.error('Erreur lors du formatage de la date:', error);
return dateString;
}
}
// Fonction utilitaire pour extraire le nom complet d'une entité
function getEntityDisplayName(entity, entityType = '') {
if (!entity) return '';
// Si c'est déjà une chaîne, la retourner
if (typeof entity === 'string') return entity;
// Si c'est un objet avec une propriété nom
if (entity && typeof entity === 'object') {
// Pour les bénéficiaires et intervenants, combiner prénom et nom
if (entityType === 'beneficiaire' || entityType === 'intervenant') {
const prenom = entity.prenom || '';
const nom = entity.nom || '';
return `${prenom} ${nom}`.trim() || entity.nom || entity.display_name || '';
}
// Pour les locaux, utiliser le nom
if (entityType === 'local') {
return entity.nom || entity.display_name || '';
}
// Fallback générique
return entity.nom || entity.display_name || entity.name || '';
}
return '';
}
// Extraire la date et l'heure depuis event.start si pas dans extendedProps
let dateStr = eventProps.date || eventProps.date_rdv || '';
let heureStr = eventProps.heure || eventProps.heure_rdv || '';
if (!dateStr && event.start) {
const startDate = new Date(event.start);
dateStr = startDate.toISOString().split('T')[0];
}
if (!heureStr && event.start) {
const startDate = new Date(event.start);
heureStr = startDate.toTimeString().substring(0, 5);
}
// Créer le contenu du popover
const popoverContent = `
${event.title}
Date: ${formatDateToFrench(dateStr)}
Heure: ${heureStr}
Type: ${eventProps.type || ''}
${eventProps.langue ? `
Langue: ${eventProps.langue}
` : ''}
${eventProps.beneficiaire ? `
Bénéficiaire: ${typeof eventProps.beneficiaire === 'string' ? eventProps.beneficiaire : getEntityDisplayName(eventProps.beneficiaire, 'beneficiaire')}
` : ''}
${eventProps.intervenant_nom ? `
Intervenant: ${eventProps.intervenant_nom}
` : ''}
${eventProps.local ? `
Local: ${typeof eventProps.local === 'string' ? eventProps.local : getEntityDisplayName(eventProps.local, 'local')}
` : ''}
${eventProps.commentaire && eventProps.show_comments ? `
Commentaire: ${eventProps.commentaire}
` : ''}
Statut: ${eventProps.statut || ''}
Cliquez pour plus de détails
`;
// Initialiser le popover Bootstrap
if (window.bootstrap && window.bootstrap.Popover) {
const popover = new bootstrap.Popover(eventEl, {
title: 'Détails de l\'événement',
content: popoverContent,
html: true,
trigger: 'hover',
placement: 'top',
container: 'body',
template: ''
});
}
}
});
calendar.render();
window.currentCalendar = calendar;
// Masquer l'indicateur de chargement
const loadingIndicator = document.getElementById('loading-indicator');
if (loadingIndicator) {
loadingIndicator.style.display = 'none';
}
// Initialiser les filtres adaptés pour intervenant
initializeIntervenantFilters(calendar);
return calendar;
}
/**
* Initialise le calendrier pour les collègues
*/
export function initializeColleaguesCalendar() {
console.log('🚀 Initialisation du calendrier collègues...');
const calendarEl = document.getElementById('agenda-calendar-colleagues');
if (!calendarEl) {
console.error('❌ Élément agenda-calendar-colleagues non trouvé');
return null;
}
currentViewMode = 'colleagues';
const calendar = new Calendar(calendarEl, {
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
initialView: 'dayGridMonth',
eventDisplay: 'block',
locale: 'fr',
firstDay: 1,
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
buttonText: {
today: 'Aujourd\'hui',
month: 'Mois',
week: 'Semaine',
day: 'Jour',
list: 'Liste'
},
height: 'auto',
editable: false,
selectable: false,
dayMaxEvents: 3,
weekends: true,
moreLinkClick: 'popover', // Afficher les événements cachés dans un popover
moreLinkContent: function(arg) {
// Personnaliser le texte du lien "+x plus"
const count = arg.num;
return `+${count} plus`;
},
events: async function(fetchInfo, successCallback, failureCallback) {
try {
const filters = collectColleaguesFilters();
const params = {
start: fetchInfo.startStr.split('T')[0],
end: fetchInfo.endStr.split('T')[0],
view_mode: 'colleagues',
filters: JSON.stringify(filters)
};
const events = await apiFetch('intervenant/agenda?' + new URLSearchParams(params));
const formattedEvents = events.map(event => {
// Extraire la date et l'heure depuis start si disponibles
let date_rdv = null;
let heure_rdv = null;
if (event.start) {
const startDate = new Date(event.start);
date_rdv = startDate.toISOString().split('T')[0];
heure_rdv = startDate.toTimeString().substring(0, 5);
}
return {
id: event.id,
title: event.title,
start: event.start,
end: event.end,
backgroundColor: getEventColor(event),
borderColor: getEventColor(event),
textColor: '#fff',
extendedProps: {
type: event.type,
statut: event.statut,
is_mine: event.is_mine,
show_comments: false, // Jamais de commentaires pour les collègues
beneficiaire: event.beneficiaire,
local: event.local,
intervenant_nom: event.intervenant_nom,
date: date_rdv,
date_rdv: date_rdv,
heure: heure_rdv,
heure_rdv: heure_rdv,
langue: event.langue
}
};
});
successCallback(formattedEvents);
} catch (error) {
console.error('Erreur lors du chargement de l\'agenda des collègues:', error);
failureCallback(error);
}
},
eventClick: function(info) {
openIntervenantEventModal(info.event);
},
// Ajouter les popovers Bootstrap sur les événements
eventDidMount: function(arg) {
const eventEl = arg.el;
const event = arg.event;
const eventProps = event.extendedProps || {};
// Fonction utilitaire pour formater une date au format français
function formatDateToFrench(dateString) {
if (!dateString) return '';
try {
const date = new Date(dateString);
if (isNaN(date.getTime())) {
// Si ce n'est pas une date valide, essayer le format YYYY-MM-DD
const parts = dateString.split('-');
if (parts.length === 3) {
return `${parts[2]}/${parts[1]}/${parts[0]}`;
}
return dateString;
}
return date.toLocaleDateString('fr-FR');
} catch (error) {
console.error('Erreur lors du formatage de la date:', error);
return dateString;
}
}
// Fonction utilitaire pour extraire le nom complet d'une entité
function getEntityDisplayName(entity, entityType = '') {
if (!entity) return '';
// Si c'est déjà une chaîne, la retourner
if (typeof entity === 'string') return entity;
// Si c'est un objet avec une propriété nom
if (entity && typeof entity === 'object') {
// Pour les bénéficiaires et intervenants, combiner prénom et nom
if (entityType === 'beneficiaire' || entityType === 'intervenant') {
const prenom = entity.prenom || '';
const nom = entity.nom || '';
return `${prenom} ${nom}`.trim() || entity.nom || entity.display_name || '';
}
// Pour les locaux, utiliser le nom
if (entityType === 'local') {
return entity.nom || entity.display_name || '';
}
// Fallback générique
return entity.nom || entity.display_name || entity.name || '';
}
return '';
}
// Extraire la date et l'heure depuis event.start si pas dans extendedProps
let dateStr = eventProps.date || eventProps.date_rdv || '';
let heureStr = eventProps.heure || eventProps.heure_rdv || '';
if (!dateStr && event.start) {
const startDate = new Date(event.start);
dateStr = startDate.toISOString().split('T')[0];
}
if (!heureStr && event.start) {
const startDate = new Date(event.start);
heureStr = startDate.toTimeString().substring(0, 5);
}
// Créer le contenu du popover
const popoverContent = `
${event.title}
Date: ${formatDateToFrench(dateStr)}
Heure: ${heureStr}
Type: ${eventProps.type || ''}
${eventProps.langue ? `
Langue: ${eventProps.langue}
` : ''}
${eventProps.beneficiaire ? `
Bénéficiaire: ${typeof eventProps.beneficiaire === 'string' ? eventProps.beneficiaire : getEntityDisplayName(eventProps.beneficiaire, 'beneficiaire')}
` : ''}
${eventProps.intervenant_nom ? `
Intervenant: ${eventProps.intervenant_nom}
` : ''}
${eventProps.local ? `
Local: ${typeof eventProps.local === 'string' ? eventProps.local : getEntityDisplayName(eventProps.local, 'local')}
` : ''}
${eventProps.commentaire && eventProps.show_comments ? `
Commentaire: ${eventProps.commentaire}
` : ''}
Statut: ${eventProps.statut || ''}
Cliquez pour plus de détails
`;
// Initialiser le popover Bootstrap
if (window.bootstrap && window.bootstrap.Popover) {
const popover = new bootstrap.Popover(eventEl, {
title: 'Détails de l\'événement',
content: popoverContent,
html: true,
trigger: 'hover',
placement: 'top',
container: 'body',
template: ''
});
}
}
});
calendar.render();
window.currentColleaguesCalendar = calendar;
const loadingIndicator = document.getElementById('loading-indicator-colleagues');
if (loadingIndicator) {
loadingIndicator.style.display = 'none';
}
initializeColleaguesFilters(calendar);
return calendar;
}
/**
* Collecte les filtres depuis le formulaire "Mon agenda"
*/
function collectIntervenantFilters() {
const filters = {};
const local = document.getElementById('local')?.value;
if (local) filters.local_id = parseInt(local);
const beneficiaire = document.getElementById('beneficiaire')?.value;
if (beneficiaire) filters.beneficiaire_id = parseInt(beneficiaire);
const typeRdv = document.getElementById('type_rdv')?.value;
if (typeRdv) filters.type_rdv = typeRdv;
const departement = document.getElementById('departement')?.value;
if (departement) filters.departement = parseInt(departement);
const typeIntervention = document.getElementById('type_intervention')?.value;
if (typeIntervention) filters.type_intervention = parseInt(typeIntervention);
const langue = document.getElementById('langue_filtre')?.value;
if (langue) filters.langue = langue;
const permanences = document.getElementById('permanences_non_assignees')?.checked;
if (permanences) filters.permanences_non_assignees = true;
return filters;
}
/**
* Collecte les filtres depuis le formulaire "Agenda des collègues"
*/
function collectColleaguesFilters() {
const filters = {};
const local = document.getElementById('local-colleagues')?.value;
if (local) filters.local_id = parseInt(local);
const beneficiaire = document.getElementById('beneficiaire-colleagues')?.value;
if (beneficiaire) filters.beneficiaire_id = parseInt(beneficiaire);
const typeRdv = document.getElementById('type_rdv-colleagues')?.value;
if (typeRdv) filters.type_rdv = typeRdv;
const departement = document.getElementById('departement-colleagues')?.value;
if (departement) filters.departement = parseInt(departement);
const typeIntervention = document.getElementById('type_intervention-colleagues')?.value;
if (typeIntervention) filters.type_intervention = parseInt(typeIntervention);
const langue = document.getElementById('langue-colleagues')?.value;
if (langue) filters.langue = langue;
return filters;
}
/**
* Initialise les filtres pour "Mon agenda"
*/
function initializeIntervenantFilters(calendar) {
// Charger les options de filtres depuis l'endpoint disponibilités
loadFilterOptions('intervenant');
// Écouter les changements de filtres
const filterForm = document.querySelector('.filters');
if (filterForm) {
const filterBtn = document.getElementById('filterBtn');
if (filterBtn) {
filterBtn.addEventListener('click', () => {
calendar.refetchEvents();
});
}
const resetBtn = document.getElementById('resetFiltersBtn');
if (resetBtn) {
resetBtn.addEventListener('click', () => {
filterForm.reset();
calendar.refetchEvents();
});
}
// Bouton "Ajouter un événement"
const addEventBtn = document.getElementById('addEventBtn');
if (addEventBtn) {
addEventBtn.addEventListener('click', () => {
// Vérifier les permissions de création
const userCanCreate = window.crviPermissions && window.crviPermissions.can_create;
if (!userCanCreate) {
notifyError('Vous n\'êtes pas autorisé à créer des événements');
console.warn('❌ Utilisateur non autorisé à créer des événements (permissions WP)');
return;
}
// Ouvrir le modal de création avec la date du jour et l'intervenant prérempli
const today = new Date();
const dateStr = today.toISOString().split('T')[0];
const startStr = dateStr + 'T09:00:00';
const endStr = dateStr + 'T10:00:00';
// Préremplir avec l'intervenant actuel (utilisateur connecté)
const currentUserId = window.crviPermissions && window.crviPermissions.user_id;
openModal('create', {
start: new Date(startStr),
end: new Date(endStr),
startStr: startStr,
endStr: endStr,
allDay: false,
extendedProps: {
id_intervenant: currentUserId
}
});
});
}
// Auto-filtrer sur changement
const selects = filterForm.querySelectorAll('select, input[type="checkbox"]');
selects.forEach(el => {
el.addEventListener('change', () => {
setTimeout(() => calendar.refetchEvents(), 300);
});
});
}
}
/**
* Initialise les filtres pour "Agenda des collègues"
*/
function initializeColleaguesFilters(calendar) {
loadFilterOptions('colleagues');
const filterForm = document.querySelector('.filters-colleagues');
if (filterForm) {
const filterBtn = document.getElementById('filterBtn-colleagues');
if (filterBtn) {
filterBtn.addEventListener('click', () => {
calendar.refetchEvents();
});
}
const resetBtn = document.getElementById('resetFiltersBtn-colleagues');
if (resetBtn) {
resetBtn.addEventListener('click', () => {
filterForm.reset();
calendar.refetchEvents();
});
}
const selects = filterForm.querySelectorAll('select');
selects.forEach(el => {
el.addEventListener('change', () => {
setTimeout(() => calendar.refetchEvents(), 300);
});
});
}
}
/**
* Charge les options des filtres depuis l'endpoint disponibilités
*/
async function loadFilterOptions(mode = 'intervenant') {
try {
const disponibilites = await apiFetch('agenda/disponibilites');
const prefix = mode === 'colleagues' ? '-colleagues' : '';
// Locaux
const localSelect = document.getElementById(`local${prefix}`);
if (localSelect && disponibilites.locaux) {
disponibilites.locaux.forEach(local => {
const option = document.createElement('option');
option.value = local.id;
option.textContent = local.nom;
localSelect.appendChild(option);
});
}
// Bénéficiaires
const beneficiaireSelect = document.getElementById(`beneficiaire${prefix}`);
if (beneficiaireSelect && disponibilites.beneficiaires) {
disponibilites.beneficiaires.forEach(benef => {
const option = document.createElement('option');
option.value = benef.id;
option.textContent = benef.nom;
beneficiaireSelect.appendChild(option);
});
}
// Départements
const departementSelect = document.getElementById(`departement${prefix}`);
if (departementSelect && disponibilites.departements) {
disponibilites.departements.forEach(dept => {
const option = document.createElement('option');
option.value = dept.id;
option.textContent = dept.nom;
departementSelect.appendChild(option);
});
}
// Types d'intervention
const typeInterventionSelect = document.getElementById(`type_intervention${prefix}`);
if (typeInterventionSelect && disponibilites.types_intervention) {
disponibilites.types_intervention.forEach(type => {
const option = document.createElement('option');
option.value = type.id;
option.textContent = type.nom;
typeInterventionSelect.appendChild(option);
});
}
// Langues
const langueSelect = document.getElementById(`langue${prefix}`);
if (langueSelect && disponibilites.langues) {
disponibilites.langues.forEach(langue => {
const option = document.createElement('option');
option.value = langue.id;
option.textContent = langue.nom;
langueSelect.appendChild(option);
});
}
// Initialiser Select2
if (window.jQuery && jQuery().select2) {
jQuery(`select${prefix ? '[id$="-colleagues"]' : ':not([id$="-colleagues"])'}`).select2();
}
} catch (error) {
console.error('Erreur lors du chargement des options de filtres:', error);
}
}
/**
* Détermine la couleur d'un événement selon son type/statut
*/
function getEventColor(event) {
if (event.type === 'permanence') {
return '#17a2b8'; // Teal pour les permanences
}
// Couleur selon le statut
switch (event.statut) {
case 'prevu':
return '#28a745'; // Vert
case 'present':
return '#0d6efd'; // Bleu
case 'absent':
return '#dc3545'; // Rouge
case 'cloture':
return '#6c757d'; // Gris
default:
return '#ffc107'; // Jaune
}
}
/**
* Ouvre le modal complet (eventModal) en mode vue, comme côté admin.
* Charge d'abord les détails complets de l'événement via l'API.
*/
async function openIntervenantEventModal(event) {
const userCanView = window.crviPermissions && window.crviPermissions.can_view;
if (!userCanView) {
console.warn('❌ Utilisateur non autorisé à voir les événements (permissions WP)');
notifyError('Vous n\'êtes pas autorisé à consulter les événements');
return;
}
try {
// Overlay sur le calendrier pendant le chargement des détails
const calendarEl = document.getElementById('agenda-calendar') || document.getElementById('agenda-calendar-colleagues');
if (window.CRVI_OVERLAY && calendarEl) { window.CRVI_OVERLAY.show(calendarEl); }
const eventId = event.id;
const eventDetails = await getEvent(eventId);
let startDate;
let endDate;
try {
// Date de début
if (eventDetails.date_rdv && eventDetails.heure_rdv) {
startDate = new Date(eventDetails.date_rdv + 'T' + eventDetails.heure_rdv);
if (isNaN(startDate.getTime())) {
startDate = new Date();
}
} else {
startDate = new Date(event.start);
}
// Date de fin
if (eventDetails.date_fin && eventDetails.heure_fin) {
endDate = new Date(eventDetails.date_fin + 'T' + eventDetails.heure_fin);
if (isNaN(endDate.getTime())) {
endDate = startDate;
}
} else {
endDate = event.end ? new Date(event.end) : startDate;
}
} catch (e) {
console.error('Erreur lors de la création des dates (intervenant):', e);
startDate = new Date();
endDate = new Date();
}
const fullEvent = {
id: eventDetails.id,
start: startDate,
end: endDate,
extendedProps: {
// Données de base
type: eventDetails.type,
commentaire: eventDetails.commentaire,
date: eventDetails.date_rdv,
heure: eventDetails.heure_rdv,
date_fin: eventDetails.date_fin,
heure_fin: eventDetails.heure_fin,
// Relations
id_beneficiaire: eventDetails.id_beneficiaire,
id_intervenant: eventDetails.id_intervenant,
id_traducteur: eventDetails.id_traducteur,
id_local: eventDetails.id_local,
langue: eventDetails.langue,
langues_disponibles: eventDetails.langues_disponibles || null,
beneficiaire: eventDetails.beneficiaire,
intervenant: eventDetails.intervenant,
traducteur: eventDetails.traducteur,
local: eventDetails.local,
// Données groupe
nb_participants: eventDetails.nb_participants,
nb_hommes: eventDetails.nb_hommes,
nb_femmes: eventDetails.nb_femmes,
// Autres
statut: eventDetails.statut,
created_at: eventDetails.created_at,
updated_at: eventDetails.updated_at
}
};
// Ouvrir le modal complet en mode "view" (mĂŞme pattern qu'en admin)
openModal('view', fullEvent);
} catch (error) {
console.error('Erreur lors du chargement des détails de l\'événement (intervenant):', error);
notifyError('Erreur lors du chargement des détails de l\'événement');
} finally {
const calendarEl = document.getElementById('agenda-calendar') || document.getElementById('agenda-calendar-colleagues');
if (window.CRVI_OVERLAY && calendarEl) { window.CRVI_OVERLAY.hide(calendarEl); }
}
}
/**
* Retourne la classe Bootstrap pour le badge de statut
*/
function getStatusBadgeClass(statut) {
switch (statut) {
case 'prevu':
return 'success';
case 'present':
return 'primary';
case 'absent':
return 'danger';
case 'cloture':
return 'secondary';
case 'annule':
return 'warning';
default:
return 'secondary';
}
}
/**
* Initialise les onglets pour basculer entre mon agenda et agenda des collègues
*/
export function initializeIntervenantAgendaTabs() {
const myAgendaTab = document.getElementById('my-agenda-tab');
const colleaguesTab = document.getElementById('colleagues-agenda-tab');
let myCalendar = null;
let colleaguesCalendar = null;
if (myAgendaTab) {
myAgendaTab.addEventListener('shown.bs.tab', () => {
console.log('🔄 Basculement vers Mon Agenda (mode: mine)');
if (!myCalendar) {
myCalendar = initializeIntervenantCalendar();
} else {
myCalendar.refetchEvents();
}
});
}
if (colleaguesTab) {
colleaguesTab.addEventListener('shown.bs.tab', () => {
console.log('🔄 Basculement vers Agenda des collègues (mode: colleagues)');
if (!colleaguesCalendar) {
colleaguesCalendar = initializeColleaguesCalendar();
} else {
colleaguesCalendar.refetchEvents();
}
});
}
// Initialiser le premier onglet (mon agenda) par défaut
if (myAgendaTab && myAgendaTab.classList.contains('active')) {
myCalendar = initializeIntervenantCalendar();
}
}