"use client" import * as React from "react" import { AlertTriangleIcon } from "lucide-react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog" export type AlertDialogProps = Omit, "children"> & { title?: React.ReactNode description?: React.ReactNode icon?: React.ReactNode cancelLabel?: React.ReactNode actionLabel?: React.ReactNode actionTone?: "default" | "destructive" cancelVariant?: React.ComponentProps["variant"] loading?: boolean closeOnAction?: boolean confirmValue?: string confirmLabel?: React.ReactNode confirmPlaceholder?: string confirmDescription?: React.ReactNode confirmCaseSensitive?: boolean severityNote?: React.ReactNode errorMessage?: React.ReactNode onActionError?: (error: unknown) => void onAction?: () => void | Promise children?: React.ReactNode preventCloseWhileLoading?: boolean actionButtonProps?: Omit, "type" | "variant" | "loading" | "disabled" | "onClick" | "children"> cancelButtonProps?: Omit, "type" | "variant" | "disabled" | "children"> } function AlertDialog({ title = "Are you sure?", description, icon = , cancelLabel = "Cancel", actionLabel = "Continue", actionTone = "destructive", cancelVariant = "outline", loading = false, closeOnAction = true, confirmValue, confirmLabel = "Type to confirm", confirmPlaceholder, confirmDescription, confirmCaseSensitive = true, severityNote, errorMessage = "Action could not be completed. Try again.", onActionError, onAction, children, preventCloseWhileLoading = true, actionButtonProps, cancelButtonProps, onOpenChange, ...props }: AlertDialogProps) { const [pending, setPending] = React.useState(false) const [confirmationInput, setConfirmationInput] = React.useState("") const [actionError, setActionError] = React.useState(null) const resolvedLoading = loading || pending const requiresTypedConfirmation = Boolean(confirmValue?.trim()) const expectedConfirmation = confirmCaseSensitive ? confirmValue?.trim() : confirmValue?.trim().toLowerCase() const actualConfirmation = confirmCaseSensitive ? confirmationInput.trim() : confirmationInput.trim().toLowerCase() const canConfirm = !requiresTypedConfirmation || actualConfirmation === expectedConfirmation React.useEffect(() => { if (!props.open) { setConfirmationInput("") setActionError(null) } }, [props.open]) const handleOpenChange = React.useCallback( (nextOpen: boolean, eventDetails: unknown) => { if (!nextOpen && preventCloseWhileLoading && resolvedLoading) { return } onOpenChange?.(nextOpen, eventDetails as never) }, [onOpenChange, preventCloseWhileLoading, resolvedLoading] ) const closeDialog = () => { handleOpenChange(false, undefined) } const handleAction = async () => { if (!canConfirm || resolvedLoading) return setActionError(null) if (!onAction) { if (closeOnAction) closeDialog() return } try { setPending(true) await onAction() if (closeOnAction) closeDialog() } catch (error) { setActionError(errorMessage) onActionError?.(error) } finally { setPending(false) } } return ( {children}
{icon}
{title} {description ? {description} : null}
{requiresTypedConfirmation ? (

{confirmLabel}

{confirmDescription ?? ( <> Type {confirmValue} to continue. )}

) : null} {severityNote ? (
{severityNote}
) : null} {actionError ? ( ) : null} }> {cancelLabel}
) } export { AlertDialog }