Website (14 monoliths split): - compliance/page.tsx (1,519 → 9), docs/audit (1,262 → 20) - quality (1,231 → 16), alerts (1,203 → 10), docs (1,202 → 11) - i18n.ts (1,173 → 8 language files) - unity-bridge (1,094 → 12), backlog (1,087 → 6) - training (1,066 → 8), rag (1,063 → 8) - Deleted index_original.ts (4,899 LOC dead backup) Studio-v2 (5 monoliths split): - meet/page.tsx (1,481 → 9), messages (1,166 → 9) - AlertsB2BContext.tsx (1,165 → 5 modules) - alerts-b2b/page.tsx (1,019 → 6), korrektur/archiv (1,001 → 6) All existing imports preserved. Zero new TypeScript errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
111 lines
3.1 KiB
TypeScript
111 lines
3.1 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect } from 'react'
|
|
import type { BacklogItem } from './types'
|
|
import { initialBacklogItems } from './backlogData'
|
|
import { categories } from './categories'
|
|
|
|
export function useBacklog() {
|
|
const [items, setItems] = useState<BacklogItem[]>(initialBacklogItems)
|
|
const [selectedCategory, setSelectedCategory] = useState<string | null>(null)
|
|
const [selectedPriority, setSelectedPriority] = useState<string | null>(null)
|
|
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set())
|
|
const [searchQuery, setSearchQuery] = useState('')
|
|
|
|
// Load saved state from localStorage
|
|
useEffect(() => {
|
|
const saved = localStorage.getItem('backlogItems')
|
|
if (saved) {
|
|
try {
|
|
setItems(JSON.parse(saved))
|
|
} catch (e) {
|
|
console.error('Failed to load backlog items:', e)
|
|
}
|
|
}
|
|
}, [])
|
|
|
|
// Save state to localStorage
|
|
useEffect(() => {
|
|
localStorage.setItem('backlogItems', JSON.stringify(items))
|
|
}, [items])
|
|
|
|
const filteredItems = items.filter((item) => {
|
|
if (selectedCategory && item.category !== selectedCategory) return false
|
|
if (selectedPriority && item.priority !== selectedPriority) return false
|
|
if (searchQuery) {
|
|
const query = searchQuery.toLowerCase()
|
|
return (
|
|
item.title.toLowerCase().includes(query) ||
|
|
item.description.toLowerCase().includes(query) ||
|
|
item.subtasks?.some((st) => st.title.toLowerCase().includes(query))
|
|
)
|
|
}
|
|
return true
|
|
})
|
|
|
|
const toggleExpand = (id: string) => {
|
|
const newExpanded = new Set(expandedItems)
|
|
if (newExpanded.has(id)) {
|
|
newExpanded.delete(id)
|
|
} else {
|
|
newExpanded.add(id)
|
|
}
|
|
setExpandedItems(newExpanded)
|
|
}
|
|
|
|
const updateItemStatus = (id: string, status: BacklogItem['status']) => {
|
|
setItems(items.map((item) => (item.id === id ? { ...item, status } : item)))
|
|
}
|
|
|
|
const toggleSubtask = (itemId: string, subtaskId: string) => {
|
|
setItems(
|
|
items.map((item) => {
|
|
if (item.id !== itemId) return item
|
|
return {
|
|
...item,
|
|
subtasks: item.subtasks?.map((st) =>
|
|
st.id === subtaskId ? { ...st, completed: !st.completed } : st
|
|
),
|
|
}
|
|
})
|
|
)
|
|
}
|
|
|
|
const getProgress = () => {
|
|
const total = items.length
|
|
const completed = items.filter((i) => i.status === 'completed').length
|
|
return { total, completed, percentage: Math.round((completed / total) * 100) }
|
|
}
|
|
|
|
const getCategoryProgress = (categoryId: string) => {
|
|
const categoryItems = items.filter((i) => i.category === categoryId)
|
|
const completed = categoryItems.filter((i) => i.status === 'completed').length
|
|
return { total: categoryItems.length, completed }
|
|
}
|
|
|
|
const clearFilters = () => {
|
|
setSelectedCategory(null)
|
|
setSelectedPriority(null)
|
|
setSearchQuery('')
|
|
}
|
|
|
|
return {
|
|
items,
|
|
filteredItems,
|
|
selectedCategory,
|
|
setSelectedCategory,
|
|
selectedPriority,
|
|
setSelectedPriority,
|
|
expandedItems,
|
|
searchQuery,
|
|
setSearchQuery,
|
|
toggleExpand,
|
|
updateItemStatus,
|
|
toggleSubtask,
|
|
getProgress,
|
|
getCategoryProgress,
|
|
clearFilters,
|
|
categories,
|
|
}
|
|
}
|