691 lines
22 KiB
JavaScript
691 lines
22 KiB
JavaScript
/**
|
|
* 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 = '<i class="fas fa-info-circle me-2"></i>Veuillez sélectionner une plage horaire valide.';
|
|
return;
|
|
}
|
|
|
|
const tranchesList = tranches.map(t => `<li>${t.debut} → ${t.fin}</li>`).join('');
|
|
previewEl.innerHTML = `
|
|
<ul>${tranchesList}</ul>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* Affiche l'estimation du nombre d'événements
|
|
*/
|
|
function displayEstimation(count) {
|
|
const containerEl = document.getElementById('estimation-container');
|
|
const countEl = document.getElementById('estimation-count');
|
|
|
|
if (!containerEl || !countEl) return;
|
|
|
|
if (count > 0) {
|
|
countEl.textContent = count;
|
|
containerEl.style.display = 'block';
|
|
} else {
|
|
containerEl.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Efface l'aperçu
|
|
*/
|
|
function clearPreview() {
|
|
const previewEl = document.getElementById('tranches-preview');
|
|
if (previewEl) {
|
|
previewEl.innerHTML = '<i class="fas fa-info-circle me-2"></i>Veuillez sélectionner une plage horaire pour voir l\'aperçu.';
|
|
}
|
|
|
|
const containerEl = document.getElementById('estimation-container');
|
|
if (containerEl) {
|
|
containerEl.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gère la soumission du formulaire
|
|
*/
|
|
async function handleFormSubmit(e) {
|
|
e.preventDefault();
|
|
|
|
const form = e.target;
|
|
const submitBtn = document.getElementById('submit-permanences-btn');
|
|
|
|
// Validation
|
|
if (!validateForm()) {
|
|
return;
|
|
}
|
|
|
|
// Récupérer les données du formulaire
|
|
const formData = new FormData(form);
|
|
const intervenantId = formData.get('intervenant_id');
|
|
const periode = parseInt(formData.get('periode'));
|
|
const moisDebut = formData.get('mois_debut');
|
|
const jours = formData.getAll('jours[]');
|
|
const heures = formData.getAll('heures[]');
|
|
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 = formData.get('informations_complementaires') || '';
|
|
|
|
// Validation supplémentaire
|
|
if (!intervenantId) {
|
|
toastr.error('Veuillez sélectionner un intervenant', 'Erreur');
|
|
return;
|
|
}
|
|
|
|
if (!moisDebut) {
|
|
toastr.error('Veuillez sélectionner un mois de début', 'Erreur');
|
|
return;
|
|
}
|
|
|
|
if (jours.length === 0) {
|
|
toastr.error('Veuillez sélectionner au moins un jour de la semaine', 'Erreur');
|
|
return;
|
|
}
|
|
|
|
if (heures.length === 0) {
|
|
toastr.error('Veuillez sélectionner au moins une heure de permanence', 'Erreur');
|
|
return;
|
|
}
|
|
|
|
// 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`;
|
|
|
|
// Désactiver le bouton
|
|
submitBtn.disabled = true;
|
|
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Création en cours...';
|
|
|
|
// Préparer les données pour l'API
|
|
const data = {
|
|
intervenant_id: parseInt(intervenantId),
|
|
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
|
|
};
|
|
|
|
try {
|
|
// Appel API (apiFetch retourne directement data, pas response.data)
|
|
const result = await apiFetch('admin/permanences', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
toastr.success(
|
|
`${result.message} (${result.permanences_crees} permanences créées)`,
|
|
'Succès',
|
|
{ timeOut: 5000 }
|
|
);
|
|
|
|
// Réinitialiser le formulaire
|
|
form.reset();
|
|
clearPreview();
|
|
|
|
// Réinitialiser la période par défaut
|
|
document.getElementById('periode-3').checked = true;
|
|
|
|
} catch (error) {
|
|
console.error('Erreur lors de la création des permanences:', error);
|
|
toastr.error('Une erreur est survenue lors de la création des permanences', 'Erreur');
|
|
} finally {
|
|
// Réactiver le bouton
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = '<i class="fas fa-save me-2"></i>Enregistrer les permanences';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Valide le formulaire avant soumission
|
|
*/
|
|
function validateForm() {
|
|
const intervenantId = document.getElementById('intervenant-select')?.value;
|
|
const periode = document.querySelector('input[name="periode"]:checked')?.value;
|
|
const moisDebut = document.getElementById('mois-debut')?.value;
|
|
const joursChecked = document.querySelectorAll('input[name="jours[]"]:checked');
|
|
const heuresChecked = document.querySelectorAll('input[name="heures[]"]:checked');
|
|
|
|
if (!intervenantId) {
|
|
toastr.error('Veuillez sélectionner un intervenant', 'Validation');
|
|
return false;
|
|
}
|
|
|
|
if (!moisDebut) {
|
|
toastr.error('Veuillez sélectionner un mois de début', 'Validation');
|
|
return false;
|
|
}
|
|
|
|
if (!periode) {
|
|
toastr.error('Veuillez sélectionner une période (3 ou 6 mois)', 'Validation');
|
|
return false;
|
|
}
|
|
|
|
if (joursChecked.length === 0) {
|
|
toastr.error('Veuillez sélectionner au moins un jour de la semaine', 'Validation');
|
|
return false;
|
|
}
|
|
|
|
if (heuresChecked.length === 0) {
|
|
toastr.error('Veuillez sélectionner au moins une heure de permanence', 'Validation');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 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');
|
|
|
|
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 = '<i class="fas fa-spinner fa-spin me-2"></i>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/admin/permanences/import-csv';
|
|
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 || 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 = `
|
|
<div class="alert alert-danger">
|
|
<i class="fas fa-exclamation-circle me-2"></i>
|
|
<strong>Erreur :</strong> ${error.message || 'Une erreur est survenue lors de l\'import'}
|
|
</div>
|
|
`;
|
|
resultContainer.style.display = 'block';
|
|
}
|
|
} finally {
|
|
// Réactiver le bouton
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = '<i class="fas fa-upload me-2"></i>Importer le CSV';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 += `
|
|
<div class="alert alert-warning">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
<strong>Attention :</strong> ${result.errors.length} erreur(s) détectée(s)
|
|
</div>
|
|
`;
|
|
|
|
if (result.errors.length <= 10) {
|
|
html += '<ul class="list-group mt-2">';
|
|
result.errors.forEach((error, index) => {
|
|
html += `
|
|
<li class="list-group-item">
|
|
<strong>Ligne ${error.line || '?'} :</strong> ${error.message || 'Erreur inconnue'}
|
|
</li>
|
|
`;
|
|
});
|
|
html += '</ul>';
|
|
}
|
|
}
|
|
|
|
if (result.created > 0) {
|
|
html += `
|
|
<div class="alert alert-success mt-3">
|
|
<i class="fas fa-check-circle me-2"></i>
|
|
<strong>Succès :</strong> ${result.created} permanence(s) créée(s) avec succès
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
container.innerHTML = html;
|
|
container.style.display = 'block';
|
|
}
|
|
|
|
|