Kairo-Jinkendo/frontend/src/components/PlanOutlineNav.jsx

106 lines
3.4 KiB
React
Raw Normal View History

import { NavLink, useLocation } from 'react-router-dom'
import { useEffect, useState } from 'react'
import { listInitiativeActions } from '../api/initiatives.js'
import { listInitiativeBacklog } from '../api/backlog.js'
import { useProgramScope } from '../context/ProgramScopeContext.jsx'
import {
PLAN_OUTLINE_NODES,
resolvePlanOutlineActiveKey,
} from '../plan/planOutlineNodes.js'
export function PlanOutlineNav() {
const location = useLocation()
const { initiativeId, initiativeTitle, hrefWithScope } = useProgramScope()
const activeKey = resolvePlanOutlineActiveKey(location.pathname)
const [counts, setCounts] = useState({ inbox: null, work: null })
useEffect(() => {
if (!initiativeId) {
setCounts({ inbox: null, work: null })
return undefined
}
let cancelled = false
Promise.all([
listInitiativeBacklog(initiativeId).catch(() => []),
listInitiativeActions(initiativeId).catch(() => []),
]).then(([backlog, actions]) => {
if (cancelled) return
setCounts({
inbox: backlog.filter((item) => item.status !== 'converted').length,
work: actions.filter(
(action) => action.status !== 'done' && action.status !== 'discarded',
).length,
})
})
return () => {
cancelled = true
}
}, [initiativeId, location.pathname])
function nodeLabel(node) {
if (node.key === 'inbox' && counts.inbox != null) {
return `${node.label} (${counts.inbox})`
}
if (node.key === 'work' && counts.work != null) {
return `${node.label} (${counts.work})`
}
return node.label
}
return (
<nav className="analysis-split__nav" aria-label="Plan-Navigation">
<div className="analysis-split__nav-header">
<span className="analysis-split__nav-eyebrow">Planen</span>
{initiativeId ? (
<p className="analysis-split__nav-scope" title={initiativeTitle || initiativeId}>
{initiativeTitle || 'Vorhaben'}
</p>
) : (
<p className="analysis-split__nav-scope analysis-split__nav-scope--muted">
Portfolio — Vorhaben wählen
</p>
)}
</div>
<ul className="analysis-split__nav-list">
{PLAN_OUTLINE_NODES.map((node) => {
const needsInitiative = node.requiresInitiative && !initiativeId
const isDisabled = node.disabled || needsInitiative
if (isDisabled) {
return (
<li key={node.key}>
<span
className={
'analysis-split__nav-link analysis-split__nav-link--disabled' +
(activeKey === node.key ? ' analysis-split__nav-link--active' : '')
}
aria-disabled="true"
title={needsInitiative ? 'Vorhaben im Scope wählen' : node.hint}
>
{nodeLabel(node)}
</span>
</li>
)
}
return (
<li key={node.key}>
<NavLink
to={hrefWithScope(node.to)}
end
className={({ isActive }) =>
'analysis-split__nav-link' +
(isActive ? ' analysis-split__nav-link--active' : '')
}
>
{nodeLabel(node)}
</NavLink>
</li>
)
})}
</ul>
</nav>
)
}