167 lines
5.7 KiB
TypeScript
167 lines
5.7 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useTransition } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import type { UserRole } from "@prisma/client";
|
|
import { ShieldCheck } from "lucide-react";
|
|
import { toast } from "sonner";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import { availableKitaRoles, kitaRoleLabels } from "@/lib/kita-roles";
|
|
import { changeKitaRoleAction } from "./actions";
|
|
|
|
const descriptions: Record<string, string> = {
|
|
ELTERN: "Eigener Haushalt, Verfügbarkeiten, Diensttausch und Kita-Alltag.",
|
|
KOORDINATOR: "Zusätzlich Notdienstpläne, Alarme und Termine koordinieren.",
|
|
ADMIN:
|
|
"Familien, Team, Zugriffsrechte und alle Kita-Verwaltungsbereiche verwalten.",
|
|
ERZIEHER:
|
|
"Personalbereich, eigene Arbeitszeit und Anträge sowie Kinder-Abwesenheiten.",
|
|
};
|
|
|
|
export type RolePerson = {
|
|
id: string;
|
|
name: string;
|
|
role: UserRole;
|
|
familyId: string | null;
|
|
hasStaffProfile: boolean;
|
|
};
|
|
|
|
export function RoleChangeButton({
|
|
person,
|
|
ownAccount = false,
|
|
}: {
|
|
person: RolePerson;
|
|
ownAccount?: boolean;
|
|
}) {
|
|
const router = useRouter();
|
|
const [open, setOpen] = useState(false);
|
|
const [role, setRole] = useState(person.role);
|
|
const [error, setError] = useState("");
|
|
const [pending, startTransition] = useTransition();
|
|
const roles = availableKitaRoles(person);
|
|
const submit = () => {
|
|
setError("");
|
|
startTransition(async () => {
|
|
try {
|
|
const result = await changeKitaRoleAction({
|
|
userId: person.id,
|
|
role,
|
|
expectedRole: person.role,
|
|
});
|
|
if (result.error) {
|
|
setError(result.error);
|
|
return;
|
|
}
|
|
toast.success("Zugriffsrolle gespeichert.");
|
|
setOpen(false);
|
|
if (result.ownRoleChanged) router.replace("/dashboard");
|
|
router.refresh();
|
|
} catch {
|
|
setError(
|
|
"Die Änderung konnte nicht gespeichert werden. Bitte erneut versuchen.",
|
|
);
|
|
}
|
|
});
|
|
};
|
|
return (
|
|
<>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
aria-label={`Zugriffsrechte für ${person.name}`}
|
|
disabled={person.role === "SUPERADMIN"}
|
|
onClick={() => {
|
|
setRole(person.role);
|
|
setError("");
|
|
setOpen(true);
|
|
}}
|
|
>
|
|
<ShieldCheck className="h-3.5 w-3.5" /> Zugriffsrechte
|
|
</Button>
|
|
<Dialog
|
|
open={open}
|
|
onOpenChange={(next) => {
|
|
if (!pending) setOpen(next);
|
|
}}
|
|
>
|
|
<DialogContent className="max-h-[90dvh] overflow-y-auto sm:max-w-lg">
|
|
<DialogHeader>
|
|
<DialogTitle>Zugriffsrechte für {person.name}</DialogTitle>
|
|
<DialogDescription>
|
|
Die Zugriffsrolle bestimmt, welche Bereiche diese Person nutzen
|
|
und verwalten kann. Ämter wie „Vorstand“ werden separat vergeben.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<fieldset disabled={pending} className="grid gap-2">
|
|
<legend className="mb-2 text-sm font-semibold text-[var(--ink)]">
|
|
Zugriffsrolle
|
|
</legend>
|
|
{roles.map((value) => (
|
|
<label
|
|
key={value}
|
|
className={`flex cursor-pointer items-start gap-3 rounded-xl border p-3 transition-colors ${role === value ? "border-[var(--accent-mid)] bg-[var(--accent-soft)]" : "border-[var(--hairline)] hover:bg-[var(--surface-2)]"}`}
|
|
>
|
|
<input
|
|
type="radio"
|
|
name={`role-${person.id}`}
|
|
value={value}
|
|
checked={role === value}
|
|
onChange={() => setRole(value)}
|
|
className="mt-1 accent-[var(--accent-deep)]"
|
|
/>
|
|
<span>
|
|
<span className="block text-sm font-semibold text-[var(--ink)]">
|
|
{kitaRoleLabels[value]}
|
|
</span>
|
|
<span className="mt-1 block text-xs leading-5 text-[var(--ink-soft)]">
|
|
{descriptions[value]}
|
|
</span>
|
|
</span>
|
|
</label>
|
|
))}
|
|
</fieldset>
|
|
<p className="text-xs leading-5 text-[var(--ink-soft)]">
|
|
{person.hasStaffProfile
|
|
? "Das Personalprofil mit Arbeitszeiten und Anträgen bleibt erhalten. Mit Kita-Admin-Rechten ist zusätzlich die Personalverwaltung zugänglich."
|
|
: person.familyId
|
|
? "Haushalt, Kinder und eigene Dienste bleiben erhalten."
|
|
: "Dieses Konto hat keinen eigenen Haushalt. Deshalb steht die Elternrolle nicht zur Auswahl."}
|
|
</p>
|
|
{ownAccount && role !== person.role ? (
|
|
<p className="rounded-lg bg-[var(--warn-soft)] p-3 text-sm leading-5 text-[var(--warn)]">
|
|
Du änderst deine eigenen Rechte. Nach dem Speichern gelangst du
|
|
zur Übersicht; der Zugang zur Verwaltung richtet sich dann nach
|
|
der neuen Rolle.
|
|
</p>
|
|
) : null}
|
|
{error ? (
|
|
<p role="alert" className="text-sm leading-5 text-[var(--danger)]">
|
|
{error}
|
|
</p>
|
|
) : null}
|
|
<DialogFooter>
|
|
<Button
|
|
variant="outline"
|
|
disabled={pending}
|
|
onClick={() => setOpen(false)}
|
|
>
|
|
Abbrechen
|
|
</Button>
|
|
<Button disabled={pending || role === person.role} onClick={submit}>
|
|
{pending ? "Wird gespeichert …" : "Rolle speichern"}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</>
|
|
);
|
|
}
|