From 43c625c3ecf32ab768c4e7404243dba0203c94ab Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 22 Feb 2026 14:43:48 +0100 Subject: [PATCH] feat: Introduce SnapshotList component for managing user snapshots and exports, leveraging a new ConfirmModal. --- .../shared/change-password-modal.tsx | 2 +- src/components/shared/confirm-modal.tsx | 128 ++++++++++++++++++ src/components/shared/success-modal.tsx | 55 +++----- .../snapshots/components/snapshot-list.tsx | 99 ++++++++------ 4 files changed, 206 insertions(+), 78 deletions(-) create mode 100644 src/components/shared/confirm-modal.tsx diff --git a/src/components/shared/change-password-modal.tsx b/src/components/shared/change-password-modal.tsx index d71defe..2949065 100644 --- a/src/components/shared/change-password-modal.tsx +++ b/src/components/shared/change-password-modal.tsx @@ -90,7 +90,7 @@ export function ChangePasswordModal({ style={{ background: "var(--bg-surface)", border: "1px solid var(--border)" }} > {/* Accent bar */} -
+
{/* Close button */} + +
+ {/* Icon + Title */} +
+
+ +
+

{title}

+
+ + {/* Message */} +

+ {message} +

+ + {/* Actions */} +
+ + +
+
+
+
+ ); +} diff --git a/src/components/shared/success-modal.tsx b/src/components/shared/success-modal.tsx index b340792..c30ef8b 100644 --- a/src/components/shared/success-modal.tsx +++ b/src/components/shared/success-modal.tsx @@ -2,12 +2,6 @@ import React, { useEffect, useState } from "react"; import { CheckCircle2, X } from "lucide-react"; -import { clsx, type ClassValue } from "clsx"; -import { twMerge } from "tailwind-merge"; - -function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} interface SuccessModalProps { isOpen: boolean; @@ -29,77 +23,66 @@ export function SuccessModal({ useEffect(() => { if (isOpen) { setIsVisible(true); - const timer = setTimeout(() => { - handleClose(); - }, duration); + const timer = setTimeout(() => handleClose(), duration); return () => clearTimeout(timer); } }, [isOpen, duration]); const handleClose = () => { setIsVisible(false); - setTimeout(onClose, 300); // Wait for fade out animation + setTimeout(onClose, 250); }; if (!isOpen && !isVisible) return null; return (
+ {/* Backdrop */}
+ {/* Panel */}
-
+ {/* Accent bar */} +
+ {/* Close button */}
-
- + {/* Icon */} +
+
-

+

{title}

-

+

{message}

- -
); } diff --git a/src/features/snapshots/components/snapshot-list.tsx b/src/features/snapshots/components/snapshot-list.tsx index b204430..8281ee3 100644 --- a/src/features/snapshots/components/snapshot-list.tsx +++ b/src/features/snapshots/components/snapshot-list.tsx @@ -15,6 +15,7 @@ import { Loader2, } from "lucide-react"; import { SuccessModal } from "@/components/shared/success-modal"; +import { ConfirmModal } from "@/components/shared/confirm-modal"; const formatDate = (date: Date) => { return new Intl.DateTimeFormat("fr-FR", { @@ -41,6 +42,14 @@ export function SnapshotList({ type }: SnapshotListProps) { message: "" }); + const [confirmModal, setConfirmModal] = useState<{ + isOpen: boolean; + title: string; + message: string; + variant?: "danger" | "default"; + onConfirm: () => void; + }>({ isOpen: false, title: "", message: "", onConfirm: () => { } }); + const restoreSnapshot = useGridStore(state => state.restoreSnapshot); const router = useRouter(); @@ -60,51 +69,49 @@ export function SnapshotList({ type }: SnapshotListProps) { fetchSnapshots(); }, [type]); - const handleDelete = async (id: number) => { - if (!window.confirm(`Supprimer cet ${type === 'export' ? 'export' : 'snapshot'} définitivement ?`)) return; - setIsDeleting(id); - try { - const res = await deleteSnapshot(id); - if (res.success) { - setSnapshots(prev => prev.filter(s => s.id !== id)); - setModal({ - isOpen: true, - title: "Action Réussie", - message: "L'élément a été supprimé de votre historique." - }); - } else { - setModal({ - isOpen: true, - title: "Erreur", - message: "Impossible de supprimer l'élément." - }); - } - } catch (err) { - setModal({ - isOpen: true, - title: "Erreur Technique", - message: "Une erreur est survenue lors de la suppression." - }); - } finally { - setIsDeleting(null); - } + const handleDelete = (id: number) => { + setConfirmModal({ + isOpen: true, + title: "Supprimer", + message: `Supprimer cet ${type === 'export' ? 'export' : 'snapshot'} définitivement ?`, + variant: "danger", + onConfirm: async () => { + setIsDeleting(id); + try { + const res = await deleteSnapshot(id); + if (res.success) { + setSnapshots(prev => prev.filter(s => s.id !== id)); + setModal({ isOpen: true, title: "Action Réussie", message: "L'élément a été supprimé de votre historique." }); + } else { + setModal({ isOpen: true, title: "Erreur", message: "Impossible de supprimer l'élément." }); + } + } catch (err) { + setModal({ isOpen: true, title: "Erreur Technique", message: "Une erreur est survenue lors de la suppression." }); + } finally { + setIsDeleting(null); + } + }, + }); }; const handleLoad = (snapshot: any) => { - if (!window.confirm(`Charger la session "${snapshot.label}" ? Cela remplacera vos brouillons actuels.`)) return; - - const changes: Record = {}; - Object.entries(snapshot.changes as any).forEach(([codein, delta]: [string, any]) => { - changes[codein] = delta.after; + setConfirmModal({ + isOpen: true, + title: "Restaurer la session", + message: `Charger la session "${snapshot.label}" ? Cela remplacera vos brouillons actuels.`, + variant: "default", + onConfirm: () => { + const changes: Record = {}; + Object.entries(snapshot.changes as any).forEach(([codein, delta]: [string, any]) => { + changes[codein] = delta.after; + }); + restoreSnapshot(changes); + const query = new URLSearchParams(); + if (snapshot.codeFournisseur) query.set("fournisseur", snapshot.codeFournisseur); + if (snapshot.magasin) query.set("magasin", snapshot.magasin); + router.push(`/grid?${query.toString()}`); + }, }); - - restoreSnapshot(changes); - - const query = new URLSearchParams(); - if (snapshot.codeFournisseur) query.set("fournisseur", snapshot.codeFournisseur); - if (snapshot.magasin) query.set("magasin", snapshot.magasin); - - router.push(`/grid?${query.toString()}`); }; if (loading) { @@ -209,6 +216,16 @@ export function SnapshotList({ type }: SnapshotListProps) { title={modal.title} message={modal.message} /> + + setConfirmModal(prev => ({ ...prev, isOpen: false }))} + onConfirm={confirmModal.onConfirm} + title={confirmModal.title} + message={confirmModal.message} + variant={confirmModal.variant} + confirmLabel={confirmModal.variant === "danger" ? "Supprimer" : "Confirmer"} + />
); }