From 1c7309a2b675ff473fe198edc126ed8429deef6c Mon Sep 17 00:00:00 2001 From: Esdras Renan Date: Sat, 18 Oct 2025 19:52:05 -0300 Subject: [PATCH] Add confirmation dialog for client deletion and align machine badges --- .../admin/clients/admin-clients-manager.tsx | 292 +++++++++++------- .../machines/admin-machines-overview.tsx | 2 +- 2 files changed, 182 insertions(+), 112 deletions(-) diff --git a/src/components/admin/clients/admin-clients-manager.tsx b/src/components/admin/clients/admin-clients-manager.tsx index 8a0adf2..7fa9afb 100644 --- a/src/components/admin/clients/admin-clients-manager.tsx +++ b/src/components/admin/clients/admin-clients-manager.tsx @@ -25,6 +25,14 @@ import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { Input } from "@/components/ui/input" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" import { Select, SelectContent, @@ -79,6 +87,7 @@ export function AdminClientsManager({ initialClients }: { initialClients: AdminC const [rowSelection, setRowSelection] = useState({}) const [sorting, setSorting] = useState([{ id: "name", desc: false }]) const [isPending, startTransition] = useTransition() + const [deleteDialogIds, setDeleteDialogIds] = useState([]) const companies = useMemo(() => { const entries = new Map() @@ -104,6 +113,11 @@ export function AdminClientsManager({ initialClients }: { initialClients: AdminC }) }, [clients, roleFilter, companyFilter, search]) + const deleteTargets = useMemo( + () => clients.filter((client) => deleteDialogIds.includes(client.id)), + [clients, deleteDialogIds], + ) + const handleDelete = useCallback( (ids: string[]) => { if (ids.length === 0) return @@ -124,6 +138,7 @@ export function AdminClientsManager({ initialClients }: { initialClients: AdminC if (deletedIds.length > 0) { setClients((prev) => prev.filter((client) => !deletedIds.includes(client.id))) setRowSelection({}) + setDeleteDialogIds([]) } toast.success( deletedIds.length === 1 @@ -239,14 +254,14 @@ export function AdminClientsManager({ initialClients }: { initialClients: AdminC size="sm" className="border-rose-200 text-rose-600 hover:bg-rose-50 hover:text-rose-700" disabled={isPending} - onClick={() => handleDelete([row.original.id])} + onClick={() => setDeleteDialogIds([row.original.id])} > Remover ), }, ], - [handleDelete, isPending] + [isPending, setDeleteDialogIds] ) const table = useReactTable({ @@ -268,124 +283,179 @@ export function AdminClientsManager({ initialClients }: { initialClients: AdminC }) const selectedRows = table.getSelectedRowModel().flatRows.map((row) => row.original) + const isBulkDelete = deleteTargets.length > 1 + const dialogTitle = isBulkDelete ? "Remover clientes selecionados" : "Remover cliente" + const dialogDescription = isBulkDelete + ? "Essa ação remove os clientes selecionados e revoga o acesso ao portal." + : "Essa ação remove o cliente escolhido e revoga o acesso ao portal." + const previewTargets = deleteTargets.slice(0, 3) + const remainingCount = deleteTargets.length - previewTargets.length return ( -
-
-
- - {clients.length} cliente{clients.length === 1 ? "" : "s"} -
-
-
- setSearch(event.target.value)} - className="h-9 w-full md:w-72" - /> - + <> +
+
+
+ + {clients.length} cliente{clients.length === 1 ? "" : "s"}
-
- - - +
+
+ setSearch(event.target.value)} + className="h-9 w-full md:w-72" + /> + +
+
+ + + +
-
-
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - {header.isPlaceholder ? null : header.column.columnDef.header instanceof Function - ? header.column.columnDef.header(header.getContext()) - : header.column.columnDef.header} - - ))} - - ))} - - - {table.getRowModel().rows.length === 0 ? ( - - - Nenhum cliente encontrado para os filtros selecionados. - - - ) : ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender(cell.column.columnDef.cell, cell.getContext())} - +
+
+ + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder ? null : header.column.columnDef.header instanceof Function + ? header.column.columnDef.header(header.getContext()) + : header.column.columnDef.header} + ))} - )) - )} - -
+ ))} + + + {table.getRowModel().rows.length === 0 ? ( + + + Nenhum cliente encontrado para os filtros selecionados. + + + ) : ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + )} + + +
+ +
+
+ Página {table.getState().pagination.pageIndex + 1} de {table.getPageCount() || 1} +
+
+ + +
+
-
-
- Página {table.getState().pagination.pageIndex + 1} de {table.getPageCount() || 1} -
-
- - -
-
-
+ 0} + onOpenChange={(open) => { + if (!open && !isPending) { + setDeleteDialogIds([]) + } + }} + > + + + {dialogTitle} + {dialogDescription} + + {deleteTargets.length > 0 ? ( +
+

+ Confirme a exclusão de {isBulkDelete ? `${deleteTargets.length} clientes selecionados` : "um cliente"}. O acesso ao portal será revogado imediatamente. +

+
    + {previewTargets.map((target) => ( +
  • + {target.name} + — {target.email} +
  • + ))} + {remainingCount > 0 ? ( +
  • + {remainingCount} outro{remainingCount === 1 ? "" : "s"}
  • + ) : null} +
+
+ ) : null} + + + + +
+
+ ) } diff --git a/src/components/admin/machines/admin-machines-overview.tsx b/src/components/admin/machines/admin-machines-overview.tsx index 9e070fc..696702b 100644 --- a/src/components/admin/machines/admin-machines-overview.tsx +++ b/src/components/admin/machines/admin-machines-overview.tsx @@ -1379,7 +1379,7 @@ export function MachineDetails({ machine }: MachineDetailsProps) { {isActive ? (togglingActive ? "Desativando..." : "Desativar") : togglingActive ? "Reativando..." : "Reativar"} {machine.registeredBy ? ( - + Registrada via {machine.registeredBy} ) : null}