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
(async () => {
try {
// Le loader est déjà géré dans fetchWithJson
const data = await fetchWithJson(`/auth/verifyMatricule/${matricule}`, 'GET');
if (data.valid) {

View File

@ -141,6 +141,11 @@
async function handleModalExtract() {
document.getElementById('modalExtraireClient').disabled = true;
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
const response = await fetch(`/client/extract`, {
method: 'POST',
body: JSON.stringify({
@ -183,6 +188,20 @@
document.getElementById("error-extract").style.display = "block";
document.getElementById('modalExtraireClient').disabled = false;
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) {
event.preventDefault();
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
let idClient = client?.id;
const numClient = document.getElementById('numClient').value;
@ -264,12 +288,44 @@
sessionStorage.setItem('tmp', JSON.stringify(clientStorage))
}
// Le loader sera masqué lors de la redirection
// Redirect vers intermédiaire
window.location.href = `/navParcours?numParcours=${getNumParcoursFromURL()}&submenu=intermediaire`;
} else {
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
async function fetchWithJson(url, method, body = null) {
// Activer le loader si disponible
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
const options = {
method: method,
headers: { 'Content-Type': 'application/json' },
@ -117,7 +123,25 @@ async function fetchWithJson(url, method, body = null) {
const response = await fetch(url, options);
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
@ -134,6 +158,7 @@ async function loadParcours(numParcours) {
}
} catch (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) {
try {
const data = await fetchWithJson(`/contrat/read/id/${idContrat}`, 'GET');
@ -159,5 +184,6 @@ async function loadContrat(idContrat) {
}
} catch (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 {
if (typeof window.showLoader === 'function') {
window.showLoader();
}
const userResponse = await fetchUserDetails(matriculeUser);
regionUser = userResponse?.user["@expand"].region?.nom || null;
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
} catch (error) {
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;
}
@ -50,6 +61,9 @@ document.addEventListener("DOMContentLoaded", async function () {
// Fetch initial data
try {
if (typeof window.showLoader === 'function') {
window.showLoader();
}
const response = await fetch(`/historiqueParcours/${regionUser}`);
const dataResponse = await response.json();
@ -58,9 +72,21 @@ document.addEventListener("DOMContentLoaded", async function () {
populateParcoursTable(tableData);
} else {
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) {
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
@ -70,6 +96,9 @@ document.addEventListener("DOMContentLoaded", async function () {
if (checkbox.checked) {
try {
if (typeof window.showLoader === 'function') {
window.showLoader();
}
const response = await fetch(`/historiqueParcours/${region}`);
const dataResponse = await response.json();
@ -78,9 +107,21 @@ document.addEventListener("DOMContentLoaded", async function () {
populateParcoursTable(tableData);
} else {
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) {
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 {
removeRegionFromTableData(region);
@ -104,6 +145,7 @@ const removeRegionFromTableData = (region) => {
async function fetchUserDetails(matriculeUser) {
try {
// Le loader doit être géré par l'appelant si nécessaire
const response = await fetch(`/user/read/matricule/${matriculeUser}`);
const data = await response.json();
@ -308,6 +350,9 @@ function downloadCSV(applyFilters) {
async function generateProject(numParcours, produit) {
try {
if (typeof window.showLoader === 'function') {
window.showLoader();
}
const response = await fetch(`/generate/${produit}/projet/${numParcours}`, {
method: "POST",
headers: { "Content-Type": "application/json"},
@ -328,8 +373,18 @@ async function generateProject(numParcours, produit) {
a.click();
window.URL.revokeObjectURL(url);
a.remove();
if (typeof window.hideLoader === 'function') {
window.hideLoader();
}
} catch (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');
if (token) {
try {
const decoded = jwt_decode(token);
const userFirstName = decoded.userFirstName;
const userLastName = decoded.userLastName;
const userMatricule = decoded.userMatricule;
const userFirstName = decoded?.userFirstName || '';
const userLastName = decoded?.userLastName || '';
const userMatricule = decoded?.userMatricule || '';
document.getElementById("firstNameItem").innerHTML = userFirstName;
document.getElementById("lastNameItem").innerHTML = userLastName;
document.getElementById("userMatricule").innerHTML = userMatricule;
// Vérifier que les éléments HTML existent avant de les modifier
const firstNameItem = document.getElementById("firstNameItem");
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 ------------ */
@ -30,10 +46,14 @@ document.addEventListener('DOMContentLoaded', function () {
if (data.valid) {
window.location.href = `/parcours?numParcours=${data.numParcours}`;
} 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) {
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, '');
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
fetch(`/generate/${produit}/projet/${numParcours}`, {
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
window.URL.revokeObjectURL(url); // Nettoie l'URL objet
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
@ -95,6 +134,7 @@ document.addEventListener('DOMContentLoaded', function () {
// Envoi de la requête pour avoir le parcours
(async () => {
try {
// Le loader est déjà géré dans loadParcours via fetchWithJson
await loadParcours(numParcours);
// 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() {
document.getElementById('modalExtraireIntermediaire').disabled = true;
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
const response = await fetch(`/client/extract`, {
method: 'POST',
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('modalExtraireIntermediaire').disabled = false;
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) {
event.preventDefault();
if (typeof window.showLoader === 'function') {
window.showLoader();
}
try {
let idIntermediaire = intermediaire?.id;
const numPortefeuille = document.getElementById('numPortefeuille').value;
let responseIntermediaire;
@ -320,8 +345,35 @@ window.initSubmenuForm = initSubmenuForm;// Module IIFE pour éviter la pollutio
} else {
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");
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
window.showLoader = function() {
clearTimeout(activateTimeout);
clearTimeout(timeoutError);
errorMessage.style.display = "none";
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(() => {
// 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");
}
}, 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
window.hideLoader = function() {
clearTimeout(activateTimeout);
clearTimeout(timeoutError);
loader.classList.remove("active");
setTimeout(() => loader.classList.add("hidden"), 500);
};
@ -25,6 +44,7 @@ document.addEventListener("DOMContentLoaded", () => {
//cas d'erreur
window.showError = function(msg) {
clearTimeout(activateTimeout);
clearTimeout(timeoutError);
errorMessage.textContent = msg;
errorMessage.style.display = "block";
};

View File

@ -122,7 +122,13 @@ document.addEventListener('DOMContentLoaded', function() {
})
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
if (produit == "RC") {

View File

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

0
test
View File