From 70d1cf23e598b5f3881719e5bb6b9a63e34f4af7 Mon Sep 17 00:00:00 2001 From: Manus Date: Wed, 11 Feb 2026 09:18:38 -0500 Subject: [PATCH] =?UTF-8?q?Checkpoint:=20Ajout=20d'une=20option=20"?= =?UTF-8?q?=E2=9E=9C=20Ajouter..."=20dans=20les=20menus=20d=C3=A9roulants?= =?UTF-8?q?=20Service=20et=20Ventilation=20de=20la=20liste=20des=20facture?= =?UTF-8?q?s.=20Quand=20s=C3=A9lectionn=C3=A9e,=20une=20bo=C3=AEte=20de=20?= =?UTF-8?q?dialogue=20s'ouvre=20pour=20saisir=20le=20nouveau=20nom,=20qui?= =?UTF-8?q?=20est=20automatiquement=20ajout=C3=A9=20=C3=A0=20la=20liste=20?= =?UTF-8?q?et=20s=C3=A9lectionn=C3=A9=20pour=20la=20facture=20en=20cours.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/pages/Invoices.tsx | 136 ++++++++++++++++++++++++++++++++-- todo.md | 8 ++ 2 files changed, 136 insertions(+), 8 deletions(-) diff --git a/client/src/pages/Invoices.tsx b/client/src/pages/Invoices.tsx index 78d91c9..26e5b4a 100644 --- a/client/src/pages/Invoices.tsx +++ b/client/src/pages/Invoices.tsx @@ -15,6 +15,14 @@ import { AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; import { Table, TableBody, @@ -36,6 +44,10 @@ export default function Invoices() { const [statusFilter, setStatusFilter] = useState("all"); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [invoiceToDelete, setInvoiceToDelete] = useState(null); + const [addDialogOpen, setAddDialogOpen] = useState(false); + const [addDialogType, setAddDialogType] = useState<"service" | "ventilation" | null>(null); + const [newItemName, setNewItemName] = useState(""); + const [pendingInvoiceId, setPendingInvoiceId] = useState(null); const { data: invoices, isLoading } = trpc.invoices.list.useQuery(); const { data: departments } = trpc.departments.getByUser.useQuery(); const { data: allocations } = trpc.accountingAllocations.getByUser.useQuery(); @@ -113,6 +125,58 @@ export default function Invoices() { }, }); + const createDepartmentMutation = trpc.departments.create.useMutation({ + onSuccess: (newDept) => { + toast.success("Service ajouté avec succès"); + utils.departments.getByUser.invalidate(); + // Update the invoice with the new department + if (pendingInvoiceId) { + updateFieldMutation.mutate({ + id: pendingInvoiceId, + data: { serviceConcerne: newDept.name }, + }); + } + setAddDialogOpen(false); + setNewItemName(""); + setPendingInvoiceId(null); + }, + onError: (error) => { + toast.error(error.message || "Erreur lors de l'ajout"); + }, + }); + + const createAllocationMutation = trpc.accountingAllocations.create.useMutation({ + onSuccess: (newAlloc) => { + toast.success("Ventilation ajoutée avec succès"); + utils.accountingAllocations.getByUser.invalidate(); + // Update the invoice with the new allocation + if (pendingInvoiceId) { + updateFieldMutation.mutate({ + id: pendingInvoiceId, + data: { ventilationComptable: newAlloc.name }, + }); + } + setAddDialogOpen(false); + setNewItemName(""); + setPendingInvoiceId(null); + }, + onError: (error) => { + toast.error(error.message || "Erreur lors de l'ajout"); + }, + }); + + const handleAddNewItem = () => { + if (!newItemName.trim()) { + toast.error("Le nom ne peut pas être vide"); + return; + } + if (addDialogType === "service") { + createDepartmentMutation.mutate({ name: newItemName.trim() }); + } else if (addDialogType === "ventilation") { + createAllocationMutation.mutate({ name: newItemName.trim() }); + } + }; + const filteredInvoices = invoices?.filter((inv) => { // Filter by search query if (searchQuery) { @@ -381,10 +445,17 @@ export default function Invoices() { @@ -414,10 +486,17 @@ export default function Invoices() { {getQualityBadge(invoice.qualityScore)} @@ -505,6 +585,46 @@ export default function Invoices() { + + {/* Add New Item Dialog */} + + + + + Ajouter {addDialogType === "service" ? "un nouveau service" : "une nouvelle ventilation"} + + + Entrez le nom {addDialogType === "service" ? "du service" : "de la ventilation comptable"} à ajouter. + + +
+ setNewItemName(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter") { + handleAddNewItem(); + } + }} + autoFocus + /> +
+ + + + +
+
); } diff --git a/todo.md b/todo.md index 579c7db..268f3b9 100644 --- a/todo.md +++ b/todo.md @@ -230,3 +230,11 @@ - [x] Transformer la cellule Ventilation en menu déroulant éditable - [x] Sauvegarder automatiquement les modifications (mutation updateFieldMutation) - [x] Afficher une notification de succès après sauvegarde + +## Ajout dynamique depuis les menus déroulants +- [x] Ajouter option "➜ Ajouter..." dans le menu Service +- [x] Ajouter option "➜ Ajouter..." dans le menu Ventilation +- [x] Créer une boîte de dialogue pour saisir le nouveau nom +- [x] Sauvegarder la nouvelle entrée dans la base de données (createDepartmentMutation, createAllocationMutation) +- [x] Sélectionner automatiquement la nouvelle valeur pour la facture +- [x] Rafraîchir les listes après ajout (invalidate queries)