feat(frontend): confirmation dialogs and undo for destructive-feeling actions
Volk aufloesen, Bienenstand deaktivieren, Benutzer deaktivieren und Webhook loeschen liefen bisher ohne jede Rueckfrage direkt auf Klick. Neue wiederverwendbare ConfirmDialog-Komponente erzwingt jetzt eine bewusste Bestaetigung. Zusaetzlich zeigen Volk/Bienenstand/Benutzer nach dem Aufloesen/Deaktivieren einen Reaktivieren-Button (nutzt die neuen Backend-Endpunkte), da diese Aktionen nie ein echtes Loeschen sind und ein versehentlicher Klick bisher nicht rueckgaengig zu machen war.
This commit is contained in:
1 parent
57979f0371
commit
6ab028d1be
9 files changed
+231
-36
No files matched your search
@@ -8,6 +8,7 @@ import { deactivateUser, fetchUsers } from "@/lib/users/api";
|
||||
vi.mock("@/lib/users/api", () => ({
|
||||
fetchUsers: vi.fn(),
|
||||
deactivateUser: vi.fn(),
|
||||
activateUser: vi.fn(),
|
||||
createUser: vi.fn(),
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { deactivateUser, fetchUsers } from "@/lib/users/api";
|
||||
import { toast } from "sonner";
|
||||
import { activateUser, deactivateUser, fetchUsers } from "@/lib/users/api";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { ConfirmDialog } from "@/components/confirm-dialog";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -25,7 +27,20 @@ export default function UsersPage() {
|
||||
mutationFn: deactivateUser,
|
||||
onSuccess: () => {
|
||||
void queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
toast.success("Benutzer deaktiviert", {
|
||||
description: "Kann jederzeit über „Aktivieren“ wiederhergestellt werden.",
|
||||
});
|
||||
},
|
||||
onError: () => toast.error("Benutzer konnte nicht deaktiviert werden"),
|
||||
});
|
||||
|
||||
const activateMutation = useMutation({
|
||||
mutationFn: activateUser,
|
||||
onSuccess: () => {
|
||||
void queryClient.invalidateQueries({ queryKey: ["users"] });
|
||||
toast.success("Benutzer aktiviert");
|
||||
},
|
||||
onError: () => toast.error("Benutzer konnte nicht aktiviert werden"),
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -65,14 +80,27 @@ export default function UsersPage() {
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={!user.isActive || deactivateMutation.isPending}
|
||||
onClick={() => deactivateMutation.mutate(user.id)}
|
||||
>
|
||||
Deaktivieren
|
||||
</Button>
|
||||
{user.isActive ? (
|
||||
<ConfirmDialog
|
||||
triggerLabel="Deaktivieren"
|
||||
triggerSize="sm"
|
||||
triggerDisabled={deactivateMutation.isPending}
|
||||
title="Benutzer deaktivieren?"
|
||||
description={`„${user.name}“ kann sich danach nicht mehr anmelden. Der Zugang kann jederzeit über „Aktivieren“ wiederhergestellt werden.`}
|
||||
confirmLabel="Deaktivieren"
|
||||
isPending={deactivateMutation.isPending}
|
||||
onConfirm={() => deactivateMutation.mutate(user.id)}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={activateMutation.isPending}
|
||||
onClick={() => activateMutation.mutate(user.id)}
|
||||
>
|
||||
Aktivieren
|
||||
</Button>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
import { deleteWebhook, fetchWebhooks } from "@/lib/webhooks/api";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ConfirmDialog } from "@/components/confirm-dialog";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -28,6 +28,7 @@ export default function WebhooksPage() {
|
||||
void queryClient.invalidateQueries({ queryKey: ["webhooks"] });
|
||||
toast.success("Webhook gelöscht");
|
||||
},
|
||||
onError: () => toast.error("Webhook konnte nicht gelöscht werden"),
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -83,14 +84,16 @@ export default function WebhooksPage() {
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={deleteMutation.isPending}
|
||||
onClick={() => deleteMutation.mutate(webhook.id)}
|
||||
>
|
||||
Löschen
|
||||
</Button>
|
||||
<ConfirmDialog
|
||||
triggerLabel="Löschen"
|
||||
triggerSize="sm"
|
||||
triggerDisabled={deleteMutation.isPending}
|
||||
title="Webhook löschen?"
|
||||
description={`Der Webhook für „${webhook.url}“ wird endgültig gelöscht. Externe Systeme erhalten danach keine Ereignisse mehr über diese Verbindung, und der Vorgang kann nicht rückgängig gemacht werden.`}
|
||||
confirmLabel="Endgültig löschen"
|
||||
isPending={deleteMutation.isPending}
|
||||
onConfirm={() => deleteMutation.mutate(webhook.id)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
|
||||
Reference in new issue
Block a user