/**
* Module Permanences Intervenant
* Gestion du formulaire d'encodage des permanences
*/
import { apiFetch } from './agenda-api.js';
import toastr from 'toastr';
/**
* Initialise le module permanences intervenant
*/
export function initializePermanences() {
console.log('🚀 Initialisation du module permanences intervenant...');
const form = document.getElementById('permanences-form');
if (!form) {
console.error('Formulaire permanences-form non trouvé');
return;
}
// Initialiser le champ mois de début avec le mois actuel
const moisDebutInput = document.getElementById('mois-debut');
if (moisDebutInput && !moisDebutInput.value) {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
moisDebutInput.value = `${year}-${month}`;
}
// Initialiser Select2 pour le champ langues
initializeSelect2();
// Écouter les changements pour mettre à jour l'aperçu
setupPreviewListeners();
// Gérer la soumission du formulaire
form.addEventListener('submit', handleFormSubmit);
// Calculer l'aperçu initial
updatePreview();
// Initialiser le formulaire d'import CSV
initializeCsvImport();
}
/**
* Initialise Select2 pour le champ de sélection des langues
*/
function initializeSelect2() {
const languesSelect = document.getElementById('langues-permanences');
if (languesSelect && typeof jQuery !== 'undefined' && jQuery.fn.select2) {
jQuery(languesSelect).select2({
placeholder: 'Sélectionnez une ou plusieurs langues',
allowClear: true,
width: '100%',
language: {
noResults: function() {
return "Aucun résultat trouvé";
}
}
});
}
}
/**
* Configure les listeners pour mettre à jour l'aperçu en temps réel
*/
function setupPreviewListeners() {
// Écouter les changements de mois de début
const moisDebut = document.getElementById('mois-debut');
if (moisDebut) {
moisDebut.addEventListener('change', updatePreview);
moisDebut.addEventListener('input', updatePreview);
}
// Écouter les changements de période
const periodInputs = document.querySelectorAll('input[name="periode"]');
periodInputs.forEach(input => {
input.addEventListener('change', updatePreview);
});
// Écouter les changements de jours
const joursInputs = document.querySelectorAll('input[name="jours[]"]');
joursInputs.forEach(input => {
input.addEventListener('change', updatePreview);
});
// Écouter les changements des heures sélectionnées
const heuresInputs = document.querySelectorAll('input[name="heures[]"]');
heuresInputs.forEach(input => {
input.addEventListener('change', updatePreview);
});
}
/**
* Calcule et affiche l'aperçu des permanences qui seront créées
*/
function updatePreview() {
const periode = parseInt(document.querySelector('input[name="periode"]:checked')?.value || '3');
const joursChecked = Array.from(document.querySelectorAll('input[name="jours[]"]:checked'))
.map(input => input.value);
const heuresChecked = Array.from(document.querySelectorAll('input[name="heures[]"]:checked'))
.map(input => input.value)
.sort(); // Trier les heures pour un affichage cohérent
const moisDebut = document.getElementById('mois-debut')?.value;
if (heuresChecked.length === 0) {
clearPreview();
return;
}
if (!moisDebut) {
clearPreview();
return;
}
if (joursChecked.length === 0) {
clearPreview();
return;
}
// Calculer les tranches horaires à partir des heures sélectionnées
// Chaque heure sélectionnée = 1 tranche d'1 heure
const tranches = heuresChecked.map(heureDebut => {
const [h, m] = heureDebut.split(':').map(Number);
const heureFin = `${String(h + 1).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
return {
debut: heureDebut,
fin: heureFin
};
});
// Calculer les dates à partir du mois de début sélectionné
const [year, month] = moisDebut.split('-').map(Number);
const startDate = new Date(year, month - 1, 1); // Premier jour du mois sélectionné
const endDate = new Date(year, month - 1 + periode, 0); // Dernier jour du mois de fin
// Compter les occurrences pour chaque jour sélectionné
let totalEvents = 0;
const joursMapping = {
'lundi': 1,
'mardi': 2,
'mercredi': 3,
'jeudi': 4,
'vendredi': 5,
'samedi': 6,
'dimanche': 0
};
const currentDate = new Date(startDate);
while (currentDate <= endDate) {
const dayOfWeek = currentDate.getDay();
const jourName = Object.keys(joursMapping).find(k => joursMapping[k] === dayOfWeek);
if (joursChecked.includes(jourName)) {
totalEvents += tranches.length;
}
currentDate.setDate(currentDate.getDate() + 1);
}
// Afficher l'aperçu
displayPreview({
periode: periode,
jours: joursChecked,
tranches: tranches,
totalEvents: totalEvents,
dateDebut: startDate,
dateFin: endDate
});
}
/**
* Calcule les tranches horaires (par tranche de 1 heure)
*/
function calculateTranches(debut, fin) {
const tranches = [];
const [debutHour, debutMin] = debut.split(':').map(Number);
const [finHour, finMin] = fin.split(':').map(Number);
let currentHour = debutHour;
let currentMin = debutMin;
while (currentHour < finHour || (currentHour === finHour && currentMin < finMin)) {
const trancheDebut = `${String(currentHour).padStart(2, '0')}:${String(currentMin).padStart(2, '0')}`;
// Ajouter 1 heure
currentHour++;
if (currentHour >= 24) {
break; // Ne pas dépasser minuit
}
const trancheFin = `${String(currentHour).padStart(2, '0')}:${String(currentMin).padStart(2, '0')}`;
tranches.push({
debut: trancheDebut,
fin: trancheFin
});
}
return tranches;
}
/**
* Affiche l'aperçu des permanences
*/
function displayPreview(data) {
const container = document.getElementById('preview-container');
if (!container) return;
const joursLabels = {
'lundi': 'Lundi',
'mardi': 'Mardi',
'mercredi': 'Mercredi',
'jeudi': 'Jeudi',
'vendredi': 'Vendredi',
'samedi': 'Samedi',
'dimanche': 'Dimanche'
};
const joursDisplay = data.jours.map(j => joursLabels[j] || j).join(', ');
const dateDebutStr = data.dateDebut.toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', year: 'numeric' });
const dateFinStr = data.dateFin.toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', year: 'numeric' });
container.innerHTML = `
Aperçu des permanences
Période : ${data.periode} mois (du ${dateDebutStr} au ${dateFinStr})
Jours sélectionnés : ${joursDisplay || 'Aucun'}
Tranches horaires :
${data.tranches.length > 0
? data.tranches.map(t => `${t.debut} - ${t.fin}`).join(', ')
: 'Aucune tranche valide'}
Nombre total d'événements à créer : ${data.totalEvents}
`;
}
/**
* Efface l'aperçu
*/
function clearPreview() {
const container = document.getElementById('preview-container');
if (!container) return;
container.innerHTML = `
Veuillez sélectionner au moins un jour et une plage horaire valide pour voir l'aperçu.
`;
}
/**
* Gère la soumission du formulaire
*/
async function handleFormSubmit(event) {
event.preventDefault();
const formElement = document.getElementById('permanences-form');
// Récupérer les données
const periode = parseInt(document.querySelector('input[name="periode"]:checked')?.value || '3');
const moisDebut = document.getElementById('mois-debut')?.value;
const jours = Array.from(document.querySelectorAll('input[name="jours[]"]:checked'))
.map(input => input.value);
const heures = Array.from(document.querySelectorAll('input[name="heures[]"]:checked'))
.map(input => input.value);
const dureePermanence = document.querySelector('input[name="duree_permanence"]:checked')?.value || '1h';
const nbTranches = dureePermanence === '15min' ? parseInt(document.getElementById('nb-tranches')?.value || '1') : null;
// Récupérer les langues sélectionnées via Select2
const languesSelect = document.getElementById('langues-permanences');
const langues = languesSelect && typeof jQuery !== 'undefined' && jQuery(languesSelect).val()
? jQuery(languesSelect).val().filter(value => value !== '')
: [];
const informationsComplementaires = document.getElementById('informations-complementaires')?.value || '';
// Validation
if (!moisDebut) {
toastr.warning('Veuillez sélectionner un mois de début', 'Validation');
return;
}
if (jours.length === 0) {
toastr.warning('Veuillez sélectionner au moins un jour', 'Validation');
return;
}
if (heures.length === 0) {
toastr.warning('Veuillez sélectionner au moins une heure de permanence', 'Validation');
return;
}
// Calculer les tranches à partir des heures sélectionnées
const tranches = heures.map(heureDebut => {
const [h, m] = heureDebut.split(':').map(Number);
const heureFin = `${String(h + 1).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
return {
debut: heureDebut,
fin: heureFin
};
});
// Calculer la plage horaire globale (min et max des heures sélectionnées)
const heuresSorted = heures.map(h => {
const [hour] = h.split(':').map(Number);
return hour;
}).sort((a, b) => a - b);
const heureMin = heuresSorted[0];
const heureMax = heuresSorted[heuresSorted.length - 1];
const plageDebut = `${String(heureMin).padStart(2, '0')}:00`;
const plageFin = `${String(heureMax + 1).padStart(2, '0')}:00`;
// Calculer les dates à partir du mois de début pour l'estimation
const [year, month] = moisDebut.split('-').map(Number);
const startDate = new Date(year, month - 1, 1);
const endDate = new Date(year, month - 1 + periode, 0);
// Demander confirmation si beaucoup d'événements
const estimatedEvents = estimateTotalEvents(startDate, endDate, jours, tranches);
if (estimatedEvents > 50) {
const confirmed = confirm(
`Vous allez créer environ ${estimatedEvents} événements. Êtes-vous sûr de vouloir continuer ?`
);
if (!confirmed) {
return;
}
}
try {
// Désactiver le formulaire
const submitBtn = event.target.querySelector('button[type="submit"]');
if (submitBtn) {
submitBtn.disabled = true;
submitBtn.innerHTML = 'Création en cours...';
}
if (window.CRVI_OVERLAY && formElement) { window.CRVI_OVERLAY.show(formElement); }
// Préparer les données
const data = {
periode: periode,
mois_debut: moisDebut,
jours: jours,
plage_horaire: {
debut: plageDebut,
fin: plageFin
},
heures: heures, // Envoyer aussi les heures individuelles pour le backend
duree_permanence: dureePermanence, // '1h' ou '15min'
nb_tranches: nbTranches, // Nombre de tranches si 15min (1-4), null si 1h
langues: langues, // Langues sélectionnées (peut être un tableau vide)
informations_complementaires: informationsComplementaires
};
// Envoyer Ă l'API
const result = await apiFetch('intervenant/permanences', {
method: 'POST',
body: JSON.stringify(data)
});
toastr.success(
`${result.events_created || 'Les'} permanence(s) ont été créées avec succès`,
'Succès',
{ timeOut: 5000 }
);
// Réinitialiser le formulaire
event.target.reset();
clearPreview();
// Recalculer l'aperçu avec les valeurs par défaut
setTimeout(updatePreview, 100);
} catch (error) {
console.error('Erreur lors de la création des permanences:', error);
toastr.error(
error.message || 'Erreur lors de la création des permanences',
'Erreur',
{ timeOut: 5000 }
);
} finally {
// Réactiver le formulaire
const submitBtn = event.target.querySelector('button[type="submit"]');
if (submitBtn) {
submitBtn.disabled = false;
submitBtn.innerHTML = 'Créer les permanences';
}
if (window.CRVI_OVERLAY && formElement) { window.CRVI_OVERLAY.hide(formElement); }
}
}
/**
* Estime le nombre total d'événements qui seront créés
*/
function estimateTotalEvents(startDate, endDate, jours, tranches) {
const joursMapping = {
'lundi': 1,
'mardi': 2,
'mercredi': 3,
'jeudi': 4,
'vendredi': 5,
'samedi': 6,
'dimanche': 0
};
let total = 0;
const currentDate = new Date(startDate);
while (currentDate <= endDate) {
const dayOfWeek = currentDate.getDay();
const jourName = Object.keys(joursMapping).find(k => joursMapping[k] === dayOfWeek);
if (jours.includes(jourName)) {
total += tranches.length;
}
currentDate.setDate(currentDate.getDate() + 1);
}
return total;
}
/**
* Initialise le formulaire d'import CSV
*/
function initializeCsvImport() {
const csvForm = document.getElementById('import-csv-form');
if (!csvForm) {
console.warn('Formulaire import-csv-form non trouvé');
return;
}
csvForm.addEventListener('submit', handleCsvImportSubmit);
}
/**
* Gère la soumission du formulaire d'import CSV
*/
async function handleCsvImportSubmit(e) {
e.preventDefault();
const form = e.target;
const fileInput = document.getElementById('csv-file');
const submitBtn = document.getElementById('submit-csv-import-btn');
const resultContainer = document.getElementById('csv-import-result');
const csvForm = document.getElementById('import-csv-form');
if (!fileInput || !fileInput.files || fileInput.files.length === 0) {
toastr.error('Veuillez sélectionner un fichier CSV', 'Erreur');
return;
}
const file = fileInput.files[0];
// Vérifier que c'est un fichier CSV
if (!file.name.toLowerCase().endsWith('.csv')) {
toastr.error('Le fichier doit ĂŞtre au format CSV', 'Erreur');
return;
}
// Désactiver le bouton
submitBtn.disabled = true;
submitBtn.innerHTML = 'Import en cours...';
// Créer FormData pour l'upload
const formData = new FormData();
formData.append('file', file);
try {
// Appel API pour l'import CSV
const url = '/wp-json/crvi/v1/intervenant/permanences/import-csv';
if (window.CRVI_OVERLAY && csvForm) { window.CRVI_OVERLAY.show(csvForm); }
const response = await fetch(url, {
method: 'POST',
headers: {
'X-WP-Nonce': window.wpApiSettings?.nonce || ''
},
body: formData
});
const data = await response.json();
if (!response.ok || !data.success) {
const errorMessage = data.error?.message || data.message || 'Erreur lors de l\'import';
throw new Error(errorMessage);
}
// Afficher les résultats
displayCsvImportResult(data.data, resultContainer);
toastr.success(
`Import réussi : ${data.data.created || 0} créés, ${data.data.errors?.length || 0} erreurs`,
'Succès',
{ timeOut: 5000 }
);
// Réinitialiser le formulaire
form.reset();
} catch (error) {
console.error('Erreur lors de l\'import CSV:', error);
toastr.error(error.message || 'Une erreur est survenue lors de l\'import CSV', 'Erreur');
if (resultContainer) {
resultContainer.innerHTML = `
Erreur : ${error.message || 'Une erreur est survenue lors de l\'import'}
`;
resultContainer.style.display = 'block';
}
} finally {
// Réactiver le bouton
submitBtn.disabled = false;
submitBtn.innerHTML = 'Importer le CSV';
if (window.CRVI_OVERLAY && csvForm) { window.CRVI_OVERLAY.hide(csvForm); }
}
}
/**
* Affiche les résultats de l'import CSV
*/
function displayCsvImportResult(result, container) {
if (!container) return;
let html = '';
if (result.errors && result.errors.length > 0) {
html += `
Attention : ${result.errors.length} erreur(s) détectée(s)
`;
if (result.errors.length <= 10) {
html += '';
result.errors.forEach((error, index) => {
html += `
-
Ligne ${error.line || '?'} : ${error.message || 'Erreur inconnue'}
`;
});
html += '
';
}
}
if (result.created > 0) {
html += `
Succès : ${result.created} permanence(s) créée(s) avec succès
`;
}
container.innerHTML = html;
container.style.display = 'block';
}