Amélioration du loader : timeout 5s, intégration automatique, correction username

- Ajout d'un timeout de 5 secondes avec message d'erreur pour mauvaise connexion
- Intégration automatique du loader dans fetchWithJson()
- Ajout du loader sur tous les appels fetch manuels (index, historiqueParcours, client-form, intermediaire-form, nav-parcours)
- Correction du problème d'affichage username sur index.js (gestion erreurs et vérification éléments HTML)
- Loader premier élément dans layout.ejs pour chargement immédiat
- Délai de 500ms avant affichage pour éviter flash sur chargements rapides
- Gestion d'erreurs améliorée dans nav-parcours.js
This commit is contained in:
Alexis Burnaz 2025-11-17 22:49:53 +01:00
parent 0be5fe4419
commit fb74a43146
10 changed files with 436 additions and 180 deletions

View File

@ -25,6 +25,7 @@ document.addEventListener('DOMContentLoaded', function () {
// Récupération des informations du parcours // Récupération des informations du parcours
(async () => { (async () => {
try { try {
// Le loader est déjà géré dans fetchWithJson
const data = await fetchWithJson(`/auth/verifyMatricule/${matricule}`, 'GET'); const data = await fetchWithJson(`/auth/verifyMatricule/${matricule}`, 'GET');
if (data.valid) { if (data.valid) {

View File

@ -141,6 +141,11 @@
async function handleModalExtract() { async function handleModalExtract() {
document.getElementById('modalExtraireClient').disabled = true; document.getElementById('modalExtraireClient').disabled = true;
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
const response = await fetch(`/client/extract`, { const response = await fetch(`/client/extract`, {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
@ -183,6 +188,20 @@
document.getElementById("error-extract").style.display = "block"; document.getElementById("error-extract").style.display = "block";
document.getElementById('modalExtraireClient').disabled = false; document.getElementById('modalExtraireClient').disabled = false;
console.log("Problème rencontré lors de l'extraction cl063 AxA PAC :", res.error); console.log("Problème rencontré lors de l'extraction cl063 AxA PAC :", res.error);
if (typeof window.showError === 'function') {
window.showError("Erreur lors de l'extraction des données client.");
}
}
} catch (error) {
console.error("Erreur lors de l'extraction client:", error);
if (typeof window.showError === 'function') {
window.showError("Erreur lors de l'extraction. Vérifiez votre connexion.");
}
} finally {
document.getElementById('modalExtraireClient').disabled = false;
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
} }
} }
@ -190,6 +209,11 @@
async function handleSubmitForm(event) { async function handleSubmitForm(event) {
event.preventDefault(); event.preventDefault();
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
let idClient = client?.id; let idClient = client?.id;
const numClient = document.getElementById('numClient').value; const numClient = document.getElementById('numClient').value;
@ -264,12 +288,44 @@
sessionStorage.setItem('tmp', JSON.stringify(clientStorage)) sessionStorage.setItem('tmp', JSON.stringify(clientStorage))
} }
// Le loader sera masqué lors de la redirection
// Redirect vers intermédiaire // Redirect vers intermédiaire
window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=intermediaire`; window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=intermediaire`;
} else { } else {
console.log('Echec lors de la mise à jour de la relation id contrat - id client :', data); console.log('Echec lors de la mise à jour de la relation id contrat - id client :', data);
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la mise à jour du contrat.");
}
}
})
.catch(error => {
console.error("Erreur lors de la mise à jour du contrat:", error);
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la mise à jour. Vérifiez votre connexion.");
} }
}); });
} else {
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la mise à jour du client.");
}
}
}
} catch (error) {
console.error("Erreur lors de la soumission du formulaire client:", error);
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la soumission. Vérifiez votre connexion.");
} }
} }
} }

View File

