Python (6 files in klausur-service): - rbac.py (1,132 → 4), admin_api.py (1,012 → 4) - routes/eh.py (1,111 → 4), ocr_pipeline_geometry.py (1,105 → 5) Python (2 files in backend-lehrer): - unit_api.py (1,226 → 6), game_api.py (1,129 → 5) Website (6 page files): - 4x klausur-korrektur pages (1,249-1,328 LOC each) → shared components in website/components/klausur-korrektur/ (17 shared files) - companion (1,057 → 10), magic-help (1,017 → 8) All re-export barrels preserve backward compatibility. Zero import errors verified. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
98 lines
3.7 KiB
TypeScript
98 lines
3.7 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect } from 'react'
|
|
import type { Feature, TeacherFeedback } from './types'
|
|
import { initialFeatures, initialFeedback, roadmapPhases } from './data'
|
|
|
|
// Data version - increment when adding new features/feedback to force refresh
|
|
const DATA_VERSION = '8.2.0' // Phase 8e: Frontend UI-Komponenten (ContextBar, Sidebar, PathPanel)
|
|
|
|
export function useCompanionDev() {
|
|
const [features, setFeatures] = useState<Feature[]>(initialFeatures)
|
|
const [feedback, setFeedback] = useState<TeacherFeedback[]>(initialFeedback)
|
|
const [activeTab, setActiveTab] = useState<'roadmap' | 'features' | 'feedback' | 'backlog'>('roadmap')
|
|
const [selectedPhase, setSelectedPhase] = useState<string | null>(null)
|
|
const [feedbackFilter, setFeedbackFilter] = useState<string>('all')
|
|
|
|
// Load from localStorage with version check
|
|
useEffect(() => {
|
|
const savedVersion = localStorage.getItem('companion-dev-version')
|
|
const savedFeatures = localStorage.getItem('companion-dev-features')
|
|
const savedFeedback = localStorage.getItem('companion-dev-feedback')
|
|
|
|
// If version mismatch or no version, use initial data and save new version
|
|
if (savedVersion !== DATA_VERSION) {
|
|
console.log(`Companion Dev: Data version updated from ${savedVersion} to ${DATA_VERSION}`)
|
|
localStorage.setItem('companion-dev-version', DATA_VERSION)
|
|
localStorage.setItem('companion-dev-features', JSON.stringify(initialFeatures))
|
|
localStorage.setItem('companion-dev-feedback', JSON.stringify(initialFeedback))
|
|
// State already initialized with initialFeatures/initialFeedback, no need to setFeatures
|
|
return
|
|
}
|
|
|
|
// Load saved data if version matches
|
|
if (savedFeatures) setFeatures(JSON.parse(savedFeatures))
|
|
if (savedFeedback) setFeedback(JSON.parse(savedFeedback))
|
|
}, [])
|
|
|
|
// Save to localStorage
|
|
useEffect(() => {
|
|
localStorage.setItem('companion-dev-features', JSON.stringify(features))
|
|
}, [features])
|
|
|
|
useEffect(() => {
|
|
localStorage.setItem('companion-dev-feedback', JSON.stringify(feedback))
|
|
}, [feedback])
|
|
|
|
const getPhaseStats = () => {
|
|
const total = roadmapPhases.length
|
|
const completed = roadmapPhases.filter(p => p.status === 'completed').length
|
|
const inProgress = roadmapPhases.filter(p => p.status === 'in_progress').length
|
|
return { total, completed, inProgress }
|
|
}
|
|
|
|
const getFeatureStats = () => {
|
|
const total = features.length
|
|
const done = features.filter(f => f.status === 'done').length
|
|
const inProgress = features.filter(f => f.status === 'in_progress').length
|
|
return { total, done, inProgress, percentage: Math.round((done / total) * 100) }
|
|
}
|
|
|
|
const getFeedbackStats = () => {
|
|
const total = feedback.length
|
|
const newCount = feedback.filter(f => f.status === 'new').length
|
|
const bugs = feedback.filter(f => f.type === 'bug').length
|
|
const requests = feedback.filter(f => f.type === 'feature_request').length
|
|
return { total, newCount, bugs, requests }
|
|
}
|
|
|
|
const updateFeatureStatus = (id: string, status: Feature['status']) => {
|
|
setFeatures(features.map(f => f.id === id ? { ...f, status } : f))
|
|
}
|
|
|
|
const updateFeedbackStatus = (id: string, status: TeacherFeedback['status']) => {
|
|
setFeedback(feedback.map(f => f.id === id ? { ...f, status } : f))
|
|
}
|
|
|
|
const filteredFeedback = feedbackFilter === 'all'
|
|
? feedback
|
|
: feedback.filter(f => f.type === feedbackFilter || f.status === feedbackFilter)
|
|
|
|
return {
|
|
features,
|
|
feedback,
|
|
activeTab,
|
|
setActiveTab,
|
|
selectedPhase,
|
|
setSelectedPhase,
|
|
feedbackFilter,
|
|
setFeedbackFilter,
|
|
phaseStats: getPhaseStats(),
|
|
featureStats: getFeatureStats(),
|
|
feedbackStats: getFeedbackStats(),
|
|
updateFeatureStatus,
|
|
updateFeedbackStatus,
|
|
filteredFeedback,
|
|
}
|
|
}
|