TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1"use client";2import * as React from "react";3import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogBody } from "@/components/ui/dialog";4import { Button } from "@/components/ui/button";5import { Input } from "@/components/ui/input";67export interface ConfirmDialogProps {8 open: boolean;9 onOpenChange: (open: boolean) => void;10 title: React.ReactNode;11 description?: React.ReactNode;12 confirmLabel?: string;13 cancelLabel?: string;14 destructive?: boolean;15 /** When set, the user must type this exact string to enable the confirm button. */16 typeToConfirm?: string;17 onConfirm: () => Promise<void> | void;18 children?: React.ReactNode;19}2021export function ConfirmDialog({ open, onOpenChange, title, description, confirmLabel = "Confirm", cancelLabel = "Cancel", destructive, typeToConfirm, onConfirm, children }: ConfirmDialogProps) {22 const [busy, setBusy] = React.useState(false);23 const [typed, setTyped] = React.useState("");24 const canConfirm = !typeToConfirm || typed.trim() === typeToConfirm;2526 const handleOpenChange = (v: boolean) => {27 if (!v) setTyped("");28 onOpenChange(v);29 };3031 return (32 <Dialog open={open} onOpenChange={handleOpenChange}>33 <DialogContent size="sm">34 <DialogHeader>35 <DialogTitle>{title}</DialogTitle>36 {description ? <DialogDescription>{description}</DialogDescription> : null}37 </DialogHeader>38 {children || typeToConfirm ? (39 <DialogBody className="space-y-3">40 {children}41 {typeToConfirm ? (42 <div className="space-y-1.5">43 <p className="text-xs text-fg-muted">44 Type <span className="font-mono font-medium text-fg">{typeToConfirm}</span> to confirm.45 </p>46 <Input value={typed} onChange={(e) => setTyped(e.target.value)} autoComplete="off" spellCheck={false} aria-label="Confirmation text" />47 </div>48 ) : null}49 </DialogBody>50 ) : null}51 <DialogFooter>52 <Button variant="ghost" onClick={() => handleOpenChange(false)} disabled={busy}>53 {cancelLabel}54 </Button>55 <Button56 variant={destructive ? "danger" : "primary"}57 loading={busy}58 disabled={!canConfirm}59 onClick={async () => {60 setBusy(true);61 try {62 await onConfirm();63 handleOpenChange(false);64 } finally {65 setBusy(false);66 }67 }}68 >69 {confirmLabel}70 </Button>71 </DialogFooter>72 </DialogContent>73 </Dialog>74 );75}76