mirror of
https://github.com/Since-3/since3-portal.git
synced 2026-10-12 21:41:16 +00:00
124 lines
4.4 KiB
TypeScript
124 lines
4.4 KiB
TypeScript
"use client";
|
|
|
|
import { useActionState, useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { FolderPlusIcon, Trash2Icon } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
} from "@/components/ui/dialog";
|
|
import { Field, FieldLabel } from "@/components/ui/field";
|
|
import { Input } from "@/components/ui/input";
|
|
import { createFolder, deleteFolder, type DocumentActionState } from "@/modules/shared/actions/documents";
|
|
|
|
function CreateFolderForm({ profileId, onDone }: { profileId: string; onDone: () => void }) {
|
|
async function run(prev: DocumentActionState, formData: FormData) {
|
|
const result = await createFolder(prev, formData);
|
|
if (result && "success" in result) onDone();
|
|
return result;
|
|
}
|
|
|
|
const [state, formAction, pending] = useActionState(run, undefined);
|
|
|
|
return (
|
|
<form action={formAction} className="flex flex-col gap-4">
|
|
<input type="hidden" name="profileId" value={profileId} />
|
|
<Field>
|
|
<FieldLabel htmlFor="folder-name">Name</FieldLabel>
|
|
<Input id="folder-name" name="name" placeholder="z. B. Verträge" autoFocus required />
|
|
</Field>
|
|
{state && "error" in state && <p className="text-sm text-destructive">{state.error}</p>}
|
|
<DialogFooter>
|
|
<Button type="submit" disabled={pending}>
|
|
{pending ? "Wird erstellt..." : "Erstellen"}
|
|
</Button>
|
|
</DialogFooter>
|
|
</form>
|
|
);
|
|
}
|
|
|
|
export function CreateFolderDialog({ profileId }: { profileId: string }) {
|
|
const [open, setOpen] = useState(false);
|
|
const [instanceKey, setInstanceKey] = useState(0);
|
|
|
|
function handleOpenChange(nextOpen: boolean) {
|
|
setOpen(nextOpen);
|
|
if (!nextOpen) setInstanceKey((key) => key + 1);
|
|
}
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={handleOpenChange}>
|
|
<DialogTrigger render={<Button />}>
|
|
<FolderPlusIcon className="size-4" /> Neuer Ordner
|
|
</DialogTrigger>
|
|
<DialogContent>
|
|
<DialogHeader className="mb-2">
|
|
<DialogTitle>Neuer Ordner</DialogTitle>
|
|
</DialogHeader>
|
|
<CreateFolderForm key={instanceKey} profileId={profileId} onDone={() => handleOpenChange(false)} />
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|
|
|
|
export function DeleteFolderDialog({
|
|
profileId,
|
|
folderId,
|
|
folderName,
|
|
redirectTo,
|
|
}: {
|
|
profileId: string;
|
|
folderId: string;
|
|
folderName: string;
|
|
redirectTo: string;
|
|
}) {
|
|
const router = useRouter();
|
|
const [open, setOpen] = useState(false);
|
|
const [pending, setPending] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
async function handleDelete() {
|
|
setPending(true);
|
|
setError(null);
|
|
const result = await deleteFolder(profileId, folderId);
|
|
setPending(false);
|
|
if (result && "error" in result) {
|
|
setError(result.error);
|
|
return;
|
|
}
|
|
setOpen(false);
|
|
router.push(redirectTo);
|
|
}
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
<DialogTrigger render={<Button variant="outline" />}>
|
|
<Trash2Icon className="size-4" /> Ordner löschen
|
|
</DialogTrigger>
|
|
<DialogContent>
|
|
<DialogHeader className="mb-4">
|
|
<DialogTitle>Ordner löschen</DialogTitle>
|
|
<DialogDescription>
|
|
Möchtest du den Ordner <span className="font-medium text-foreground">{folderName}</span> löschen?
|
|
Das geht nur, wenn er leer ist.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
{error && <p className="text-sm text-destructive">{error}</p>}
|
|
<DialogFooter>
|
|
<Button type="button" variant="outline" onClick={() => setOpen(false)} disabled={pending}>
|
|
Abbrechen
|
|
</Button>
|
|
<Button type="button" variant="destructive" onClick={handleDelete} disabled={pending}>
|
|
{pending ? "Wird gelöscht..." : "Löschen"}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|