@ -108,6 +108,12 @@ function isNullOrUndefined(value) {
// Fonction pour éviter la duplication du code fetch // Fonction pour éviter la duplication du code fetch
async function fetchWithJson(url, method, body = null) { async function fetchWithJson(url, method, body = null) {
// Activer le loader si disponible
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
const options = { const options = {
method: method, method: method,
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
@ -117,7 +123,25 @@ async function fetchWithJson(url, method, body = null) {
const response = await fetch(url, options); const response = await fetch(url, options);
if (!response.ok) throw new Error('Réseau ou erreur serveur'); if (!response.ok) throw new Error('Réseau ou erreur serveur');
return await response.json(); const result = await response.json();
// Désactiver le loader si disponible
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
return result;
} catch (error) {
// Désactiver le loader en cas d'erreur
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
// Afficher l'erreur si disponible
if (typeof window.showError === 'function') {
window.showError('Erreur lors de la communication avec le serveur. Vérifiez votre connexion.');
}
throw error;
}
} }
// Fonction de load du parcours en session storage // Fonction de load du parcours en session storage
@ -134,6 +158,7 @@ async function loadParcours(numParcours) {
} }
} catch (error) { } catch (error) {
console.error("Erreur lors de la récupération des informations parcours :", error); console.error("Erreur lors de la récupération des informations parcours :", error);
// Le loader est déjà géré dans fetchWithJson
} }
} }
@ -146,7 +171,7 @@ function toggler(btn, div) {
} }
} }
// Fonction de load du parcours en session storage // Fonction de load du contrat en session storage
async function loadContrat(idContrat) { async function loadContrat(idContrat) {
try { try {
const data = await fetchWithJson(`/contrat/read/id/${idContrat}`, 'GET'); const data = await fetchWithJson(`/contrat/read/id/${idContrat}`, 'GET');
@ -159,5 +184,6 @@ async function loadContrat(idContrat) {
} }
} catch (error) { } catch (error) {
console.error("Erreur lors de la récupération des informations contrat :", error); console.error("Erreur lors de la récupération des informations contrat :", error);
// Le loader est déjà géré dans fetchWithJson
} }
} }

View File

