/** * Module Permanences Admin * Gestion du formulaire d'encodage des permanences pour l'admin (avec sélection d'intervenant) */ import { apiFetch } from './agenda-api.js'; import toastr from 'toastr'; /** * Initialise le module permanences admin */ export function initializeAdminPermanences() { console.log('🚀 Initialisation du module permanences admin...'); const form = document.getElementById('admin-permanences-form'); if (!form) { console.error('Formulaire admin-permanences-form non trouvé'); return; } // Préselection des jours et heures selon l'intervenant setupIntervenantDefaults(); // 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 la préselection des inputs jours[] et heures[] * à partir des attributs data-days et data-time-slots de l'option sélectionnée */ function setupIntervenantDefaults() { const select = document.getElementById('intervenant-select'); if (!select) return; // Suivi des changements manuels pour ne pas écraser l'utilisateur let hasUserChanged = false; // Marquer qu'il y a eu modification dès qu'une case est cochée/décochée const markChanged = () => { hasUserChanged = true; }; document.querySelectorAll('input[name="jours[]"]').forEach(input => { input.addEventListener('change', markChanged); }); document.querySelectorAll('input[name="heures[]"]').forEach(input => { input.addEventListener('change', markChanged); }); const applyDefaults = () => { // Si l'utilisateur a déjà modifié les cases, ne pas écraser ses choix if (hasUserChanged) { // Laisser l'aperçu se recalculer d'après l'état courant updatePreview(); return; } const option = select.options[select.selectedIndex]; if (!option) return; const daysStr = option.getAttribute('data-days') || ''; const timesStr = option.getAttribute('data-time-slots') || ''; const days = daysStr .split(',') .map(s => s.trim().toLowerCase()) .filter(Boolean); const times = timesStr .split(',') .map(s => s.trim()) .filter(Boolean); // Réinitialiser toutes les cases document.querySelectorAll('input[name="jours[]"]').forEach(input => { input.checked = false; }); document.querySelectorAll('input[name="heures[]"]').forEach(input => { input.checked = false; }); // Appliquer les jours if (days.length > 0) { document.querySelectorAll('input[name="jours[]"]').forEach(input => { const value = String(input.value || '').toLowerCase(); if (days.includes(value)) { input.checked = true; } }); } // Appliquer les heures if (times.length > 0) { document.querySelectorAll('input[name="heures[]"]').forEach(input => { const value = String(input.value || '').trim(); if (times.includes(value)) { input.checked = true; } }); } // Mettre à jour l'aperçu updatePreview(); }; // Sur changement d'intervenant select.addEventListener('change', applyDefaults); // Initialisation à l'ouverture si une option est déjà sélectionnée applyDefaults(); // Si le formulaire est réinitialisé, réactiver l'application auto des valeurs par défaut const form = document.getElementById('admin-permanences-form'); if (form) { form.addEventListener('reset', () => { // Attendre la remise à zéro effective du DOM setTimeout(() => { hasUserChanged = false; applyDefaults(); }, 0); }); } } /** * 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); }); // Écouter les changements de durée de permanence (1h ou 15min) const dureeInputs = document.querySelectorAll('input[name="duree_permanence"]'); dureeInputs.forEach(input => { input.addEventListener('change', updatePreview); }); // Écouter les changements du nombre de tranches (si 15min) const nbTranchesSelect = document.getElementById('nb-tranches'); if (nbTranchesSelect) { nbTranchesSelect.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; const dureePermanence = document.querySelector('input[name="duree_permanence"]:checked')?.value || '1h'; const nbTranches = dureePermanence === '15min' ? parseInt(document.getElementById('nb-tranches')?.value || '1') : 1; 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 let tranches = []; if (dureePermanence === '15min') { // Mode 15 minutes : créer des tranches de 15 minutes heuresChecked.forEach(heureDebut => { const [h, m] = heureDebut.split(':').map(Number); for (let i = 0; i < nbTranches; i++) { const minutesDebut = m + (i * 15); const minutesFin = m + ((i + 1) * 15); const trancheDebut = `${String(h).padStart(2, '0')}:${String(minutesDebut).padStart(2, '0')}`; const trancheFin = `${String(h).padStart(2, '0')}:${String(minutesFin).padStart(2, '0')}`; tranches.push({ debut: trancheDebut, fin: trancheFin }); } }); } else { // Mode 1 heure : chaque heure sélectionnée = 1 tranche d'1 heure 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 }; joursChecked.forEach(jour => { const jourNum = joursMapping[jour.toLowerCase()]; if (jourNum !== undefined) { const occurrences = countDayOccurrences(jourNum, startDate, endDate); totalEvents += occurrences * tranches.length; } }); // Afficher les tranches displayTranches(tranches); // Afficher l'estimation displayEstimation(totalEvents); } /** * Calcule les tranches horaires d'1 heure dans une plage */ function calculateTranches(heureDebut, heureFin) { const tranches = []; const [debutH, debutM] = heureDebut.split(':').map(Number); const [finH, finM] = heureFin.split(':').map(Number); let currentH = debutH; let currentM = debutM; while (currentH < finH || (currentH === finH && currentM < finM)) { const trancheDebut = `${String(currentH).padStart(2, '0')}:${String(currentM).padStart(2, '0')}`; // Ajouter 1 heure currentH += 1; const trancheFin = `${String(currentH).padStart(2, '0')}:${String(currentM).padStart(2, '0')}`; // Vérifier que la tranche ne dépasse pas l'heure de fin if (currentH < finH || (currentH === finH && currentM <= finM)) { tranches.push({ debut: trancheDebut, fin: trancheFin }); } else { break; } } return tranches; } /** * Compte le nombre d'occurrences d'un jour de la semaine dans une plage de dates */ function countDayOccurrences(jourSemaine, startDate, endDate) { let count = 0; const current = new Date(startDate); // Ajuster au premier jour de la semaine ciblée const currentDay = current.getDay(); const diff = (jourSemaine - currentDay + 7) % 7; current.setDate(current.getDate() + diff); // Compter les occurrences while (current <= endDate) { count++; current.setDate(current.getDate() + 7); // Semaine suivante } return count; } /** * Affiche les tranches horaires générées */ function displayTranches(tranches) { const previewEl = document.getElementById('tranches-preview'); if (!previewEl) return; if (tranches.length === 0) { previewEl.innerHTML = 'Veuillez sélectionner une plage horaire valide.'; return; } const tranchesList = tranches.map(t => `