/** * Provider that wraps the builder and adds undo/redo functionality * Automatically stores state snapshots when significant changes occur */ "use client"; import { createContext, useContext, useEffect, useRef, type ReactNode } from 'react'; import { useBuilderState, useBuilderDispatch } from '@/lib/admin/builder/context'; import { useSimpleUndoRedo } from '@/lib/admin/builder/useSimpleUndoRedo'; import type { BuilderState } from '@/lib/admin/builder/context'; interface UndoRedoContextValue { canUndo: boolean; canRedo: boolean; undo: () => void; redo: () => void; store: () => void; clear: () => void; resetDirty: () => void; // Сброс isDirty флага } const UndoRedoContext = createContext(undefined); interface BuilderUndoRedoProviderProps { children: ReactNode; } export function BuilderUndoRedoProvider({ children }: BuilderUndoRedoProviderProps) { const state = useBuilderState(); const dispatch = useBuilderDispatch(); const previousStateRef = useRef(state); const isRestoringRef = useRef(false); // Функция для сброса isDirty const resetDirty = () => { dispatch({ type: 'reset', payload: { ...state, isDirty: false } }); }; const undoRedo = useSimpleUndoRedo( state, (newState) => { isRestoringRef.current = true; dispatch({ type: 'reset', payload: newState }); } ); // Auto-store state when significant changes occur useEffect(() => { // Don't store if we're in the middle of restoring from undo/redo if (isRestoringRef.current) { isRestoringRef.current = false; previousStateRef.current = state; return; } const prev = previousStateRef.current; // Check for significant changes that should trigger a store const shouldStore = ( // Screen count changed prev.screens.length !== state.screens.length || // Selected screen changed prev.selectedScreenId !== state.selectedScreenId || // Meta data changed JSON.stringify(prev.meta) !== JSON.stringify(state.meta) || // Screen structure changed (templates, navigation, etc.) prev.screens.some((prevScreen, index) => { const currentScreen = state.screens[index]; if (!currentScreen || prevScreen.id !== currentScreen.id) return true; return ( prevScreen.template !== currentScreen.template || JSON.stringify(prevScreen.navigation) !== JSON.stringify(currentScreen.navigation) || JSON.stringify(prevScreen.title) !== JSON.stringify(currentScreen.title) ); }) ); if (shouldStore) { // Store the previous state (not current) so we can undo to it undoRedo.store(); previousStateRef.current = state; } }, [state, undoRedo]); // Store initial state useEffect(() => { undoRedo.store(); }, []); // eslint-disable-line react-hooks/exhaustive-deps const contextValue: UndoRedoContextValue = { canUndo: undoRedo.canUndo, canRedo: undoRedo.canRedo, undo: undoRedo.undo, redo: undoRedo.redo, store: undoRedo.store, clear: undoRedo.clear, resetDirty, }; return ( {children} ); } export function useBuilderUndoRedo(): UndoRedoContextValue { const context = useContext(UndoRedoContext); if (!context) { throw new Error('useBuilderUndoRedo must be used within BuilderUndoRedoProvider'); } return context; }