DiscardChangesConfirmationDialog.tsx 2.1 KB

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