import React, { createContext, useContext, useReducer, useCallback } from 'react'; import { useNavigationUrlSync } from '../hooks/useUrlSync'; /** * NavigationContext - Complete navigation management system * * Handles navigation modes, navigation guards for unsaved changes, * and breadcrumb/history navigation. Separated from FileContext to * maintain clear separation of concerns. */ // Navigation mode types - complete list to match fileContext.ts export type ModeType = | 'viewer' | 'pageEditor' | 'fileEditor' | 'merge' | 'split' | 'compress' | 'ocr' | 'convert' | 'sanitize' | 'addPassword' | 'changePermissions' | 'addWatermark' | 'removePassword' | 'single-large-page' | 'repair' | 'unlockPdfForms' | 'removeCertificateSign'; // Navigation state interface NavigationState { currentMode: ModeType; hasUnsavedChanges: boolean; pendingNavigation: (() => void) | null; showNavigationWarning: boolean; } // Navigation actions type NavigationAction = | { type: 'SET_MODE'; payload: { mode: ModeType } } | { type: 'SET_UNSAVED_CHANGES'; payload: { hasChanges: boolean } } | { type: 'SET_PENDING_NAVIGATION'; payload: { navigationFn: (() => void) | null } } | { type: 'SHOW_NAVIGATION_WARNING'; payload: { show: boolean } }; // Navigation reducer const navigationReducer = (state: NavigationState, action: NavigationAction): NavigationState => { switch (action.type) { case 'SET_MODE': return { ...state, currentMode: action.payload.mode }; case 'SET_UNSAVED_CHANGES': return { ...state, hasUnsavedChanges: action.payload.hasChanges }; case 'SET_PENDING_NAVIGATION': return { ...state, pendingNavigation: action.payload.navigationFn }; case 'SHOW_NAVIGATION_WARNING': return { ...state, showNavigationWarning: action.payload.show }; default: return state; } }; // Initial state const initialState: NavigationState = { currentMode: 'pageEditor', hasUnsavedChanges: false, pendingNavigation: null, showNavigationWarning: false }; // Navigation context actions interface export interface NavigationContextActions { setMode: (mode: ModeType) => void; setHasUnsavedChanges: (hasChanges: boolean) => void; showNavigationWarning: (show: boolean) => void; requestNavigation: (navigationFn: () => void) => void; confirmNavigation: () => void; cancelNavigation: () => void; } // Split context values export interface NavigationContextStateValue { currentMode: ModeType; hasUnsavedChanges: boolean; pendingNavigation: (() => void) | null; showNavigationWarning: boolean; } export interface NavigationContextActionsValue { actions: NavigationContextActions; } // Create contexts const NavigationStateContext = createContext(undefined); const NavigationActionsContext = createContext(undefined); // Provider component export const NavigationProvider: React.FC<{ children: React.ReactNode; enableUrlSync?: boolean; }> = ({ children, enableUrlSync = true }) => { const [state, dispatch] = useReducer(navigationReducer, initialState); const actions: NavigationContextActions = { setMode: useCallback((mode: ModeType) => { dispatch({ type: 'SET_MODE', payload: { mode } }); }, []), setHasUnsavedChanges: useCallback((hasChanges: boolean) => { dispatch({ type: 'SET_UNSAVED_CHANGES', payload: { hasChanges } }); }, []), showNavigationWarning: useCallback((show: boolean) => { dispatch({ type: 'SHOW_NAVIGATION_WARNING', payload: { show } }); }, []), requestNavigation: useCallback((navigationFn: () => void) => { // If no unsaved changes, navigate immediately if (!state.hasUnsavedChanges) { navigationFn(); return; } // Otherwise, store the navigation and show warning dispatch({ type: 'SET_PENDING_NAVIGATION', payload: { navigationFn } }); dispatch({ type: 'SHOW_NAVIGATION_WARNING', payload: { show: true } }); }, [state.hasUnsavedChanges]), confirmNavigation: useCallback(() => { // Execute pending navigation if (state.pendingNavigation) { state.pendingNavigation(); } // Clear navigation state dispatch({ type: 'SET_PENDING_NAVIGATION', payload: { navigationFn: null } }); dispatch({ type: 'SHOW_NAVIGATION_WARNING', payload: { show: false } }); }, [state.pendingNavigation]), cancelNavigation: useCallback(() => { // Clear navigation without executing dispatch({ type: 'SET_PENDING_NAVIGATION', payload: { navigationFn: null } }); dispatch({ type: 'SHOW_NAVIGATION_WARNING', payload: { show: false } }); }, []) }; const stateValue: NavigationContextStateValue = { currentMode: state.currentMode, hasUnsavedChanges: state.hasUnsavedChanges, pendingNavigation: state.pendingNavigation, showNavigationWarning: state.showNavigationWarning }; const actionsValue: NavigationContextActionsValue = { actions }; // Enable URL synchronization useNavigationUrlSync(state.currentMode, actions.setMode, enableUrlSync); return ( {children} ); }; // Navigation hooks export const useNavigationState = () => { const context = useContext(NavigationStateContext); if (context === undefined) { throw new Error('useNavigationState must be used within NavigationProvider'); } return context; }; export const useNavigationActions = () => { const context = useContext(NavigationActionsContext); if (context === undefined) { throw new Error('useNavigationActions must be used within NavigationProvider'); } return context; }; // Combined hook for convenience export const useNavigation = () => { const state = useNavigationState(); const { actions } = useNavigationActions(); return { ...state, ...actions }; }; // Navigation guard hook (equivalent to old useFileNavigation) export const useNavigationGuard = () => { const state = useNavigationState(); const { actions } = useNavigationActions(); return { pendingNavigation: state.pendingNavigation, showNavigationWarning: state.showNavigationWarning, hasUnsavedChanges: state.hasUnsavedChanges, requestNavigation: actions.requestNavigation, confirmNavigation: actions.confirmNavigation, cancelNavigation: actions.cancelNavigation, setHasUnsavedChanges: actions.setHasUnsavedChanges, setShowNavigationWarning: actions.showNavigationWarning }; }; // Utility functions for mode handling export const isValidMode = (mode: string): mode is ModeType => { const validModes: ModeType[] = [ 'viewer', 'pageEditor', 'fileEditor', 'merge', 'split', 'compress', 'ocr', 'convert', 'addPassword', 'changePermissions', 'sanitize' ]; return validModes.includes(mode as ModeType); }; export const getDefaultMode = (): ModeType => 'pageEditor'; // TODO: This will be expanded for URL-based routing system // - URL parsing utilities // - Route definitions // - Navigation hooks with URL sync // - History management // - Breadcrumb restoration from URL params