@ -29,11 +29,22 @@ document.addEventListener("DOMContentLoaded", async function () {
} }
try { try {
if (typeof window.showLoader === 'function') {
window.showLoader();
}
const userResponse = await fetchUserDetails(matriculeUser); const userResponse = await fetchUserDetails(matriculeUser);
regionUser = userResponse?.user["@expand"].region?.nom || null; regionUser = userResponse?.user["@expand"].region?.nom || null;
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
} catch (error) { } catch (error) {
displayError("Erreur lors de la récupération des données utilisateur."); displayError("Erreur lors de la récupération des données utilisateur.");
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la récupération des données utilisateur.");
}
return; return;
} }
@ -50,6 +61,9 @@ document.addEventListener("DOMContentLoaded", async function () {
// Fetch initial data // Fetch initial data
try { try {
if (typeof window.showLoader === 'function') {
window.showLoader();
}
const response = await fetch(`/historiqueParcours/${regionUser}`); const response = await fetch(`/historiqueParcours/${regionUser}`);
const dataResponse = await response.json(); const dataResponse = await response.json();
@ -58,9 +72,21 @@ document.addEventListener("DOMContentLoaded", async function () {
populateParcoursTable(tableData); populateParcoursTable(tableData);
} else { } else {
displayError("Erreur lors de la récupération des parcours"); displayError("Erreur lors de la récupération des parcours");
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la récupération des parcours");
}
}
if (typeof window.hideLoader === 'function') {
window.hideLoader();
} }
} catch (error) { } catch (error) {
displayError("Failed to fetch data. Please try again later."); displayError("Failed to fetch data. Please try again later.");
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors du chargement des données. Vérifiez votre connexion.");
}
} }
// Add event listeners to checkboxes // Add event listeners to checkboxes
@ -70,6 +96,9 @@ document.addEventListener("DOMContentLoaded", async function () {
if (checkbox.checked) { if (checkbox.checked) {
try { try {
if (typeof window.showLoader === 'function') {
window.showLoader();
}
const response = await fetch(`/historiqueParcours/${region}`); const response = await fetch(`/historiqueParcours/${region}`);
const dataResponse = await response.json(); const dataResponse = await response.json();
@ -78,9 +107,21 @@ document.addEventListener("DOMContentLoaded", async function () {
populateParcoursTable(tableData); populateParcoursTable(tableData);
} else { } else {
displayError("Erreur lors de la récupération des parcours"); displayError("Erreur lors de la récupération des parcours");
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la récupération des parcours");
}
}
if (typeof window.hideLoader === 'function') {
window.hideLoader();
} }
} catch (error) { } catch (error) {
displayError("Failed to fetch data. Please try again later."); displayError("Failed to fetch data. Please try again later.");
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors du chargement des données. Vérifiez votre connexion.");
}
} }
} else { } else {
removeRegionFromTableData(region); removeRegionFromTableData(region);
@ -104,6 +145,7 @@ const removeRegionFromTableData = (region) => {
async function fetchUserDetails(matriculeUser) { async function fetchUserDetails(matriculeUser) {
try { try {
// Le loader doit être géré par l'appelant si nécessaire
const response = await fetch(`/user/read/matricule/${matriculeUser}`); const response = await fetch(`/user/read/matricule/${matriculeUser}`);
const data = await response.json(); const data = await response.json();
@ -308,6 +350,9 @@ function downloadCSV(applyFilters) {
async function generateProject(numParcours, produit) { async function generateProject(numParcours, produit) {
try { try {
if (typeof window.showLoader === 'function') {
window.showLoader();
}
const response = await fetch(`/generate/${produit}/projet/${numParcours}`, { const response = await fetch(`/generate/${produit}/projet/${numParcours}`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json"}, headers: { "Content-Type": "application/json"},
@ -328,8 +373,18 @@ async function generateProject(numParcours, produit) {
a.click(); a.click();
window.URL.revokeObjectURL(url); window.URL.revokeObjectURL(url);
a.remove(); a.remove();
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
} catch (error) { } catch (error) {
console.error("Erreur lors de la génération du projet:", error); console.error("Erreur lors de la génération du projet:", error);
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError('Erreur lors de la génération du projet. Vérifiez votre connexion.');
}
} }
} }

View File

@ -4,14 +4,30 @@ document.addEventListener('DOMContentLoaded', function () {
const token = localStorage.getItem('jwtToken'); const token = localStorage.getItem('jwtToken');
if (token) { if (token) {
try {
const decoded = jwt_decode(token); const decoded = jwt_decode(token);
const userFirstName = decoded.userFirstName; const userFirstName = decoded?.userFirstName || '';
const userLastName = decoded.userLastName; const userLastName = decoded?.userLastName || '';
const userMatricule = decoded.userMatricule; const userMatricule = decoded?.userMatricule || '';
document.getElementById("firstNameItem").innerHTML = userFirstName; // Vérifier que les éléments HTML existent avant de les modifier
document.getElementById("lastNameItem").innerHTML = userLastName; const firstNameItem = document.getElementById("firstNameItem");
document.getElementById("userMatricule").innerHTML = userMatricule; const lastNameItem = document.getElementById("lastNameItem");
const userMatriculeItem = document.getElementById("userMatricule");
if (firstNameItem) {
firstNameItem.innerHTML = userFirstName;
}
if (lastNameItem) {
lastNameItem.innerHTML = userLastName;
}
if (userMatriculeItem) {
userMatriculeItem.innerHTML = userMatricule;
}
} catch (error) {
console.error("Erreur lors du décodage du token:", error);
// En cas d'erreur, ne pas afficher les informations utilisateur
}
} }
/* ---------- EVENNEMENT ------------ */ /* ---------- EVENNEMENT ------------ */
@ -30,10 +46,14 @@ document.addEventListener('DOMContentLoaded', function () {
if (data.valid) { if (data.valid) {
window.location.href = `/parcours?numParcours=${data.numParcours}`; window.location.href = `/parcours?numParcours=${data.numParcours}`;
} else { } else {
console.log("Erreur dans la création d'un nouveau parcours") console.log("Erreur dans la création d'un nouveau parcours");
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la création du parcours. Veuillez réessayer.");
}
} }
} catch (error) { } catch (error) {
console.error("Erreur serveur lors de la création d'un nouveau parcours :", error); console.error("Erreur serveur lors de la création d'un nouveau parcours :", error);
// L'erreur est déjà gérée par fetchWithJson avec le loader
} }
})(); })();
}); });
@ -50,6 +70,11 @@ document.addEventListener('DOMContentLoaded', function () {
const produit = document.getElementById('produit').innerHTML.replace(/\s/g, ''); const produit = document.getElementById('produit').innerHTML.replace(/\s/g, '');
let filename; let filename;
// Activer le loader
if (typeof window.showLoader === 'function') {
window.showLoader();
}
// Envoi de la requête POST au serveur pour générer le projet // Envoi de la requête POST au serveur pour générer le projet
fetch(`/generate/${produit}/projet/${numParcours}`, { fetch(`/generate/${produit}/projet/${numParcours}`, {
method: 'POST', method: 'POST',
@ -78,8 +103,22 @@ document.addEventListener('DOMContentLoaded', function () {
a.click(); // Simule un clic sur l'élément pour déclencher le téléchargement a.click(); // Simule un clic sur l'élément pour déclencher le téléchargement
window.URL.revokeObjectURL(url); // Nettoie l'URL objet window.URL.revokeObjectURL(url); // Nettoie l'URL objet
a.remove(); // Supprime l'élément a du document a.remove(); // Supprime l'élément a du document
// Désactiver le loader
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
}) })
.catch(error => console.error('Erreur lors de la génération du projet:', error)); .catch(error => {
console.error('Erreur lors de la génération du projet:', error);
// Désactiver le loader et afficher l'erreur
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError('Erreur lors de la génération du projet. Vérifiez votre connexion.');
}
});
}); });
// Écoute de l'événement de soumission du formulaire // Écoute de l'événement de soumission du formulaire
@ -95,6 +134,7 @@ document.addEventListener('DOMContentLoaded', function () {
// Envoi de la requête pour avoir le parcours // Envoi de la requête pour avoir le parcours
(async () => { (async () => {
try { try {
// Le loader est déjà géré dans loadParcours via fetchWithJson
await loadParcours(numParcours); await loadParcours(numParcours);
// Accéder aux informations stockées du parcours // Accéder aux informations stockées du parcours

View File

@ -176,6 +176,12 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
async function handleModalExtract() { async function handleModalExtract() {
document.getElementById('modalExtraireIntermediaire').disabled = true; document.getElementById('modalExtraireIntermediaire').disabled = true;
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
const response = await fetch(`/client/extract`, { const response = await fetch(`/client/extract`, {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
@ -215,6 +221,20 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
document.getElementById("error-extract").style.display = "block"; document.getElementById("error-extract").style.display = "block";
document.getElementById('modalExtraireIntermediaire').disabled = false; document.getElementById('modalExtraireIntermediaire').disabled = false;
console.log("Problème rencontré lors de l'extraction cl063 AxA PAC :", res.error); console.log("Problème rencontré lors de l'extraction cl063 AxA PAC :", res.error);
if (typeof window.showError === 'function') {
window.showError("Erreur lors de l'extraction des données intermédiaire.");
}
}
} catch (error) {
console.error("Erreur lors de l'extraction intermédiaire:", error);
if (typeof window.showError === 'function') {
window.showError("Erreur lors de l'extraction. Vérifiez votre connexion.");
}
} finally {
document.getElementById('modalExtraireIntermediaire').disabled = false;
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
} }
} }
@ -222,6 +242,11 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
async function handleSubmitForm(event, redirection) { async function handleSubmitForm(event, redirection) {
event.preventDefault(); event.preventDefault();
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
let idIntermediaire = intermediaire?.id; let idIntermediaire = intermediaire?.id;
const numPortefeuille = document.getElementById('numPortefeuille').value; const numPortefeuille = document.getElementById('numPortefeuille').value;
let responseIntermediaire; let responseIntermediaire;
@ -320,8 +345,35 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
} else { } else {
console.log('Echec lors de la mise à jour de la relation id contrat - id client :', data); console.log('Echec lors de la mise à jour de la relation id contrat - id client :', data);
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la mise à jour du contrat.");
}
}
})
.catch(error => {
console.error("Erreur lors de la mise à jour du contrat:", error);
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la mise à jour. Vérifiez votre connexion.");
} }
}); });
} else {
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
}
} catch (error) {
console.error("Erreur lors de la soumission du formulaire intermédiaire:", error);
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
if (typeof window.showError === 'function') {
window.showError("Erreur lors de la soumission. Vérifiez votre connexion.");
} }
} }
} }

