"use client"; import type * as React from "react"; import { useState, useTransition } from "react"; import { Check, Copy, type LucideIcon, MoreHorizontal, Trash2, } from "lucide-react"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard"; import type { DropdownMenuContentProps } from "@radix-ui/react-dropdown-menu"; import { isTRPCClientError } from "@trpc/client"; import { toast } from "sonner"; interface QuickActionsProps extends React.ComponentProps { align?: DropdownMenuContentProps["align"]; side?: DropdownMenuContentProps["side"]; actions?: { id: string; label: string; icon: LucideIcon; variant: "default" | "destructive"; onClick?: () => Promise | void; }[]; deleteAction?: { /** * The value that must be typed to confirm deletion. Also used in the dialog title. */ confirmationValue: string; submitAction?: () => Promise; }; } export function QuickActions({ align = "end", side, className, actions, deleteAction, children, ...props }: QuickActionsProps) { const [value, setValue] = useState(""); const [isPending, startTransition] = useTransition(); const [open, setOpen] = useState(false); const { copy, isCopied } = useCopyToClipboard(); const handleDelete = async () => { startTransition(async () => { if (!deleteAction?.submitAction) return; const promise = deleteAction.submitAction(); toast.promise(promise, { loading: "Deleting...", success: "Deleted", error: (error) => { if (isTRPCClientError(error)) { return error.message; } return "Failed to delete"; }, }); try { await promise; } catch (error) { console.error("Failed to delete:", error); } finally { setOpen(false); } }); }; return ( {children ?? ( )} Quick Actions {actions ?.filter((item) => item.id !== "delete") .map((item) => ( { e.stopPropagation(); item.onClick?.(); }} > {item.label} ))} {deleteAction && ( <> {/* NOTE: add a separator only if actions exist */} {actions?.length ? : null} Delete )} { // NOTE: bug where the body is not clickable after closing the alert dialog event.preventDefault(); document.body.style.pointerEvents = ""; }} > Are you sure about deleting `{deleteAction?.confirmationValue}`? This action cannot be undone. This will permanently remove the entry from the database. {deleteAction?.confirmationValue && (

Type{" "} {" "} to confirm

setValue(e.target.value)} />
)} e.stopPropagation()}> Cancel { e.preventDefault(); handleDelete(); }} > {isPending ? "Deleting..." : "Delete"}
); }