import { useEffect, useMemo, useState } from 'react' import { Link, useNavigate } from 'react-router-dom' import { FaTimes } from 'react-icons/fa' import { IconRoute, IconPlus, IconTrash, IconTicket } from '@tabler/icons-react' import { PageHeader, Card, Button, Badge, EmptyState, Field } from '../components/ui' import { useAuth } from '../context/AuthContext' import { useRoadmaps } from '../hooks/useRoadmaps' import { useWebsiteProjects } from '../hooks/useWebsiteProjects' import { fetchRoadmapNodes, computeProgress, ROADMAP_STATUS } from '../lib/roadmaps' import RoadmapProgress from '../components/roadmap/RoadmapProgressBar' export default function RoadmapsPage() { const { user } = useAuth() const navigate = useNavigate() const { roadmaps, loading, fetchAll, createRoadmap, deleteRoadmap } = useRoadmaps() const { fetchAllProjects } = useWebsiteProjects() const [projects, setProjects] = useState([]) const [progressById, setProgressById] = useState({}) const [showCreate, setShowCreate] = useState(false) const [form, setForm] = useState({ projectId: '', title: '', goalTitle: '' }) const [creating, setCreating] = useState(false) const [error, setError] = useState('') useEffect(() => { let cancelled = false async function load() { const [allProjects, allRoadmaps] = await Promise.all([fetchAllProjects(), fetchAll()]) if (cancelled) return setProjects(allProjects.filter((p) => !p.isTemplate && !p.archived)) const active = allRoadmaps.filter((r) => r.status === ROADMAP_STATUS.ACTIVE) const entries = await Promise.all(active.map(async (r) => { try { return [r.$id, computeProgress(await fetchRoadmapNodes(r.$id))] } catch { return [r.$id, null] } })) if (!cancelled) setProgressById(Object.fromEntries(entries.filter(([, p]) => p))) } load() return () => { cancelled = true } }, [fetchAll, fetchAllProjects]) const activeRoadmaps = roadmaps.filter((r) => r.status === ROADMAP_STATUS.ACTIVE) const completedRoadmaps = roadmaps.filter((r) => r.status === ROADMAP_STATUS.COMPLETED) // Nur Projekte ohne aktiven Plan anbieten (genau 1 aktiver Plan pro Projekt) const availableProjects = useMemo(() => { const withActivePlan = new Set(activeRoadmaps.map((r) => r.projectId)) return projects.filter((p) => !withActivePlan.has(p.$id)) }, [projects, activeRoadmaps]) const openCreate = () => { setForm({ projectId: availableProjects[0]?.$id || '', title: '', goalTitle: '' }) setError('') setShowCreate(true) } const handleCreate = async (e) => { e.preventDefault() const project = projects.find((p) => p.$id === form.projectId) if (!project) { setError('Bitte ein Projekt auswaehlen.') return } setCreating(true) setError('') const result = await createRoadmap(project, { title: form.title.trim(), goalTitle: form.goalTitle.trim() }, user) setCreating(false) if (!result.success) { setError(result.error) return } setShowCreate(false) navigate(`/roadmaps/${result.data.roadmap.$id}`) } const handleDelete = async (roadmap) => { const ok = window.confirm( `Plan "${roadmap.title}" wirklich loeschen?\n\n` + `Alle Knoten werden entfernt und das Projektticket (WOID ${roadmap.woid || '-'}) wird abgebrochen.` ) if (!ok) return const result = await deleteRoadmap(roadmap, user) if (!result.success) window.alert(`Loeschen fehlgeschlagen: ${result.error}`) } const renderRoadmapCard = (roadmap) => { const progress = progressById[roadmap.$id] return (
{roadmap.title}
Projekt: {roadmap.projectName || '-'} {roadmap.customerName ? ` · Kunde: ${roadmap.customerName}` : ''}
{roadmap.woid && (
Projektticket WOID {roadmap.woid}
)}
{roadmap.status === ROADMAP_STATUS.COMPLETED ? Abgeschlossen : progress && }
{roadmap.status === ROADMAP_STATUS.ACTIVE && ( )}
) } return (
Plan erstellen } /> {loading && !roadmaps.length ? (

Lade Roadmaps…

) : ( <> {!activeRoadmaps.length ? ( } title="Noch keine aktiven Plaene" hint="Erstelle zu einem Projekt einen Plan — das zugehoerige Projektticket wird automatisch angelegt." action={availableProjects.length ? : null} /> ) : (
{activeRoadmaps.map(renderRoadmapCard)}
)} {completedRoadmaps.length > 0 && ( <>

Archiv

{completedRoadmaps.map(renderRoadmapCard)}
)} )} {showCreate && (
setShowCreate(false)}>

Neuen Plan erstellen

Zum Plan wird automatisch ein Projektticket erstellt, in dem der Fortschritt getrackt wird.

setForm((f) => ({ ...f, title: e.target.value }))} /> setForm((f) => ({ ...f, goalTitle: e.target.value }))} /> {error &&

{error}

}
)}
) }