Files
breakpilot-lehrer/studio-v2/lib/geo-lernwelt/GeoContext.tsx
Benjamin Boenisch 5a31f52310 Initial commit: breakpilot-lehrer - Lehrer KI Platform
Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website,
Klausur-Service, School-Service, Voice-Service, Geo-Service,
BreakPilot Drive, Agent-Core

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 23:47:26 +01:00

277 lines
6.9 KiB
TypeScript

'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<GeoAction>
// 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<GeoContextValue | null>(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 <GeoContext.Provider value={value}>{children}</GeoContext.Provider>
}
// 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
}