View File

@ -3,21 +3,40 @@ document.addEventListener("DOMContentLoaded", () => {
const errorMessage = document.getElementById("error-message"); const errorMessage = document.getElementById("error-message");
let activateTimeout = null; let activateTimeout = null;
let timeoutError = null;
// Le loader est le premier élément dans le HTML, donc il est chargé en premier
// Il est prêt à s'afficher immédiatement dès que showLoader() est appelé
// Pas de classe "hidden" par défaut = il est dans le DOM et prêt instantanément
//activer le loader et le montrer a l'écran //activer le loader et le montrer a l'écran
window.showLoader = function() { window.showLoader = function() {
clearTimeout(activateTimeout); clearTimeout(activateTimeout);
clearTimeout(timeoutError);
errorMessage.style.display = "none"; errorMessage.style.display = "none";
loader.classList.remove("hidden"); loader.classList.remove("hidden");
// Délai avant l'affichage : permet d'éviter le flash du loader sur les chargements rapides
// Si hideLoader() est appelé avant ce délai, l'utilisateur ne verra jamais le loader
activateTimeout = setTimeout(() => { activateTimeout = setTimeout(() => {
// Vérifier qu'on est toujours pas caché (au cas où hideLoader() ait été appelé entre temps)
if (!loader.classList.contains("hidden")) {
loader.classList.add("active"); loader.classList.add("active");
}
}, 500); }, 500);
// Afficher un message d'erreur après 5 secondes si le loader est toujours actif
timeoutError = setTimeout(() => {
if (loader.classList.contains("active") && !loader.classList.contains("hidden")) {
showError("Connexion lente ou problème de réseau. Veuillez vérifier votre connexion.");
}
}, 5000);
}; };
//enlever le loader et le faire disparaitre //enlever le loader et le faire disparaitre
window.hideLoader = function() { window.hideLoader = function() {
clearTimeout(activateTimeout); clearTimeout(activateTimeout);
clearTimeout(timeoutError);
loader.classList.remove("active"); loader.classList.remove("active");
setTimeout(() => loader.classList.add("hidden"), 500); setTimeout(() => loader.classList.add("hidden"), 500);
}; };
@ -25,6 +44,7 @@ document.addEventListener("DOMContentLoaded", () => {
//cas d'erreur //cas d'erreur
window.showError = function(msg) { window.showError = function(msg) {
clearTimeout(activateTimeout); clearTimeout(activateTimeout);
clearTimeout(timeoutError);
errorMessage.textContent = msg; errorMessage.textContent = msg;
errorMessage.style.display = "block"; errorMessage.style.display = "block";
}; };

View File

@ -122,7 +122,13 @@ document.addEventListener('DOMContentLoaded', function() {
}) })
hideLoader(); hideLoader();
}) })
.catch(error => console.error('Error:', error)); .catch(error => {
console.error('Error:', error);
hideLoader();
if (typeof window.showError === 'function') {
window.showError("Erreur lors du chargement du formulaire. Vérifiez votre connexion.");
}
});
//A MODIFIER UNE FOIS QUE RC SERA ADAPTé AU PARCOURS //A MODIFIER UNE FOIS QUE RC SERA ADAPTé AU PARCOURS
if (produit == "RC") { if (produit == "RC") {

View File

@ -32,8 +32,8 @@
<body> <body>
<main> <main>
<!-- Loader --> <!-- Loader - Premier élément chargé pour affichage immédiat -->
<div id="loader-overlay" class="hidden"> <div id="loader-overlay">
<div class="loader-spin-wrap"> <div class="loader-spin-wrap">
<div class="loader-spin"></div> <div class="loader-spin"></div>
</div> </div>

0
test
View File