From 9a8891fc9d9938ccb3295f85271cf6327baabcb6 Mon Sep 17 00:00:00 2001 From: RoxanaElena09 Date: Wed, 10 Dec 2025 09:44:44 +0100 Subject: [PATCH] feat:avant apres+media queries+modale de suppression --- prestations/html/ajouter_avant_apres.html | 138 +++++++++++---------- prestations/html/liste_avant_apres.html | 118 +++++++++++------- prestations/html/modifier_avant_apres.html | 88 ++++++------- prestations/html/voir_avant_apres.html | 32 ++--- prestations/js/ajouter_avant_apres.js | 87 +++++++++++-- prestations/js/liste_avant_apres.js | 67 +++++++--- prestations/js/modifier_avant_apres.js | 54 ++++++-- 7 files changed, 365 insertions(+), 219 deletions(-) diff --git a/prestations/html/ajouter_avant_apres.html b/prestations/html/ajouter_avant_apres.html index 2b9f499..ce24bf2 100644 --- a/prestations/html/ajouter_avant_apres.html +++ b/prestations/html/ajouter_avant_apres.html @@ -1,5 +1,6 @@ + @@ -8,14 +9,6 @@ - -
+ -

Ajouter une paire avant/après

+
- -
- Nouvelle paire ajoutée avec succès ! +

Ajouter une paire avant/après

+ + +
+ Nouvelle paire ajoutée avec succès ! +
+ + +
+ Merci de remplir tous les champs obligatoires. +
+ + +
+ Format d'image invalide. Formats acceptés : JPG, PNG, WEBP. +
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + + image avant +
+ + +
+ + + + image après +
+ + +
+ +
+ +
+
+ +
- -
- Merci de remplir tous les champs obligatoires. -
- -
- - -
- - -
- - -
- - -
- - -
- - - - -
- - -
- - - - -
- - -
- Annuler - -
- -
-
- - - + + + + diff --git a/prestations/html/liste_avant_apres.html b/prestations/html/liste_avant_apres.html index 15c898f..fbec2de 100644 --- a/prestations/html/liste_avant_apres.html +++ b/prestations/html/liste_avant_apres.html @@ -1,60 +1,84 @@ + - - - Liste des paires avant/apres - - - - + + + Liste des paires avant/après + - - -
-

Liste des paires avant/apres

- - -
Paire supprimée avec succès !
- - + - - - - - - - - - - - - - - -
Titre paireTypeAvantApresActions
+
+

Liste des paires avant/après

+ + +
+ Paire supprimée avec succès !
- + + + +
+ + + + + + + + + + + + + +
Titre paireTypeAvantAprèsActions
+
+
+ + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/prestations/html/modifier_avant_apres.html b/prestations/html/modifier_avant_apres.html index 37d5959..8b90c0d 100644 --- a/prestations/html/modifier_avant_apres.html +++ b/prestations/html/modifier_avant_apres.html @@ -1,5 +1,6 @@ + @@ -7,24 +8,17 @@ - -
-

Modifier une paire avant/après

+ + +
+

Modifier une paire avant/après

@@ -34,71 +28,71 @@ Une erreur est survenue. Merci de vérifier le formulaire.
+ +
+ Format d'image invalide. Formats acceptés : JPG, PNG, WEBP. +
+ -
+
- +
- - + -
- -
-
- - -
- Laisser vide pour conserver l'image actuelle. -
+ +
+ +
+ + + + Aperçu avant
-
-

Aperçu actuel AVANT

- Image avant + + +
+ + + + Aperçu après
- -
-
- - -
- Laisser vide pour conserver l'image actuelle. -
+ +
+ -
-

Aperçu actuel APRÈS

- Image après +
+
- -
- - Annuler - - -
+ diff --git a/prestations/html/voir_avant_apres.html b/prestations/html/voir_avant_apres.html index a1e6f86..0189e2d 100644 --- a/prestations/html/voir_avant_apres.html +++ b/prestations/html/voir_avant_apres.html @@ -8,46 +8,39 @@ - + -
+
-

Détails de la paire avant/après

+

Détails de la paire avant/après

Impossible d'afficher cette paire.
-
+
- -

+

Chargement...

-
-
+ +
+ +

AVANT

- + Photo avant
-
+

APRÈS

