Organize/components/admin/user-role-menu.tsx

72 lines
1.9 KiB
TypeScript

"use client";
import { useState } from "react";
import { toast } from "sonner";
import { Badge } from "@/components/ui/badge";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { updateUserRole } from "@/lib/actions/admin";
import { Role } from "@/lib/generated/prisma/enums";
const ROLE_BADGE_VARIANT: Record<Role, "default" | "secondary" | "outline"> = {
ADMIN: "default",
USER: "secondary",
PENDING: "outline",
};
const ROLE_LABEL: Record<Role, string> = {
ADMIN: "Administrator",
USER: "User",
PENDING: "Pending",
};
/** The role badge doubles as the trigger -- clicking it opens a menu to
* change the user's role in place. */
export function UserRoleMenu({ userId, role }: { userId: string; role: Role }) {
const [current, setCurrent] = useState(role);
const [pending, setPending] = useState(false);
async function handleChange(next: string) {
if (next === current || pending) return;
const prev = current;
setCurrent(next as Role);
setPending(true);
const result = await updateUserRole(userId, next);
setPending(false);
if (result?.error) {
setCurrent(prev);
toast.error(result.error);
}
}
return (
<DropdownMenu>
<DropdownMenuTrigger
render={
<Badge
variant={ROLE_BADGE_VARIANT[current]}
className="cursor-pointer select-none"
>
{ROLE_LABEL[current]}
</Badge>
}
/>
<DropdownMenuContent align="start">
<DropdownMenuRadioGroup value={current} onValueChange={handleChange}>
{Object.values(Role).map((value) => (
<DropdownMenuRadioItem key={value} value={value}>
{ROLE_LABEL[value]}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
);
}