"use client"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, } from "@/components/ui/sheet"; import { cn } from "@/lib/utils"; import React, { createContext, useContext, useEffect, useRef, useState, } from "react"; export function FormSheetContent({ children, className, ...props }: React.ComponentProps) { return ( {children} ); } export function FormSheetHeader({ children, className, ...props }: React.ComponentProps) { return ( {children} ); } export function FormSheetFooter({ children, className, ...props }: React.ComponentProps) { return ( {children} ); } export function FormSheetFooterInfo({ children, className, ...props }: React.ComponentProps<"p">) { return (

{children}

); } export function FormSheetTrigger({ children, className, disabled, ...props }: React.ComponentProps) { return ( {children} ); } export function FormSheetAlertDialog({ onConfirm, ...props }: React.ComponentProps & { onConfirm: () => void; }) { return ( Discard changes? You have unsaved changes. Are you sure you want to discard them? Continue editing Discard changes ); } const FormSheetDirtyContext = createContext<{ isDirty: boolean; setIsDirty: (dirty: boolean) => void; } | null>(null); export function useFormSheetDirty() { const context = useContext(FormSheetDirtyContext); if (!context) { throw new Error( "useFormSheetDirty must be used within FormSheetWithDirtyProtection", ); } return context; } export function FormSheetWithDirtyProtection({ children, open: controlledOpen, onOpenChange: controlledOnOpenChange, }: { children: React.ReactNode; open?: boolean; onOpenChange?: (open: boolean) => void; }) { const [internalOpen, setInternalOpen] = useState(false); const [isDirty, setIsDirty] = useState(false); const [showAlert, setShowAlert] = useState(false); const shouldBypassAlert = useRef(false); const open = controlledOpen ?? internalOpen; const setOpen = controlledOnOpenChange ?? setInternalOpen; // Reset states when sheet closes useEffect(() => { if (!open) { setIsDirty(false); shouldBypassAlert.current = false; } }, [open]); const handleOpenChange = (newOpen: boolean) => { if (!newOpen && isDirty && !shouldBypassAlert.current) { // User is trying to close with unsaved changes setShowAlert(true); } else { setOpen(newOpen); } }; const handleDiscardChanges = () => { shouldBypassAlert.current = true; setShowAlert(false); setOpen(false); }; const handleInteractOutside = (e: Event) => { if (isDirty) { e.preventDefault(); setShowAlert(true); } }; const handleEscapeKeyDown = (e: KeyboardEvent) => { if (isDirty) { e.preventDefault(); setShowAlert(true); } }; return ( {/* Clone children and inject event handlers if it's SheetContent */} {React.Children.map(children, (child) => { if ( React.isValidElement(child) && (child.type === FormSheetContent || child.type === SheetContent) ) { return React.cloneElement( child as React.ReactElement<{ onInteractOutside?: (e: Event) => void; onEscapeKeyDown?: (e: KeyboardEvent) => void; }>, { onInteractOutside: handleInteractOutside, onEscapeKeyDown: handleEscapeKeyDown, }, ); } return child; })} ); } export { SheetTitle as FormSheetTitle, SheetDescription as FormSheetDescription, Sheet as FormSheet, };