fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
276
studio-v2/lib/geo-lernwelt/GeoContext.tsx
Normal file
276
studio-v2/lib/geo-lernwelt/GeoContext.tsx
Normal file
@@ -0,0 +1,276 @@
|
||||
'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
|
||||
}
|
||||
Reference in New Issue
Block a user