Checkpoint: Ajout de boutons Modifier et Supprimer sur chaque ligne de la liste des factures. Le bouton Modifier redirige vers la page de détail, le bouton Supprimer affiche une boîte de dialogue de confirmation avant suppression définitive.

This commit is contained in:
Manus
2026-02-11 09:04:49 -05:00
parent b93c31619f
commit e217ac06ce
2 changed files with 81 additions and 1 deletions

View File

@@ -5,6 +5,16 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import {
Table,
TableBody,
@@ -14,7 +24,7 @@ import {
TableRow,
} from "@/components/ui/table";
import { trpc } from "@/lib/trpc";
import { Search, FileText, Download, FileSpreadsheet, Trash2 } from "lucide-react";
import { Search, FileText, Download, FileSpreadsheet, Trash2, Edit, Trash } from "lucide-react";
import * as XLSX from 'xlsx';
import { toast } from "sonner";
import { useLocation } from "wouter";
@@ -24,6 +34,8 @@ export default function Invoices() {
const [searchQuery, setSearchQuery] = useState("");
const [selectedIds, setSelectedIds] = useState<number[]>([]);
const [statusFilter, setStatusFilter] = useState<string>("all");
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [invoiceToDelete, setInvoiceToDelete] = useState<number | null>(null);
const { data: invoices, isLoading } = trpc.invoices.list.useQuery();
const utils = trpc.useUtils();
@@ -77,6 +89,18 @@ export default function Invoices() {
},
});
const deleteMutation = trpc.invoices.delete.useMutation({
onSuccess: () => {
toast.success("Facture supprimée avec succès");
utils.invoices.list.invalidate();
setDeleteDialogOpen(false);
setInvoiceToDelete(null);
},
onError: (error) => {
toast.error(error.message || "Erreur lors de la suppression");
},
});
const filteredInvoices = invoices?.filter((inv) => {
// Filter by search query
if (searchQuery) {
@@ -309,6 +333,7 @@ export default function Invoices() {
<TableHead>Ventilation</TableHead>
<TableHead>Score</TableHead>
<TableHead>Statut</TableHead>
<TableHead className="w-32">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
@@ -345,6 +370,29 @@ export default function Invoices() {
<TableCell className="text-sm">{invoice.ventilationComptable || "-"}</TableCell>
<TableCell>{getQualityBadge(invoice.qualityScore)}</TableCell>
<TableCell>{getExportStatusBadge(invoice.exportStatus || "not_exported")}</TableCell>
<TableCell>
<div className="flex gap-2">
<Button
size="sm"
variant="outline"
onClick={() => setLocation(`/invoices/${invoice.id}`)}
className="h-8 px-2"
>
<Edit className="h-4 w-4" />
</Button>
<Button
size="sm"
variant="outline"
onClick={() => {
setInvoiceToDelete(invoice.id);
setDeleteDialogOpen(true);
}}
className="h-8 px-2 text-red-600 hover:text-red-700 hover:bg-red-50"
>
<Trash className="h-4 w-4" />
</Button>
</div>
</TableCell>
</TableRow>
);
})}
@@ -373,6 +421,31 @@ export default function Invoices() {
</div>
)}
</div>
{/* Delete Confirmation Dialog */}
<AlertDialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Êtes-vous sûr de vouloir supprimer cette facture ?</AlertDialogTitle>
<AlertDialogDescription>
Cette action est irréversible. La facture sera définitivement supprimée de la base de données.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={() => setInvoiceToDelete(null)}>Annuler</AlertDialogCancel>
<AlertDialogAction
onClick={() => {
if (invoiceToDelete) {
deleteMutation.mutate({ id: invoiceToDelete });
}
}}
className="bg-red-600 hover:bg-red-700"
>
Supprimer
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</DashboardLayout>
);
}