import { useCallback, useEffect, useState } from 'react' import { useInitiativeOperations } from '../../context/InitiativeOperationsContext.jsx' import { listInitiativeJourney } from '../../api/journey.js' import { listInitiativeRoadmapCriteriaProgress, listInitiativeRoadmapGraphState, listRoadmapItemCriteria, } from '../../api/roadmap.js' import { DecisionsSection } from '../../components/DecisionsSection.jsx' import { ReviewsSection } from '../../components/ReviewsSection.jsx' import { RecurringSection } from '../../components/RecurringSection.jsx' import { EvidenceSection } from '../../components/EvidenceSection.jsx' import { JourneyTimeline } from '../../components/JourneyTimeline.jsx' import { JourneyGateProgressSection, sortGatesForJourney } from '../../components/JourneyGateProgressSection.jsx' import { JourneyGateMapSection } from '../../components/JourneyGateMapSection.jsx' export function InitiativeJourneyPage() { const ops = useInitiativeOperations() const { id, capabilities, error, formBusy, roadmapItems } = ops const [journeyEvents, setJourneyEvents] = useState([]) const [journeyLoading, setJourneyLoading] = useState(true) const [journeyError, setJourneyError] = useState(null) const [graphState, setGraphState] = useState(null) const [criteriaProgress, setCriteriaProgress] = useState({}) const [criteriaByGate, setCriteriaByGate] = useState({}) const [gateMetaLoading, setGateMetaLoading] = useState(true) const loadJourney = useCallback(async () => { if (!id) return setJourneyLoading(true) setJourneyError(null) try { const data = await listInitiativeJourney(id) setJourneyEvents(data.events || []) } catch (err) { setJourneyError(err.message) } finally { setJourneyLoading(false) } }, [id]) useEffect(() => { if (!id || !roadmapItems.length) { setGraphState(null) setCriteriaProgress({}) setCriteriaByGate({}) setGateMetaLoading(false) return undefined } let cancelled = false setGateMetaLoading(true) Promise.all([ listInitiativeRoadmapGraphState(id), listInitiativeRoadmapCriteriaProgress(id), ]) .then(async ([graph, progress]) => { if (cancelled) return setGraphState(graph || null) setCriteriaProgress(progress || {}) const sortedFocus = sortGatesForJourney(roadmapItems, graph || null) .slice(0, 5) .map((item) => item.id) const criteriaEntries = await Promise.all( sortedFocus.map((gateId) => listRoadmapItemCriteria(gateId) .then((criteria) => [gateId, Array.isArray(criteria) ? criteria : []]) .catch(() => [gateId, []]), ), ) if (cancelled) return setCriteriaByGate(Object.fromEntries(criteriaEntries)) }) .catch(() => { if (!cancelled) { setGraphState(null) setCriteriaProgress({}) setCriteriaByGate({}) } }) .finally(() => { if (!cancelled) setGateMetaLoading(false) }) return () => { cancelled = true } }, [id, roadmapItems]) useEffect(() => { loadJourney() }, [loadJourney, ops.decisions, ops.reviews, ops.evidenceItems, ops.actions]) if (!capabilities.has('kairo.initiative.read')) { return null } return ( <> {error &&

{error}

}

Journey

Chronologie aus Entscheidungen, Nachweisen, committeter Arbeit und Zielzuständen — Plan/Ist nachvollziehbar.

{journeyError &&

{journeyError}

} {journeyLoading ? (

Timeline wird geladen…

) : ( )}
) }