- + Photo après
@@ -68,3 +61,4 @@ + diff --git a/prestations/js/ajouter_avant_apres.js b/prestations/js/ajouter_avant_apres.js index 440e9a7..4d184f2 100644 --- a/prestations/js/ajouter_avant_apres.js +++ b/prestations/js/ajouter_avant_apres.js @@ -30,13 +30,48 @@ const afterPreview = document.getElementById("afterPreview"); const successMsg = document.getElementById("successMsg"); const errorMsg = document.getElementById("errorMsg"); +const errorFormat = document.getElementById("errorFormat"); + +// Formats autorisés +const allowedTypes = ["image/jpeg", "image/png", "image/webp"]; // =============================== -// Prévisualisation images +// Fonctions utilitaires +// =============================== +function hideMessages() { + successMsg.classList.add("d-none"); + errorMsg.classList.add("d-none"); + errorFormat.classList.add("d-none"); +} + +function isValidFormat(file) { + if (!file) return false; + return allowedTypes.includes(file.type); +} + +// =============================== +// Prévisualisation image AVANT +// + contrôle du format // =============================== beforeInput.addEventListener("change", function () { + hideMessages(); + const file = this.files[0]; - if (!file) return; + + if (!file) { + beforePreview.style.display = "none"; + beforePreview.src = "#"; + return; + } + + // Vérif format + if (!isValidFormat(file)) { + errorFormat.classList.remove("d-none"); + this.value = ""; // reset le champ + beforePreview.style.display = "none"; + beforePreview.src = "#"; + return; + } const reader = new FileReader(); reader.onload = e => { @@ -46,9 +81,29 @@ beforeInput.addEventListener("change", function () { reader.readAsDataURL(file); }); +// =============================== +// Prévisualisation image APRÈS +// + contrôle du format +// =============================== afterInput.addEventListener("change", function () { + hideMessages(); + const file = this.files[0]; - if (!file) return; + + if (!file) { + afterPreview.style.display = "none"; + afterPreview.src = "#"; + return; + } + + // Vérif format + if (!isValidFormat(file)) { + errorFormat.classList.remove("d-none"); + this.value = ""; // reset le champ + afterPreview.style.display = "none"; + afterPreview.src = "#"; + return; + } const reader = new FileReader(); reader.onload = e => { @@ -64,23 +119,35 @@ afterInput.addEventListener("change", function () { form.addEventListener("submit", function (e) { e.preventDefault(); - // Reset messages - errorMsg.classList.add("d-none"); - successMsg.classList.add("d-none"); + hideMessages(); - // Validation simple - if (!titleInput.value.trim() || !typeInput.value.trim() || !beforeInput.files[0] || !afterInput.files[0]) { + // Champs obligatoires + if ( + !titleInput.value.trim() || + !typeInput.value.trim() || + !beforeInput.files[0] || + !afterInput.files[0] + ) { errorMsg.classList.remove("d-none"); return; } + const beforeFile = beforeInput.files[0]; + const afterFile = afterInput.files[0]; + + // Vérification format des deux images + if (!isValidFormat(beforeFile) || !isValidFormat(afterFile)) { + errorFormat.classList.remove("d-none"); + return; + } + // Nouvelle entrée (simulation) const newPair = { id: galleryPairs.length + 1, titre: titleInput.value.trim(), type: typeInput.value.trim(), - avant: URL.createObjectURL(beforeInput.files[0]), - apres: URL.createObjectURL(afterInput.files[0]) + avant: URL.createObjectURL(beforeFile), + apres: URL.createObjectURL(afterFile) }; galleryPairs.push(newPair); diff --git a/prestations/js/liste_avant_apres.js b/prestations/js/liste_avant_apres.js index 64c5fc9..b1eaaec 100644 --- a/prestations/js/liste_avant_apres.js +++ b/prestations/js/liste_avant_apres.js @@ -22,6 +22,14 @@ let galleryPairs = [ const tableBody = document.getElementById("prestationTableBody"); const succesDeleteMsg = document.getElementById("succesDeleteMsg"); +// Modal & bouton de confirmation +const deleteModalEl = document.getElementById("deleteModal"); +const confirmDeleteBtn = document.getElementById("confirmDeleteBtn"); +const deleteModal = new bootstrap.Modal(deleteModalEl); + +// ID de la paire en attente de suppression +let pairIdToDelete = null; + // =============================== // Fonction d'affichage // =============================== @@ -36,27 +44,33 @@ function displayPairs() { ${pair.type} - + - + - + +
- - Voir + + + Voir + - - Modifier + + + Modifier + - - + + +
`; @@ -65,26 +79,39 @@ function displayPairs() { } // =============================== -// Fonction de suppression +// Ouvrir le modal de suppression +// =============================== +function openDeleteModal(id) { + pairIdToDelete = id; // on mémorise l'id + deleteModal.show(); // on ouvre le modal +} + +// =============================== +// Fonction de suppression réelle // =============================== function deletePair(id) { - if (!confirm("Voulez-vous vraiment supprimer cette paire ?")) { - return; - } - galleryPairs = galleryPairs.filter(pair => pair.id !== id); displayPairs(); succesDeleteMsg.classList.remove("d-none"); - // Disparaît après 2 secondes setTimeout(() => { succesDeleteMsg.classList.add("d-none"); }, 2000); } +// =============================== +// Clic sur "Supprimer" dans le modal +// =============================== +confirmDeleteBtn.addEventListener("click", () => { + if (pairIdToDelete !== null) { + deletePair(pairIdToDelete); + pairIdToDelete = null; + } + deleteModal.hide(); +}); + // =============================== // Chargement initial // =============================== displayPairs(); - diff --git a/prestations/js/modifier_avant_apres.js b/prestations/js/modifier_avant_apres.js index fae9bde..5111af8 100644 --- a/prestations/js/modifier_avant_apres.js +++ b/prestations/js/modifier_avant_apres.js @@ -19,6 +19,11 @@ const galleryPairs = [ } ]; +// =============================== +// Formats d'images autorisés +// =============================== +const allowedTypes = ["image/jpeg", "image/png", "image/webp"]; + // Sélecteurs const editForm = document.getElementById("editPairForm"); const pairIdInput = document.getElementById("pairId"); @@ -31,6 +36,7 @@ const afterPreview = document.getElementById("afterPreview"); const successMsg = document.getElementById("successMsg"); const errorMsg = document.getElementById("errorMsg"); +const errorFormat = document.getElementById("errorFormat"); // =============================== // Récup ID dans l'URL @@ -71,23 +77,39 @@ function loadPairData() { afterPreview.src = pair.apres; } -// Prévisu des nouvelles images -beforeInput.addEventListener("change", function () { - const file = this.files[0]; +// =============================== +// Gestion du changement d'image +// =============================== +function handleImageChange(inputEl, previewEl) { + const file = inputEl.files[0]; if (!file) return; + // Vérification format + if (!allowedTypes.includes(file.type)) { + // Format non autorisé + errorFormat.classList.remove("d-none"); + inputEl.value = ""; // reset du champ + previewEl.src = ""; // reset de la prévisu + return; + } + + // Format OK → on cache le message d'erreur + errorFormat.classList.add("d-none"); + const reader = new FileReader(); - reader.onload = e => beforePreview.src = e.target.result; + reader.onload = e => { + previewEl.src = e.target.result; + }; reader.readAsDataURL(file); +} + +// Prévisu des nouvelles images + contrôle format +beforeInput.addEventListener("change", function () { + handleImageChange(beforeInput, beforePreview); }); afterInput.addEventListener("change", function () { - const file = this.files[0]; - if (!file) return; - - const reader = new FileReader(); - reader.onload = e => afterPreview.src = e.target.result; - reader.readAsDataURL(file); + handleImageChange(afterInput, afterPreview); }); // Soumission @@ -96,6 +118,7 @@ editForm.addEventListener("submit", function (e) { errorMsg.classList.add("d-none"); successMsg.classList.add("d-none"); + errorFormat.classList.add("d-none"); if (!titleInput.value.trim()) { errorMsg.textContent = "Le titre est obligatoire."; @@ -103,7 +126,16 @@ editForm.addEventListener("submit", function (e) { return; } - // Ici ce serait un fetch vers l'API en vrai. + // Double check format côté submit (au cas où) + const filesToCheck = [beforeInput.files[0], afterInput.files[0]]; + for (const file of filesToCheck) { + if (!file || !allowedTypes.includes(file.type)) { + errorFormat.classList.remove("d-none"); + return; + } + } + + successMsg.classList.remove("d-none"); setTimeout(() => {