DiscardChangesConfirmationDialog.tsx80 lines · main
1'use client'
2
3import { useCallback, useEffect, useRef, type ReactNode } from 'react'
4import {
5 AlertDialog,
6 AlertDialogAction,
7 AlertDialogCancel,
8 AlertDialogContent,
9 AlertDialogDescription,
10 AlertDialogFooter,
11 AlertDialogHeader,
12 AlertDialogTitle,
13} from 'ui'
14
15import { type ConfirmOnCloseModalProps } from '@/hooks/ui/useConfirmOnClose'
16
17export interface DiscardChangesConfirmationDialogProps extends ConfirmOnCloseModalProps {
18 title?: ReactNode
19 description?: ReactNode
20 confirmLabel?: ReactNode
21 cancelLabel?: ReactNode
22 size?: React.ComponentProps<typeof AlertDialogContent>['size']
23}
24
25export const DiscardChangesConfirmationDialog = ({
26 visible,
27 onClose,
28 onCancel,
29 title = 'Unsaved changes',
30 description = 'You have unsaved changes. Are you sure you want to discard them?',
31 confirmLabel = 'Discard changes',
32 cancelLabel = 'Keep editing',
33 size = 'tiny',
34}: DiscardChangesConfirmationDialogProps) => {
35 const isConfirmingRef = useRef(false)
36
37 useEffect(() => {
38 if (visible) {
39 isConfirmingRef.current = false
40 }
41 }, [visible])
42
43 const handleConfirm = useCallback(() => {
44 isConfirmingRef.current = true
45 onClose()
46 }, [onClose])
47
48 const handleOpenChange = useCallback(
49 (open: boolean) => {
50 if (open) return
51
52 if (isConfirmingRef.current) {
53 isConfirmingRef.current = false
54 return
55 }
56
57 onCancel()
58 },
59 [onCancel]
60 )
61
62 return (
63 <AlertDialog open={visible} onOpenChange={handleOpenChange}>
64 <AlertDialogContent size={size}>
65 <AlertDialogHeader>
66 <AlertDialogTitle>{title}</AlertDialogTitle>
67 {description !== undefined && description !== null && (
68 <AlertDialogDescription>{description}</AlertDialogDescription>
69 )}
70 </AlertDialogHeader>
71 <AlertDialogFooter>
72 <AlertDialogCancel>{cancelLabel}</AlertDialogCancel>
73 <AlertDialogAction variant="danger" onClick={handleConfirm}>
74 {confirmLabel}
75 </AlertDialogAction>
76 </AlertDialogFooter>
77 </AlertDialogContent>
78 </AlertDialog>
79 )
80}