"use strict"; /* * ========================================================= * CONFIGURATION * ========================================================= */ const API_URL = "../php/api_list_full_table_indice.php"; /* * API de création. * * A créer côté PHP. */ const API_CREATE_URL = "../php/api_create_indice.php"; const tableauIndices = document.getElementById("tableauIndices"); const compteur = document.getElementById("compteur"); const message = document.getElementById("message"); const btnActualiser = document.getElementById("btnActualiser"); const btnNouveau = document.getElementById("btnNouveau"); const filtreIndice = document.getElementById("filtreIndice"); /* * ========================================================= * MODAL * ========================================================= */ const modalNouvelEnregistrement = document.getElementById( "modalNouvelEnregistrement", ); const formNouvelEnregistrement = document.getElementById( "formNouvelEnregistrement", ); const btnFermerModal = document.getElementById("btnFermerModal"); const btnAnnuler = document.getElementById("btnAnnuler"); const btnSauvegarder = document.getElementById("btnSauvegarder"); const messageNouveau = document.getElementById("messageNouveau"); /* * ========================================================= * CHAMPS FORMULAIRE * ========================================================= */ const nouvelIndice = document.getElementById("nouvelIndice"); const nouveauNom = document.getElementById("nouveauNom"); const nouvelIsin = document.getElementById("nouvelIsin"); const nouveauSymbole = document.getElementById("nouveauSymbole"); const nouvelActif = document.getElementById("nouvelActif"); const nouvelAfficher = document.getElementById("nouvelAfficher"); /* * ========================================================= * DONNEES * ========================================================= */ let tousLesEnregistrements = []; /* * ========================================================= * AFFICHER MESSAGE * ========================================================= */ function afficherMessage(texte, type = "info") { message.textContent = texte; message.classList.remove( "hidden", "bg-emerald-900/50", "border-emerald-700", "text-emerald-300", "bg-rose-900/50", "border-rose-700", "text-rose-300", "bg-slate-900", "border-slate-700", "text-slate-300", ); message.classList.add("border"); if (type === "success") { message.classList.add( "bg-emerald-900/50", "border-emerald-700", "text-emerald-300", ); } else if (type === "error") { message.classList.add("bg-rose-900/50", "border-rose-700", "text-rose-300"); } else { message.classList.add("bg-slate-900", "border-slate-700", "text-slate-300"); } } /* * ========================================================= * CACHER MESSAGE * ========================================================= */ function cacherMessage() { message.classList.add("hidden"); } /* * ========================================================= * ECHAPPER HTML * ========================================================= */ function echapperHTML(valeur) { if (valeur === null || valeur === undefined) { return ""; } return String(valeur) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } /* * ========================================================= * CHECKBOX * ========================================================= */ function creerCheckbox(valeur) { const checked = Number(valeur) === 1 || valeur === true || valeur === "1"; return `
`; } /* * ========================================================= * CREER UNE LIGNE * ========================================================= */ function creerLigne(enregistrement) { return ` ${echapperHTML(enregistrement.id)} ${echapperHTML(enregistrement.indice)} ${echapperHTML(enregistrement.nom)} ${echapperHTML(enregistrement.isin)} ${echapperHTML(enregistrement.symbole)} ${creerCheckbox(enregistrement.actif)} ${creerCheckbox(enregistrement.afficher)} ${echapperHTML(enregistrement.updated_at)} ${echapperHTML(enregistrement.created_at)} `; } /* * ========================================================= * CONSTRUIRE FILTRES * ========================================================= */ function construireFiltres() { const indices = [ ...new Set( tousLesEnregistrements .map(function (enregistrement) { return enregistrement.indice; }) .filter(function (indice) { return ( indice !== null && indice !== undefined && String(indice).trim() !== "" ); }), ), ]; indices.sort(function (a, b) { return String(a).localeCompare(String(b), "fr", { sensitivity: "base", }); }); const filtreActuel = filtreIndice.value; filtreIndice.innerHTML = ""; /* * Tout */ const optionTout = document.createElement("option"); optionTout.value = "tout"; optionTout.textContent = "Tout"; filtreIndice.appendChild(optionTout); /* * Afficher */ const optionAfficher = document.createElement("option"); optionAfficher.value = "afficher"; optionAfficher.textContent = "Afficher"; filtreIndice.appendChild(optionAfficher); /* * Inactif */ const optionInactif = document.createElement("option"); optionInactif.value = "inactif"; optionInactif.textContent = "Inactif"; filtreIndice.appendChild(optionInactif); /* * Indices */ indices.forEach(function (indice) { const option = document.createElement("option"); option.value = "indice:" + indice; option.textContent = indice; filtreIndice.appendChild(option); }); /* * Restaurer filtre */ const optionExiste = Array.from(filtreIndice.options).some(function (option) { return option.value === filtreActuel; }); if (optionExiste) { filtreIndice.value = filtreActuel; } else { filtreIndice.value = "tout"; } } /* * ========================================================= * APPLIQUER FILTRE * ========================================================= */ function appliquerFiltre() { const filtre = filtreIndice.value; let enregistrementsFiltres; /* * Tout */ if (filtre === "tout") { enregistrementsFiltres = tousLesEnregistrements; } else if (filtre === "afficher") { /* * Afficher */ enregistrementsFiltres = tousLesEnregistrements.filter( function (enregistrement) { return ( Number(enregistrement.afficher) === 1 || enregistrement.afficher === true || enregistrement.afficher === "1" ); }, ); } else if (filtre === "inactif") { /* * Inactif */ enregistrementsFiltres = tousLesEnregistrements.filter( function (enregistrement) { return !( Number(enregistrement.actif) === 1 || enregistrement.actif === true || enregistrement.actif === "1" ); }, ); } else if (filtre.startsWith("indice:")) { /* * Indice */ const indiceRecherche = filtre.substring("indice:".length); enregistrementsFiltres = tousLesEnregistrements.filter( function (enregistrement) { return ( String(enregistrement.indice).toLowerCase() === String(indiceRecherche).toLowerCase() ); }, ); } else { enregistrementsFiltres = tousLesEnregistrements; } afficherDonneesFiltrees(enregistrementsFiltres); } /* * ========================================================= * AFFICHER DONNEES FILTREES * ========================================================= */ function afficherDonneesFiltrees(enregistrements) { tableauIndices.innerHTML = ""; if (!Array.isArray(enregistrements) || enregistrements.length === 0) { compteur.textContent = "0 enregistrement"; tableauIndices.innerHTML = ` Aucun enregistrement correspondant au filtre sélectionné. `; return; } /* * ======================================================= * TRI PAR ID CROISSANT * ======================================================= */ const donneesTriees = [...enregistrements].sort(function (a, b) { return Number(a.id) - Number(b.id); }); let html = ""; donneesTriees.forEach(function (enregistrement) { html += creerLigne(enregistrement); }); tableauIndices.innerHTML = html; compteur.textContent = donneesTriees.length + (donneesTriees.length > 1 ? " enregistrements" : " enregistrement"); } /* * ========================================================= * AFFICHER DONNEES * ========================================================= */ function afficherDonnees(data) { tousLesEnregistrements = Array.isArray(data) ? data : []; construireFiltres(); appliquerFiltre(); } /* * ========================================================= * CHARGER DONNEES * ========================================================= */ async function chargerDonnees() { btnActualiser.disabled = true; btnActualiser.textContent = "↻ Chargement..."; afficherMessage("Chargement des indices et des actions...", "info"); try { const response = await fetch(API_URL, { method: "GET", credentials: "same-origin", cache: "no-store", headers: { Accept: "application/json", }, }); if (!response.ok) { throw new Error("Erreur HTTP " + response.status); } const result = await response.json(); if (!result || result.status !== "success") { throw new Error( result && result.message ? result.message : "L'API a retourné une erreur.", ); } afficherDonnees(result.data); cacherMessage(); } catch (error) { console.error("Erreur chargement indices/actions :", error); tableauIndices.innerHTML = ` Impossible de charger les données. `; compteur.textContent = "Erreur de chargement"; afficherMessage( "Erreur lors de la récupération des données : " + error.message, "error", ); } finally { btnActualiser.disabled = false; btnActualiser.textContent = "↻ Actualiser"; } } /* * ========================================================= * OUVRIR MODAL * ========================================================= */ function ouvrirModal() { formNouvelEnregistrement.reset(); /* * Valeurs par défaut */ nouvelActif.checked = true; nouvelAfficher.checked = true; messageNouveau.classList.add("hidden"); modalNouvelEnregistrement.classList.remove("hidden"); modalNouvelEnregistrement.classList.add("flex"); setTimeout(function () { nouvelIndice.focus(); }, 50); } /* * ========================================================= * FERMER MODAL * ========================================================= */ function fermerModal() { modalNouvelEnregistrement.classList.add("hidden"); modalNouvelEnregistrement.classList.remove("flex"); } /* * ========================================================= * MESSAGE MODAL * ========================================================= */ function afficherMessageNouveau(texte, type = "error") { messageNouveau.textContent = texte; messageNouveau.classList.remove( "hidden", "bg-rose-900/50", "border-rose-700", "text-rose-300", "bg-emerald-900/50", "border-emerald-700", "text-emerald-300", ); messageNouveau.classList.add("border"); if (type === "success") { messageNouveau.classList.add( "bg-emerald-900/50", "border-emerald-700", "text-emerald-300", ); } else { messageNouveau.classList.add( "bg-rose-900/50", "border-rose-700", "text-rose-300", ); } } /* * ========================================================= * SAUVEGARDER NOUVEL ENREGISTREMENT * ========================================================= */ async function sauvegarderNouvelEnregistrement(event) { event.preventDefault(); /* * Lecture des champs */ const donnees = { indice: nouvelIndice.value.trim(), nom: nouveauNom.value.trim(), isin: nouvelIsin.value.trim().toUpperCase(), symbole: nouveauSymbole.value.trim().toUpperCase(), actif: nouvelActif.checked ? 1 : 0, afficher: nouvelAfficher.checked ? 1 : 0, }; /* * Vérification */ if (!donnees.indice || !donnees.nom || !donnees.isin || !donnees.symbole) { afficherMessageNouveau("Tous les champs texte sont obligatoires."); return; } /* * Désactivation bouton */ btnSauvegarder.disabled = true; btnSauvegarder.textContent = "Sauvegarde..."; messageNouveau.classList.add("hidden"); try { const response = await fetch(API_CREATE_URL, { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(donnees), }); if (!response.ok) { throw new Error("Erreur HTTP " + response.status); } const result = await response.json(); if (!result || result.status !== "success") { throw new Error( result && result.message ? result.message : "Impossible de créer l'enregistrement.", ); } /* * Fermeture */ fermerModal(); /* * Message */ afficherMessage("L'enregistrement a été créé avec succès.", "success"); /* * Rechargement */ await chargerDonnees(); } catch (error) { console.error("Erreur création enregistrement :", error); afficherMessageNouveau(error.message, "error"); } finally { btnSauvegarder.disabled = false; btnSauvegarder.textContent = "Sauvegarder"; } } /* * ========================================================= * EVENEMENTS * ========================================================= */ filtreIndice.addEventListener("change", function () { appliquerFiltre(); }); btnActualiser.addEventListener("click", function () { chargerDonnees(); }); btnNouveau.addEventListener("click", function () { ouvrirModal(); }); btnFermerModal.addEventListener("click", function () { fermerModal(); }); btnAnnuler.addEventListener("click", function () { fermerModal(); }); formNouvelEnregistrement.addEventListener( "submit", sauvegarderNouvelEnregistrement, ); /* * Fermer en cliquant sur le fond */ modalNouvelEnregistrement.addEventListener("click", function (event) { if (event.target === modalNouvelEnregistrement) { fermerModal(); } }); /* * Touche Echap */ document.addEventListener("keydown", function (event) { if ( event.key === "Escape" && !modalNouvelEnregistrement.classList.contains("hidden") ) { fermerModal(); } }); /* * ========================================================= * INITIALISATION * ========================================================= */ document.addEventListener("DOMContentLoaded", function () { chargerDonnees(); });