609 lines
22 KiB
JavaScript
609 lines
22 KiB
JavaScript
/**
|
|
* Module Profil Intervenant
|
|
* Gestion du formulaire de profil et mise à jour des informations
|
|
*/
|
|
|
|
import { apiFetch } from './agenda-api.js';
|
|
import toastr from 'toastr';
|
|
|
|
// Variables globales pour gérer les indisponibilités
|
|
let indisponibilitesList = [];
|
|
let indisponibiliteCounter = 0;
|
|
|
|
/**
|
|
* Initialise le module profil intervenant
|
|
*/
|
|
export function initializeProfile() {
|
|
console.log('🚀 Initialisation du module profil intervenant...');
|
|
|
|
// Charger les données du profil
|
|
loadProfile();
|
|
|
|
// Écouter les événements du formulaire principal
|
|
const profileForm = document.getElementById('profile-form');
|
|
if (profileForm) {
|
|
profileForm.addEventListener('submit', handleProfileSubmit);
|
|
}
|
|
|
|
const cancelBtn = document.getElementById('cancel-profile-btn');
|
|
if (cancelBtn) {
|
|
cancelBtn.addEventListener('click', () => {
|
|
loadProfile(); // Recharger pour annuler les modifications
|
|
});
|
|
}
|
|
|
|
// Écouter les événements du formulaire de disponibilités
|
|
const disponibilitesForm = document.getElementById('disponibilites-form');
|
|
if (disponibilitesForm) {
|
|
disponibilitesForm.addEventListener('submit', handleDisponibilitesSubmit);
|
|
}
|
|
|
|
// Gestion de l'ajout d'indisponibilité
|
|
const addIndispoBtn = document.getElementById('add-indisponibilite-btn');
|
|
if (addIndispoBtn) {
|
|
addIndispoBtn.addEventListener('click', showIndisponibiliteForm);
|
|
}
|
|
|
|
const saveIndispoBtn = document.getElementById('save-indisponibilite-btn');
|
|
if (saveIndispoBtn) {
|
|
saveIndispoBtn.addEventListener('click', saveIndisponibilite);
|
|
}
|
|
|
|
const cancelIndispoBtn = document.getElementById('cancel-indisponibilite-btn');
|
|
if (cancelIndispoBtn) {
|
|
cancelIndispoBtn.addEventListener('click', hideIndisponibiliteForm);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Charge les données du profil depuis l'API
|
|
*/
|
|
async function loadProfile() {
|
|
try {
|
|
const profileContainer = document.getElementById('intervenant-profile-container') || document.getElementById('profile-form') || document.body;
|
|
if (window.CRVI_OVERLAY && profileContainer) { window.CRVI_OVERLAY.show(profileContainer); }
|
|
const profile = await apiFetch('intervenant/profile');
|
|
|
|
// Remplir les champs non modifiables
|
|
const nomEl = document.getElementById('profile-nom');
|
|
const prenomEl = document.getElementById('profile-prenom');
|
|
const emailEl = document.getElementById('profile-email');
|
|
|
|
if (nomEl) nomEl.value = profile.nom || '';
|
|
if (prenomEl) prenomEl.value = profile.prenom || '';
|
|
if (emailEl) emailEl.value = profile.email || '';
|
|
|
|
// Téléphone (modifiable)
|
|
const telephoneEl = document.getElementById('profile-telephone');
|
|
if (telephoneEl) {
|
|
telephoneEl.value = profile.telephone || '';
|
|
}
|
|
|
|
// Jours de disponibilité (checkboxes) - déjà générés en PHP, on met juste à jour les valeurs
|
|
updateJoursDisponibiliteCheckboxes(profile.jours_de_disponibilite || []);
|
|
|
|
// Heures de permanences (checkboxes)
|
|
updateHeuresPermanencesCheckboxes(profile.heures_de_permanences || []);
|
|
|
|
// Indisponibilités ponctuelles - déjà générées en PHP, on synchronise juste la liste
|
|
indisponibilitesList = profile.indisponibilites_ponctuelles || [];
|
|
// Synchroniser la liste avec celle affichée en PHP (pour les mises à jour après sauvegarde)
|
|
syncIndisponibilitesList(indisponibilitesList);
|
|
// Rafraîchir explicitement l'affichage pour éviter tout écart visuel
|
|
displayIndisponibilites(indisponibilitesList);
|
|
|
|
// Départements (format: [{id, nom}, ...])
|
|
displayDepartements(profile.departements || []);
|
|
|
|
// Spécialisations (format: [{id, nom}, ...])
|
|
displaySpecialisations(profile.specialisations || []);
|
|
|
|
} catch (error) {
|
|
console.error('Erreur lors du chargement du profil:', error);
|
|
toastr.error(
|
|
error.message || 'Erreur lors du chargement du profil',
|
|
'Erreur',
|
|
{ timeOut: 5000 }
|
|
);
|
|
} finally {
|
|
const profileContainer = document.getElementById('intervenant-profile-container') || document.getElementById('profile-form') || document.body;
|
|
if (window.CRVI_OVERLAY && profileContainer) { window.CRVI_OVERLAY.hide(profileContainer); }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Met à jour les checkboxes des jours de disponibilité (déjà générées en PHP)
|
|
*/
|
|
function updateJoursDisponibiliteCheckboxes(joursActuels) {
|
|
const joursValues = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'];
|
|
|
|
joursValues.forEach(jour => {
|
|
const checkbox = document.getElementById(`jour-${jour}`);
|
|
if (checkbox) {
|
|
checkbox.checked = joursActuels.includes(jour);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Met à jour les checkboxes des heures de permanences
|
|
*/
|
|
function updateHeuresPermanencesCheckboxes(heuresActuelles) {
|
|
const heuresValues = ['09:00','10:00','11:00','12:00','13:00','14:00','15:00','16:00'];
|
|
heuresValues.forEach(h => {
|
|
const checkbox = document.getElementById(`heure-${h}`);
|
|
if (checkbox) {
|
|
checkbox.checked = Array.isArray(heuresActuelles) && heuresActuelles.includes(h);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Synchronise la liste JS des indisponibilités avec les données de l'API
|
|
* (les indisponibilités sont déjà affichées en PHP, on synchronise juste la liste interne)
|
|
*/
|
|
function syncIndisponibilitesList(indisponibilites) {
|
|
// La liste est déjà affichée en PHP, on synchronise juste la liste JS
|
|
// pour les opérations d'ajout/suppression
|
|
indisponibilitesList = indisponibilites || [];
|
|
|
|
// Mettre à jour l'affichage si des indisponibilités ont été ajoutées/supprimées
|
|
const container = document.getElementById('profile-indisponibilites-list');
|
|
const emptyContainer = document.getElementById('profile-indisponibilites-empty');
|
|
|
|
if (!container) return;
|
|
|
|
// Si la liste est vide, afficher le message
|
|
if (indisponibilitesList.length === 0) {
|
|
const existingItems = container.querySelectorAll('.indisponibilite-item');
|
|
existingItems.forEach(item => item.remove());
|
|
if (emptyContainer) {
|
|
emptyContainer.style.display = 'block';
|
|
}
|
|
} else {
|
|
if (emptyContainer) {
|
|
emptyContainer.style.display = 'none';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Affiche les indisponibilités ponctuelles (utilisée après ajout/suppression)
|
|
*/
|
|
function displayIndisponibilites(indisponibilites) {
|
|
const container = document.getElementById('profile-indisponibilites-list');
|
|
const emptyContainer = document.getElementById('profile-indisponibilites-empty');
|
|
|
|
if (!container) return;
|
|
|
|
if (!indisponibilites || indisponibilites.length === 0) {
|
|
container.innerHTML = '';
|
|
if (emptyContainer) {
|
|
emptyContainer.style.display = 'block';
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (emptyContainer) {
|
|
emptyContainer.style.display = 'none';
|
|
}
|
|
|
|
// Types d'indisponibilité
|
|
const typesLabels = {
|
|
'conge': 'Congé',
|
|
'absence': 'Absence',
|
|
'maladie': 'Maladie'
|
|
};
|
|
|
|
container.innerHTML = indisponibilites.map((indisp, index) => {
|
|
const debut = indisp.debut || '';
|
|
const fin = indisp.fin || '';
|
|
const type = indisp.type || 'conge';
|
|
const typeLabel = typesLabels[type] || type;
|
|
const commentaire = indisp.commentaire || '';
|
|
|
|
// Badge classes selon type
|
|
let badgeClass = 'badge-indispo-unknown';
|
|
if (type === 'conge') badgeClass = 'badge-indispo-conge';
|
|
else if (type === 'absence') badgeClass = 'badge-indispo-absence';
|
|
else if (type === 'maladie') badgeClass = 'badge-indispo-maladie';
|
|
|
|
// Convertir les dates au format d/m/Y pour l'affichage
|
|
let debutFormatted = debut;
|
|
let finFormatted = fin;
|
|
|
|
// Si les dates sont au format YYYY-MM-DD, les convertir
|
|
if (debut && debut.match(/^\d{4}-\d{2}-\d{2}$/)) {
|
|
const dateObj = new Date(debut);
|
|
debutFormatted = dateObj.toLocaleDateString('fr-FR');
|
|
}
|
|
if (fin && fin.match(/^\d{4}-\d{2}-\d{2}$/)) {
|
|
const dateObj = new Date(fin);
|
|
finFormatted = dateObj.toLocaleDateString('fr-FR');
|
|
}
|
|
|
|
// Afficher la période
|
|
let periodeText = '';
|
|
if (debutFormatted && finFormatted) {
|
|
if (debutFormatted === finFormatted) {
|
|
periodeText = `Le ${debutFormatted}`;
|
|
} else {
|
|
periodeText = `Du ${debutFormatted} au ${finFormatted}`;
|
|
}
|
|
} else if (debutFormatted) {
|
|
periodeText = `Le ${debutFormatted}`;
|
|
}
|
|
|
|
return `
|
|
<div class="indisponibilite-item indispo-${type}" data-index="${index}">
|
|
<div>
|
|
<strong>${periodeText}</strong>
|
|
<span class="badge ${badgeClass} ms-2">${typeLabel}</span>
|
|
${commentaire ? `<p class="mb-0 text-muted mt-1">${commentaire}</p>` : ''}
|
|
</div>
|
|
<button type="button" class="btn-remove" onclick="removeIndisponibilite(${index})" title="Supprimer">
|
|
<i class="fas fa-times"></i>
|
|
</button>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
// Fonction globale pour supprimer une indisponibilité
|
|
window.removeIndisponibilite = function(index) {
|
|
if (confirm('Êtes-vous sûr de vouloir supprimer cette indisponibilité ?')) {
|
|
indisponibilitesList.splice(index, 1);
|
|
displayIndisponibilites(indisponibilitesList);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Affiche le formulaire d'ajout d'indisponibilité
|
|
*/
|
|
function showIndisponibiliteForm() {
|
|
const container = document.getElementById('indisponibilite-form-container');
|
|
if (container) {
|
|
container.style.display = 'block';
|
|
|
|
// Ajouter les attributs required quand le formulaire est visible
|
|
const debutInput = document.getElementById('indispo-debut');
|
|
const finInput = document.getElementById('indispo-fin');
|
|
const typeSelect = document.getElementById('indispo-type');
|
|
|
|
if (debutInput) debutInput.setAttribute('required', 'required');
|
|
if (finInput) finInput.setAttribute('required', 'required');
|
|
if (typeSelect) typeSelect.setAttribute('required', 'required');
|
|
|
|
// Réinitialiser les champs
|
|
if (debutInput) debutInput.value = '';
|
|
if (finInput) finInput.value = '';
|
|
if (typeSelect) typeSelect.value = '';
|
|
const commentaireTextarea = document.getElementById('indispo-commentaire');
|
|
if (commentaireTextarea) commentaireTextarea.value = '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cache le formulaire d'ajout d'indisponibilité
|
|
*/
|
|
function hideIndisponibiliteForm() {
|
|
const container = document.getElementById('indisponibilite-form-container');
|
|
if (container) {
|
|
container.style.display = 'none';
|
|
|
|
// Retirer les attributs required quand le formulaire est caché
|
|
const debutInput = document.getElementById('indispo-debut');
|
|
const finInput = document.getElementById('indispo-fin');
|
|
const typeSelect = document.getElementById('indispo-type');
|
|
|
|
if (debutInput) debutInput.removeAttribute('required');
|
|
if (finInput) finInput.removeAttribute('required');
|
|
if (typeSelect) typeSelect.removeAttribute('required');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sauvegarde une nouvelle indisponibilité dans la liste
|
|
*/
|
|
function saveIndisponibilite() {
|
|
const debut = document.getElementById('indispo-debut').value;
|
|
const fin = document.getElementById('indispo-fin').value;
|
|
const type = document.getElementById('indispo-type').value;
|
|
const commentaire = document.getElementById('indispo-commentaire').value.trim();
|
|
|
|
// Validation
|
|
if (!debut || !fin || !type) {
|
|
toastr.warning('Veuillez remplir tous les champs obligatoires', 'Validation');
|
|
return;
|
|
}
|
|
|
|
// Vérifier que la date de fin est après la date de début
|
|
if (new Date(fin) < new Date(debut)) {
|
|
toastr.warning('La date de fin doit être supérieure ou égale à la date de début', 'Validation');
|
|
return;
|
|
}
|
|
|
|
// Convertir les dates au format d/m/Y pour ACF
|
|
const debutFormatted = formatDateToDMY(debut);
|
|
const finFormatted = formatDateToDMY(fin);
|
|
|
|
// Ajouter à la liste
|
|
indisponibilitesList.push({
|
|
debut: debutFormatted,
|
|
fin: finFormatted,
|
|
type: type,
|
|
commentaire: commentaire
|
|
});
|
|
|
|
// Rafraîchir l'affichage
|
|
displayIndisponibilites(indisponibilitesList);
|
|
|
|
// Cacher le formulaire
|
|
hideIndisponibiliteForm();
|
|
|
|
toastr.success('Indisponibilité ajoutée. N\'oubliez pas d\'enregistrer.', 'Succès', { timeOut: 3000 });
|
|
}
|
|
|
|
/**
|
|
* Convertit une date au format YYYY-MM-DD vers d/m/Y
|
|
*/
|
|
function formatDateToDMY(dateStr) {
|
|
if (!dateStr) return '';
|
|
const date = new Date(dateStr);
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const year = date.getFullYear();
|
|
return `${day}/${month}/${year}`;
|
|
}
|
|
|
|
/**
|
|
* Convertit une date au format d/m/Y vers YYYY-MM-DD
|
|
*/
|
|
function formatDateToYMD(dateStr) {
|
|
if (!dateStr) return '';
|
|
// Format d/m/Y vers YYYY-MM-DD
|
|
const parts = dateStr.split('/');
|
|
if (parts.length === 3) {
|
|
return `${parts[2]}-${parts[1]}-${parts[0]}`;
|
|
}
|
|
return dateStr;
|
|
}
|
|
|
|
/**
|
|
* Affiche les départements
|
|
*/
|
|
function displayDepartements(departements) {
|
|
const container = document.getElementById('profile-departements');
|
|
if (!container) return;
|
|
|
|
if (!departements || departements.length === 0) {
|
|
container.innerHTML = '<span class="text-muted">Aucun département assigné</span>';
|
|
return;
|
|
}
|
|
|
|
// Les départements viennent comme objets {id, nom}
|
|
container.innerHTML = departements.map(dep => {
|
|
const nom = dep.nom || dep.post_title || `Département #${dep.id || dep.ID || dep}`;
|
|
return `<span class="badge bg-secondary me-2 mb-2">${nom}</span>`;
|
|
}).join('');
|
|
}
|
|
|
|
/**
|
|
* Affiche les spécialisations (types d'intervention)
|
|
*/
|
|
function displaySpecialisations(specialisations) {
|
|
const container = document.getElementById('profile-specialisations');
|
|
if (!container) return;
|
|
|
|
if (!specialisations || specialisations.length === 0) {
|
|
container.innerHTML = '<span class="text-muted">Aucune spécialisation assignée</span>';
|
|
return;
|
|
}
|
|
|
|
// Les spécialisations viennent comme objets {id, nom}
|
|
container.innerHTML = specialisations.map(spec => {
|
|
const nom = spec.nom || spec.post_title || `Spécialisation #${spec.id || spec.ID || spec}`;
|
|
return `<span class="badge bg-primary me-2 mb-2">${nom}</span>`;
|
|
}).join('');
|
|
}
|
|
|
|
/**
|
|
* Gère la soumission du formulaire de profil
|
|
*/
|
|
async function handleProfileSubmit(event) {
|
|
event.preventDefault();
|
|
|
|
const telephoneEl = document.getElementById('profile-telephone');
|
|
if (!telephoneEl) {
|
|
toastr.error('Champ téléphone non trouvé', 'Erreur');
|
|
return;
|
|
}
|
|
|
|
const telephone = telephoneEl.value.trim();
|
|
|
|
// Validation basique
|
|
if (!telephone) {
|
|
toastr.warning('Le numéro de téléphone est requis', 'Validation');
|
|
telephoneEl.focus();
|
|
return;
|
|
}
|
|
|
|
// Format de validation simple (à adapter selon les besoins)
|
|
const phoneRegex = /^[0-9+\s\-()]{8,}$/;
|
|
if (!phoneRegex.test(telephone)) {
|
|
toastr.warning('Format de numéro de téléphone invalide', 'Validation');
|
|
telephoneEl.focus();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Désactiver le bouton de soumission
|
|
const submitBtn = event.target.querySelector('button[type="submit"]');
|
|
if (submitBtn) {
|
|
submitBtn.disabled = true;
|
|
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Enregistrement...';
|
|
}
|
|
const profileContainer = document.getElementById('intervenant-profile-container') || document.getElementById('profile-form') || document.body;
|
|
if (window.CRVI_OVERLAY && profileContainer) { window.CRVI_OVERLAY.show(profileContainer); }
|
|
|
|
await apiFetch('intervenant/profile', {
|
|
method: 'PUT',
|
|
body: JSON.stringify({
|
|
telephone: telephone
|
|
})
|
|
});
|
|
|
|
toastr.success(
|
|
'Profil mis à jour avec succès',
|
|
'Succès',
|
|
{ timeOut: 3000 }
|
|
);
|
|
|
|
// Recharger le profil pour avoir les données à jour
|
|
await loadProfile();
|
|
|
|
} catch (error) {
|
|
console.error('Erreur lors de la mise à jour du profil:', error);
|
|
toastr.error(
|
|
error.message || 'Erreur lors de la mise à jour du profil',
|
|
'Erreur',
|
|
{ timeOut: 5000 }
|
|
);
|
|
} finally {
|
|
// Réactiver le bouton
|
|
const submitBtn = event.target.querySelector('button[type="submit"]');
|
|
if (submitBtn) {
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = '<i class="fas fa-save me-2"></i>Enregistrer les modifications';
|
|
}
|
|
const profileContainer = document.getElementById('intervenant-profile-container') || document.getElementById('profile-form') || document.body;
|
|
if (window.CRVI_OVERLAY && profileContainer) { window.CRVI_OVERLAY.hide(profileContainer); }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gère la soumission du formulaire de disponibilités
|
|
*/
|
|
async function handleDisponibilitesSubmit(event) {
|
|
event.preventDefault();
|
|
|
|
try {
|
|
// Récupérer les jours de disponibilité cochés
|
|
const joursCheckboxes = document.querySelectorAll('input[name="jours_disponibilite[]"]:checked');
|
|
const joursDisponibilite = Array.from(joursCheckboxes).map(cb => cb.value);
|
|
|
|
// Récupérer les heures de permanences cochées
|
|
const heuresCheckboxes = document.querySelectorAll('input[name="heures_permanences[]"]:checked');
|
|
const heuresPermanences = Array.from(heuresCheckboxes).map(cb => cb.value);
|
|
|
|
// Désactiver le bouton de soumission
|
|
const submitBtn = event.target.querySelector('button[type="submit"]');
|
|
if (submitBtn) {
|
|
submitBtn.disabled = true;
|
|
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Enregistrement...';
|
|
}
|
|
const profileContainer = document.getElementById('intervenant-profile-container') || document.getElementById('disponibilites-form') || document.body;
|
|
if (window.CRVI_OVERLAY && profileContainer) { window.CRVI_OVERLAY.show(profileContainer); }
|
|
|
|
await apiFetch('intervenant/profile', {
|
|
method: 'PUT',
|
|
body: JSON.stringify({
|
|
jours_de_disponibilite: joursDisponibilite,
|
|
heures_de_permanences: heuresPermanences,
|
|
indisponibilites_ponctuelles: indisponibilitesList
|
|
})
|
|
});
|
|
|
|
toastr.success(
|
|
'Disponibilités mises à jour avec succès',
|
|
'Succès',
|
|
{ timeOut: 3000 }
|
|
);
|
|
|
|
// Vérifier s'il y a des conflits d'indisponibilités
|
|
await checkAndDisplayConflicts();
|
|
|
|
// Recharger le profil pour avoir les données à jour
|
|
await loadProfile();
|
|
|
|
} catch (error) {
|
|
console.error('Erreur lors de la mise à jour des disponibilités:', error);
|
|
toastr.error(
|
|
error.message || 'Erreur lors de la mise à jour des disponibilités',
|
|
'Erreur',
|
|
{ timeOut: 5000 }
|
|
);
|
|
} finally {
|
|
// Réactiver le bouton
|
|
const submitBtn = event.target.querySelector('button[type="submit"]');
|
|
if (submitBtn) {
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = '<i class="fas fa-save me-2"></i>Enregistrer les disponibilités';
|
|
}
|
|
const profileContainer = document.getElementById('intervenant-profile-container') || document.getElementById('disponibilites-form') || document.body;
|
|
if (window.CRVI_OVERLAY && profileContainer) { window.CRVI_OVERLAY.hide(profileContainer); }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Vérifie et affiche les conflits d'indisponibilités après la sauvegarde
|
|
*/
|
|
async function checkAndDisplayConflicts() {
|
|
try {
|
|
// Faire une requête à l'API WordPress pour récupérer le message de conflit
|
|
const response = await apiFetch('intervenant/conflicts-check');
|
|
|
|
if (response && response.has_conflicts && response.message) {
|
|
// Afficher le message de conflit en haut de la page
|
|
displayConflictMessage(response.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('Erreur lors de la vérification des conflits:', error);
|
|
// Ne pas afficher d'erreur à l'utilisateur pour ne pas perturber l'expérience
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Affiche un message de conflit en haut de la page
|
|
* @param {string} message - Le message HTML à afficher
|
|
*/
|
|
function displayConflictMessage(message) {
|
|
// Trouver le conteneur où afficher le message (après le header, avant le contenu)
|
|
const container = document.querySelector('.crvi-intervenant-profile .container-fluid');
|
|
if (!container) return;
|
|
|
|
// Supprimer les anciens messages de conflit s'il y en a
|
|
const oldAlert = container.querySelector('.conflict-alert');
|
|
if (oldAlert) {
|
|
oldAlert.remove();
|
|
}
|
|
|
|
// Créer un nouvel élément d'alerte
|
|
const alertDiv = document.createElement('div');
|
|
alertDiv.className = 'conflict-alert alert alert-danger alert-dismissible fade show mt-3';
|
|
alertDiv.setAttribute('role', 'alert');
|
|
alertDiv.innerHTML = message;
|
|
|
|
// Ajouter un bouton de fermeture
|
|
const closeButton = document.createElement('button');
|
|
closeButton.type = 'button';
|
|
closeButton.className = 'btn-close';
|
|
closeButton.setAttribute('data-bs-dismiss', 'alert');
|
|
closeButton.setAttribute('aria-label', 'Close');
|
|
alertDiv.appendChild(closeButton);
|
|
|
|
// Insérer le message après la navigation (row mb-4)
|
|
const navRow = container.querySelector('.row.mb-4');
|
|
if (navRow && navRow.nextSibling) {
|
|
container.insertBefore(alertDiv, navRow.nextSibling);
|
|
} else {
|
|
container.insertBefore(alertDiv, container.firstChild);
|
|
}
|
|
|
|
// Scroller vers le haut pour voir le message
|
|
window.scrollTo({
|
|
top: 0,
|
|
behavior: 'smooth'
|
|
});
|
|
}
|