Replace per-row inline action buttons (Edit, Activate/Deactivate, Delete, Grant SuperUser) across all six admin tables with a Radix DropdownMenu triggered by a ⋯ button. Introduces RowActionsMenu/Item/DestructiveItem/ Separator primitives and a DeleteConfirmDialog modal. Each Edit*Button gains controlled open/onOpenChange props so the dialog can be driven from the table's per-row ActionsMenu sub-component. Toggle and delete actions use useTransition + router.refresh() directly in the table. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
|
import { MoreHorizontal } from "lucide-react";
|
|
|
|
export function RowActionsMenu({ children }: { children: React.ReactNode }) {
|
|
return (
|
|
<DropdownMenu.Root>
|
|
<DropdownMenu.Trigger asChild>
|
|
<button
|
|
className="rounded p-1.5 text-neutral-400 hover:text-neutral-600 hover:bg-neutral-100 transition-colors"
|
|
aria-label="Row actions"
|
|
>
|
|
<MoreHorizontal className="h-4 w-4" />
|
|
</button>
|
|
</DropdownMenu.Trigger>
|
|
<DropdownMenu.Portal>
|
|
<DropdownMenu.Content
|
|
align="end"
|
|
sideOffset={4}
|
|
className="min-w-[160px] rounded-lg border border-neutral-200 bg-white shadow-lg py-1 z-50"
|
|
>
|
|
{children}
|
|
</DropdownMenu.Content>
|
|
</DropdownMenu.Portal>
|
|
</DropdownMenu.Root>
|
|
);
|
|
}
|
|
|
|
export function RowActionsItem({
|
|
children,
|
|
onClick,
|
|
disabled,
|
|
}: {
|
|
children: React.ReactNode;
|
|
onClick?: () => void;
|
|
disabled?: boolean;
|
|
}) {
|
|
return (
|
|
<DropdownMenu.Item
|
|
onSelect={(e) => {
|
|
e.preventDefault();
|
|
onClick?.();
|
|
}}
|
|
disabled={disabled}
|
|
className="flex items-center gap-2 px-3 py-2 text-sm cursor-pointer hover:bg-neutral-50 transition-colors text-neutral-700 outline-none data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed"
|
|
>
|
|
{children}
|
|
</DropdownMenu.Item>
|
|
);
|
|
}
|
|
|
|
export function RowActionsDestructiveItem({
|
|
children,
|
|
onClick,
|
|
disabled,
|
|
}: {
|
|
children: React.ReactNode;
|
|
onClick?: () => void;
|
|
disabled?: boolean;
|
|
}) {
|
|
return (
|
|
<DropdownMenu.Item
|
|
onSelect={(e) => {
|
|
e.preventDefault();
|
|
onClick?.();
|
|
}}
|
|
disabled={disabled}
|
|
className="flex items-center gap-2 px-3 py-2 text-sm cursor-pointer hover:bg-danger-50 transition-colors text-danger-600 outline-none data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed"
|
|
>
|
|
{children}
|
|
</DropdownMenu.Item>
|
|
);
|
|
}
|
|
|
|
export function RowActionsSeparator() {
|
|
return <DropdownMenu.Separator className="my-1 h-px bg-neutral-100" />;
|
|
}
|