/** * 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 += ''; } } if (result.created > 0) { html += `
Succès : ${result.created} permanence(s) créée(s) avec succès
`; } container.innerHTML = html; container.style.display = 'block'; }