import { useCallback, useEffect, useState } from 'react' import { Link, useParams } from 'react-router-dom' import { getInitiative, listInitiativeActions, createInitiativeAction, } from '../api/initiatives.js' import { updateAction, setActionAssignments } from '../api/actions.js' import { listInitiativeBlockers, createInitiativeBlocker, updateBlocker, deleteBlocker, } from '../api/blockers.js' import { listInitiativeBacklog, createInitiativeBacklogItem, updateBacklogItem, deleteBacklogItem, convertBacklogToAction, } from '../api/backlog.js' import { listInitiativeMilestones, createInitiativeMilestone, updateMilestone, deleteMilestone, } from '../api/milestones.js' import { ACTION_STATUS_LABELS } from '../constants/status.js' import { StatusBadge } from '../components/StatusBadge.jsx' import { PriorityBadge } from '../components/PriorityBadge.jsx' import { ActionForm } from '../components/ActionForm.jsx' import { BlockersSection } from '../components/BlockersSection.jsx' import { BacklogSection } from '../components/BacklogSection.jsx' import { MilestonesSection } from '../components/MilestonesSection.jsx' import { EmptyState } from '../components/EmptyState.jsx' import { ErrorState } from '../components/ErrorState.jsx' import { LoadingState } from '../components/LoadingState.jsx' import { useCapabilities } from '../hooks/useCapabilities.js' import { useActors } from '../hooks/useActors.js' import { useSession } from '../context/SessionContext.jsx' export function InitiativeDetailPage() { const { id } = useParams() const { context } = useSession() const { capabilities } = useCapabilities() const { actors, loading: actorsLoading, error: actorsError, usedFallback: actorsUsedFallback, reload: reloadActors, } = useActors() const [initiative, setInitiative] = useState(null) const [actions, setActions] = useState([]) const [blockers, setBlockers] = useState([]) const [backlogItems, setBacklogItems] = useState([]) const [milestones, setMilestones] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [showActionForm, setShowActionForm] = useState(false) const [editingAction, setEditingAction] = useState(null) const [formBusy, setFormBusy] = useState(false) const [hideDone, setHideDone] = useState(true) const load = useCallback(async () => { setLoading(true) setError(null) try { const [initData, actionData] = await Promise.all([ getInitiative(id), listInitiativeActions(id), ]) setInitiative(initData) setActions(actionData) const loads = [] if (capabilities.has('kairo.blocker.read')) { loads.push(listInitiativeBlockers(id).then(setBlockers).catch(() => setBlockers([]))) } if (capabilities.has('kairo.backlog.read')) { loads.push(listInitiativeBacklog(id).then(setBacklogItems).catch(() => setBacklogItems([]))) } if (capabilities.has('kairo.milestone.read')) { loads.push(listInitiativeMilestones(id).then(setMilestones).catch(() => setMilestones([]))) } await Promise.all(loads) } catch (err) { setError(err.message) } finally { setLoading(false) } }, [id, capabilities]) useEffect(() => { load() }, [load]) const visibleActions = hideDone ? actions.filter((a) => a.status !== 'done' && a.status !== 'discarded') : actions async function handleCreateAction(payload) { setFormBusy(true) try { const assigned = payload.assigned_actor_ids?.length > 0 ? payload.assigned_actor_ids : context?.actor?.id ? [context.actor.id] : [] await createInitiativeAction(id, { ...payload, assigned_actor_ids: assigned }) setShowActionForm(false) await load() } catch (err) { setError(err.message) } finally { setFormBusy(false) } } async function handleUpdateAction(actionId, payload) { setFormBusy(true) try { await updateAction(actionId, { title: payload.title, description: payload.description, status: payload.status, priority: payload.priority, }) if (capabilities.has('kairo.action.manage')) { await setActionAssignments(actionId, payload.assigned_actor_ids || []) } setEditingAction(null) await load() } catch (err) { setError(err.message) } finally { setFormBusy(false) } } async function handleQuickStatus(action, status) { if (!capabilities.has('kairo.action.manage')) return try { await updateAction(action.id, { status }) await load() } catch (err) { setError(err.message) } } async function handleCreateBlocker(body) { setFormBusy(true) try { await createInitiativeBlocker(id, body) await load() } catch (err) { setError(err.message) } finally { setFormBusy(false) } } async function handleBlockerStatus(blockerId, status) { try { await updateBlocker(blockerId, { status }) await load() } catch (err) { setError(err.message) } } async function handleDeleteBlocker(blockerId) { try { await deleteBlocker(blockerId) await load() } catch (err) { setError(err.message) } } async function handleCreateBacklog(body) { setFormBusy(true) try { await createInitiativeBacklogItem(id, body) await load() } catch (err) { setError(err.message) } finally { setFormBusy(false) } } async function handleBacklogStatus(itemId, status) { try { await updateBacklogItem(itemId, { status }) await load() } catch (err) { setError(err.message) } } async function handleConvertBacklog(itemId) { setFormBusy(true) try { await convertBacklogToAction(itemId) await load() } catch (err) { setError(err.message) } finally { setFormBusy(false) } } async function handleDeleteBacklog(itemId) { try { await deleteBacklogItem(itemId) await load() } catch (err) { setError(err.message) } } async function handleCreateMilestone(body) { setFormBusy(true) try { await createInitiativeMilestone(id, body) await load() } catch (err) { setError(err.message) } finally { setFormBusy(false) } } async function handleMilestoneStatus(milestoneId, status) { try { await updateMilestone(milestoneId, { status }) await load() } catch (err) { setError(err.message) } } async function handleDeleteMilestone(milestoneId) { try { await deleteMilestone(milestoneId) await load() } catch (err) { setError(err.message) } } if (loading) { return (
) } if (error && !initiative) { return (
) } if (!initiative) { return (
) } return (

{initiative.title}

{initiative.goal &&

{initiative.goal}

}
{error &&

{error}

}

Maßnahmen

{capabilities.has('kairo.action.manage') && ( )}
{showActionForm && (
setShowActionForm(false)} busy={formBusy} submitLabel="Maßnahme anlegen" />
)} {visibleActions.length === 0 && ( )}
    {visibleActions.map((action) => (
  • {editingAction === action.id ? ( handleUpdateAction(action.id, payload)} onCancel={() => setEditingAction(null)} busy={formBusy} submitLabel="Speichern" /> ) : ( <>
    {action.title} {action.description && (

    {action.description}

    )} {action.assigned_actor_ids?.length > 0 && (

    Zugewiesen: {action.assigned_actor_ids.length} Actor(s)

    )}
    {capabilities.has('kairo.action.manage') && ( <> )}
    )}
  • ))}
{capabilities.has('kairo.milestone.read') && ( )} {capabilities.has('kairo.backlog.read') && ( )} {capabilities.has('kairo.blocker.read') && ( )}
) }