'use client' import { createContext, useContext, useReducer, useCallback, ReactNode, } from 'react' import { AOIResponse, AOITheme, AOIQuality, Difficulty, GeoJSONPolygon, LearningNode, GeoLernweltState, } from '@/app/geo-lernwelt/types' // Initial state const initialState: GeoLernweltState = { currentAOI: null, drawnPolygon: null, selectedTheme: 'topographie', quality: 'medium', difficulty: 'mittel', learningNodes: [], selectedNode: null, isDrawing: false, isLoading: false, error: null, unityReady: false, unityProgress: 0, } // Action types type GeoAction = | { type: 'SET_AOI'; payload: AOIResponse | null } | { type: 'SET_POLYGON'; payload: GeoJSONPolygon | null } | { type: 'SET_THEME'; payload: AOITheme } | { type: 'SET_QUALITY'; payload: AOIQuality } | { type: 'SET_DIFFICULTY'; payload: Difficulty } | { type: 'SET_LEARNING_NODES'; payload: LearningNode[] } | { type: 'ADD_LEARNING_NODE'; payload: LearningNode } | { type: 'UPDATE_LEARNING_NODE'; payload: LearningNode } | { type: 'REMOVE_LEARNING_NODE'; payload: string } | { type: 'SELECT_NODE'; payload: LearningNode | null } | { type: 'SET_DRAWING'; payload: boolean } | { type: 'SET_LOADING'; payload: boolean } | { type: 'SET_ERROR'; payload: string | null } | { type: 'SET_UNITY_READY'; payload: boolean } | { type: 'SET_UNITY_PROGRESS'; payload: number } | { type: 'RESET' } // Reducer function geoReducer(state: GeoLernweltState, action: GeoAction): GeoLernweltState { switch (action.type) { case 'SET_AOI': return { ...state, currentAOI: action.payload } case 'SET_POLYGON': return { ...state, drawnPolygon: action.payload } case 'SET_THEME': return { ...state, selectedTheme: action.payload } case 'SET_QUALITY': return { ...state, quality: action.payload } case 'SET_DIFFICULTY': return { ...state, difficulty: action.payload } case 'SET_LEARNING_NODES': return { ...state, learningNodes: action.payload } case 'ADD_LEARNING_NODE': return { ...state, learningNodes: [...state.learningNodes, action.payload], } case 'UPDATE_LEARNING_NODE': return { ...state, learningNodes: state.learningNodes.map((node) => node.id === action.payload.id ? action.payload : node ), } case 'REMOVE_LEARNING_NODE': return { ...state, learningNodes: state.learningNodes.filter( (node) => node.id !== action.payload ), selectedNode: state.selectedNode?.id === action.payload ? null : state.selectedNode, } case 'SELECT_NODE': return { ...state, selectedNode: action.payload } case 'SET_DRAWING': return { ...state, isDrawing: action.payload } case 'SET_LOADING': return { ...state, isLoading: action.payload } case 'SET_ERROR': return { ...state, error: action.payload } case 'SET_UNITY_READY': return { ...state, unityReady: action.payload } case 'SET_UNITY_PROGRESS': return { ...state, unityProgress: action.payload } case 'RESET': return initialState default: return state } } // Context types interface GeoContextValue { state: GeoLernweltState dispatch: React.Dispatch // Convenience actions setAOI: (aoi: AOIResponse | null) => void setPolygon: (polygon: GeoJSONPolygon | null) => void setTheme: (theme: AOITheme) => void setQuality: (quality: AOIQuality) => void setDifficulty: (difficulty: Difficulty) => void setLearningNodes: (nodes: LearningNode[]) => void addNode: (node: LearningNode) => void updateNode: (node: LearningNode) => void removeNode: (nodeId: string) => void selectNode: (node: LearningNode | null) => void setDrawing: (drawing: boolean) => void setLoading: (loading: boolean) => void setError: (error: string | null) => void setUnityReady: (ready: boolean) => void setUnityProgress: (progress: number) => void reset: () => void } // Create context const GeoContext = createContext(null) // Provider component export function GeoProvider({ children }: { children: ReactNode }) { const [state, dispatch] = useReducer(geoReducer, initialState) // Convenience action creators const setAOI = useCallback( (aoi: AOIResponse | null) => dispatch({ type: 'SET_AOI', payload: aoi }), [] ) const setPolygon = useCallback( (polygon: GeoJSONPolygon | null) => dispatch({ type: 'SET_POLYGON', payload: polygon }), [] ) const setTheme = useCallback( (theme: AOITheme) => dispatch({ type: 'SET_THEME', payload: theme }), [] ) const setQuality = useCallback( (quality: AOIQuality) => dispatch({ type: 'SET_QUALITY', payload: quality }), [] ) const setDifficulty = useCallback( (difficulty: Difficulty) => dispatch({ type: 'SET_DIFFICULTY', payload: difficulty }), [] ) const setLearningNodes = useCallback( (nodes: LearningNode[]) => dispatch({ type: 'SET_LEARNING_NODES', payload: nodes }), [] ) const addNode = useCallback( (node: LearningNode) => dispatch({ type: 'ADD_LEARNING_NODE', payload: node }), [] ) const updateNode = useCallback( (node: LearningNode) => dispatch({ type: 'UPDATE_LEARNING_NODE', payload: node }), [] ) const removeNode = useCallback( (nodeId: string) => dispatch({ type: 'REMOVE_LEARNING_NODE', payload: nodeId }), [] ) const selectNode = useCallback( (node: LearningNode | null) => dispatch({ type: 'SELECT_NODE', payload: node }), [] ) const setDrawing = useCallback( (drawing: boolean) => dispatch({ type: 'SET_DRAWING', payload: drawing }), [] ) const setLoading = useCallback( (loading: boolean) => dispatch({ type: 'SET_LOADING', payload: loading }), [] ) const setError = useCallback( (error: string | null) => dispatch({ type: 'SET_ERROR', payload: error }), [] ) const setUnityReady = useCallback( (ready: boolean) => dispatch({ type: 'SET_UNITY_READY', payload: ready }), [] ) const setUnityProgress = useCallback( (progress: number) => dispatch({ type: 'SET_UNITY_PROGRESS', payload: progress }), [] ) const reset = useCallback(() => dispatch({ type: 'RESET' }), []) const value: GeoContextValue = { state, dispatch, setAOI, setPolygon, setTheme, setQuality, setDifficulty, setLearningNodes, addNode, updateNode, removeNode, selectNode, setDrawing, setLoading, setError, setUnityReady, setUnityProgress, reset, } return {children} } // Hook to use context export function useGeo() { const context = useContext(GeoContext) if (!context) { throw new Error('useGeo must be used within a GeoProvider') } return context } // Hook for just the state (read-only) export function useGeoState() { const { state } = useGeo() return state }