import React, { createContext, useContext, useReducer, useEffect, useCallback, ReactNode } from 'react'; import { StrategyContext, CalendarContext, WorkflowProgress } from '../services/navigationOrchestrator'; // Context state interface interface StrategyCalendarState { activeStrategy: any | null; strategyContext: StrategyContext | null; calendarContext: CalendarContext | null; workflowProgress: WorkflowProgress; isContextValid: boolean; lastUpdated: string | null; error: string | null; } // Action types type StrategyCalendarAction = | { type: 'SET_ACTIVE_STRATEGY'; payload: any } | { type: 'SET_STRATEGY_CONTEXT'; payload: StrategyContext } | { type: 'SET_CALENDAR_CONTEXT'; payload: CalendarContext } | { type: 'UPDATE_WORKFLOW_PROGRESS'; payload: Partial } | { type: 'CLEAR_CONTEXT' } | { type: 'SET_ERROR'; payload: string } | { type: 'CLEAR_ERROR' } | { type: 'VALIDATE_CONTEXT' }; // Initial state const initialState: StrategyCalendarState = { activeStrategy: null, strategyContext: null, calendarContext: null, workflowProgress: { currentStep: 'strategy', completedSteps: [], totalSteps: 4, progressPercentage: 0 }, isContextValid: false, lastUpdated: null, error: null }; // Reducer function function strategyCalendarReducer(state: StrategyCalendarState, action: StrategyCalendarAction): StrategyCalendarState { switch (action.type) { case 'SET_ACTIVE_STRATEGY': return { ...state, activeStrategy: action.payload, lastUpdated: new Date().toISOString(), error: null }; case 'SET_STRATEGY_CONTEXT': return { ...state, strategyContext: action.payload, lastUpdated: new Date().toISOString(), error: null }; case 'SET_CALENDAR_CONTEXT': return { ...state, calendarContext: action.payload, lastUpdated: new Date().toISOString(), error: null }; case 'UPDATE_WORKFLOW_PROGRESS': return { ...state, workflowProgress: { ...state.workflowProgress, ...action.payload }, lastUpdated: new Date().toISOString() }; case 'CLEAR_CONTEXT': return { ...initialState, lastUpdated: new Date().toISOString() }; case 'SET_ERROR': return { ...state, error: action.payload, lastUpdated: new Date().toISOString() }; case 'CLEAR_ERROR': return { ...state, error: null }; case 'VALIDATE_CONTEXT': const isValid = validateContextIntegrity(state); return { ...state, isContextValid: isValid, lastUpdated: new Date().toISOString() }; default: return state; } } // Context validation function function validateContextIntegrity(state: StrategyCalendarState): boolean { try { // Check if strategy context exists and has required fields if (state.strategyContext) { const { strategyId, strategyData, activationStatus } = state.strategyContext; if (!strategyId || !strategyData || !activationStatus) { return false; } } // Check if calendar context is valid when it exists if (state.calendarContext) { const { strategyContext } = state.calendarContext; if (strategyContext && !validateContextIntegrity({ ...state, strategyContext })) { return false; } } // Check workflow progress validity const { currentStep, totalSteps, progressPercentage } = state.workflowProgress; if (!currentStep || totalSteps <= 0 || progressPercentage < 0 || progressPercentage > 100) { return false; } return true; } catch (error) { console.error('Context validation error:', error); return false; } } // Context interface interface StrategyCalendarContextType { state: StrategyCalendarState; dispatch: React.Dispatch; // Convenience methods setActiveStrategy: (strategy: any) => void; setStrategyContext: (context: StrategyContext) => void; setCalendarContext: (context: CalendarContext) => void; updateWorkflowProgress: (progress: Partial) => void; clearContext: () => void; setError: (error: string) => void; clearError: () => void; validateContext: () => void; // Utility methods getStrategyData: () => any | null; getCalendarData: () => any | null; isStrategyActive: () => boolean; isCalendarReady: () => boolean; getWorkflowStep: () => string; getProgressPercentage: () => number; isFromStrategyActivation: () => boolean; } // Create context const StrategyCalendarContext = createContext(undefined); // Provider component interface StrategyCalendarProviderProps { children: ReactNode; } export const StrategyCalendarProvider: React.FC = ({ children }) => { const [state, dispatch] = useReducer(strategyCalendarReducer, initialState); // Validate context on state changes useEffect(() => { dispatch({ type: 'VALIDATE_CONTEXT' }); }, [state.strategyContext, state.calendarContext, state.workflowProgress]); // Persist context to session storage useEffect(() => { if (state.lastUpdated) { try { sessionStorage.setItem('strategyCalendarContext', JSON.stringify({ strategyContext: state.strategyContext, calendarContext: state.calendarContext, workflowProgress: state.workflowProgress, lastUpdated: state.lastUpdated })); } catch (error) { console.error('Failed to persist context to session storage:', error); } } }, [state.strategyContext, state.calendarContext, state.workflowProgress, state.lastUpdated]); // Restore context from session storage on mount useEffect(() => { try { const persisted = sessionStorage.getItem('strategyCalendarContext'); if (persisted) { const data = JSON.parse(persisted); const lastUpdated = new Date(data.lastUpdated); const now = new Date(); // Check if context is still valid (not older than 30 minutes) if (now.getTime() - lastUpdated.getTime() < 30 * 60 * 1000) { if (data.strategyContext) { dispatch({ type: 'SET_STRATEGY_CONTEXT', payload: data.strategyContext }); } if (data.calendarContext) { dispatch({ type: 'SET_CALENDAR_CONTEXT', payload: data.calendarContext }); } if (data.workflowProgress) { dispatch({ type: 'UPDATE_WORKFLOW_PROGRESS', payload: data.workflowProgress }); } } else { // Clear expired context sessionStorage.removeItem('strategyCalendarContext'); } } } catch (error) { console.error('Failed to restore context from session storage:', error); } }, []); // Convenience methods const setActiveStrategy = (strategy: any) => { dispatch({ type: 'SET_ACTIVE_STRATEGY', payload: strategy }); }; const setStrategyContext = (context: StrategyContext) => { dispatch({ type: 'SET_STRATEGY_CONTEXT', payload: context }); }; const setCalendarContext = (context: CalendarContext) => { dispatch({ type: 'SET_CALENDAR_CONTEXT', payload: context }); }; const updateWorkflowProgress = (progress: Partial) => { dispatch({ type: 'UPDATE_WORKFLOW_PROGRESS', payload: progress }); }; const clearContext = () => { dispatch({ type: 'CLEAR_CONTEXT' }); sessionStorage.removeItem('strategyCalendarContext'); }; const setError = (error: string) => { dispatch({ type: 'SET_ERROR', payload: error }); }; const clearError = () => { dispatch({ type: 'CLEAR_ERROR' }); }; const validateContext = () => { dispatch({ type: 'VALIDATE_CONTEXT' }); }; // Utility methods const getStrategyData = () => state.strategyContext?.strategyData || null; const getCalendarData = () => state.calendarContext?.autoPopulatedData || null; const isStrategyActive = () => state.strategyContext?.activationStatus === 'active'; const isCalendarReady = () => { return state.calendarContext !== null && state.calendarContext.autoPopulatedData !== null && state.isContextValid; }; const getWorkflowStep = () => state.workflowProgress.currentStep; const getProgressPercentage = () => state.workflowProgress.progressPercentage; const isFromStrategyActivation = useCallback(() => { // Check if we have a preserved strategy context from navigation const result = state.strategyContext?.activationStatus === 'active' && state.strategyContext?.activationTimestamp !== null; return result; }, [state.strategyContext?.activationStatus, state.strategyContext?.activationTimestamp]); const contextValue: StrategyCalendarContextType = { state, dispatch, setActiveStrategy, setStrategyContext, setCalendarContext, updateWorkflowProgress, clearContext, setError, clearError, validateContext, getStrategyData, getCalendarData, isStrategyActive, isCalendarReady, getWorkflowStep, getProgressPercentage, isFromStrategyActivation }; return ( {children} ); }; // Custom hook to use the context export const useStrategyCalendarContext = (): StrategyCalendarContextType => { const context = useContext(StrategyCalendarContext); if (context === undefined) { throw new Error('useStrategyCalendarContext must be used within a StrategyCalendarProvider'); } return context; }; // Hook for components that only need read access export const useStrategyCalendarState = () => { const { state } = useStrategyCalendarContext(); return state; }; // Hook for components that need to dispatch actions export const useStrategyCalendarActions = () => { const { setActiveStrategy, setStrategyContext, setCalendarContext, updateWorkflowProgress, clearContext, setError, clearError, validateContext } = useStrategyCalendarContext(); return { setActiveStrategy, setStrategyContext, setCalendarContext, updateWorkflowProgress, clearContext, setError, clearError, validateContext }; };