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

171 lines
5.6 KiB
React
Raw Normal View History

import { Link } from 'react-router-dom'
import { useMemo, useState } from 'react'
import { EmptyState } from './EmptyState.jsx'
import { StatusBadge } from './StatusBadge.jsx'
import { PriorityBadge } from './PriorityBadge.jsx'
import { Modal } from './Modal.jsx'
import { ActionForm } from './ActionForm.jsx'
import { ActionTaskPanel } from './ActionTaskPanel.jsx'
import { gateTitleById } from './GateSelect.jsx'
import { buildProjectPath, collectProjectSubtreeIds } from '../utils/projectTree.js'
import { actionPath } from '../utils/routes.js'
function formatProjectContext(projects, projectId) {
if (!projectId) return 'Direkt am Vorhaben'
const path = buildProjectPath(projects, projectId)
return path.map((p) => p.title).join(' → ')
}
export function PlanActionsSection({
actions,
projects = [],
roadmapItems = [],
scopeProjectId = '',
hideDone,
onHideDoneChange,
canManage,
onCreateAction,
actors,
actorsLoading,
actorsError,
actorsUsedFallback,
onReloadActors,
busy,
}) {
const [showCreate, setShowCreate] = useState(false)
const [expandedActions, setExpandedActions] = useState(() => new Set())
const visibleActions = useMemo(() => {
let list = hideDone
? actions.filter((a) => a.status !== 'done' && a.status !== 'discarded')
: [...actions]
if (scopeProjectId) {
const subtreeIds = collectProjectSubtreeIds(projects, scopeProjectId)
list = list.filter((a) => a.project_id && subtreeIds.has(a.project_id))
}
return list.sort((a, b) => {
const projectA = a.project_id || ''
const projectB = b.project_id || ''
if (projectA !== projectB) {
if (!projectA) return -1
if (!projectB) return 1
return projectA.localeCompare(projectB)
}
return (a.title || '').localeCompare(b.title || '')
})
}, [actions, hideDone, scopeProjectId, projects])
async function handleCreate(payload) {
await onCreateAction(payload)
setShowCreate(false)
}
function toggleActionTasks(actionId) {
setExpandedActions((prev) => {
const next = new Set(prev)
if (next.has(actionId)) next.delete(actionId)
else next.add(actionId)
return next
})
}
return (
<section className="card plan-actions-section">
<div className="section-header">
<div>
<h2>Arbeit</h2>
<p className="section-lead muted">
Committete Arbeitspakete und zugehörige Aufgaben — Ausführung über die Objektseite.
</p>
</div>
<div className="section-actions">
<label className="checkbox-label inline-filter">
<input
type="checkbox"
checked={hideDone}
onChange={(e) => onHideDoneChange(e.target.checked)}
/>
Erledigte ausblenden
</label>
{canManage && (
<button
type="button"
className="btn btn-primary btn-block-mobile"
onClick={() => setShowCreate(true)}
>
Arbeitspaket
</button>
)}
</div>
</div>
{scopeProjectId && (
<p className="muted plan-actions-section__scope-hint">
Gefiltert nach Projekt im Scope — Scope oben leeren für alle Arbeitspakete.
</p>
)}
{visibleActions.length === 0 && (
<EmptyState message="Noch keine Arbeitspakete — lege welche an oder wandle Backlog-Items um." />
)}
<ul className="item-list plan-actions-list">
{visibleActions.map((action) => (
<li key={action.id} className="list-item card-list-item plan-actions-list__item">
<div className="plan-actions-list__header">
<div className="list-item-main">
<Link to={actionPath(action.id)} className="plan-actions-list__title">
<strong>{action.title}</strong>
</Link>
<p className="list-item-sub muted">
{formatProjectContext(projects, action.project_id)}
</p>
{action.roadmap_item_id && (
<p className="list-item-sub muted">
Gate: {gateTitleById(roadmapItems, action.roadmap_item_id)}
</p>
)}
{action.description && (
<p className="list-item-desc">{action.description}</p>
)}
</div>
<div className="list-item-meta action-controls">
<StatusBadge kind="action" status={action.status} />
<PriorityBadge priority={action.priority} />
<Link to={actionPath(action.id)} className="btn btn-secondary btn-sm">
Öffnen
</Link>
</div>
</div>
<ActionTaskPanel
actionId={action.id}
roadmapItems={roadmapItems}
canManage={canManage}
expanded={expandedActions.has(action.id)}
onToggle={() => toggleActionTasks(action.id)}
/>
</li>
))}
</ul>
<Modal open={showCreate} title="Arbeitspaket anlegen" onClose={() => setShowCreate(false)} size="lg">
<ActionForm
projects={projects}
roadmapItems={roadmapItems}
actors={actors}
actorsLoading={actorsLoading}
actorsError={actorsError}
actorsUsedFallback={actorsUsedFallback}
onReloadActors={onReloadActors}
onSubmit={handleCreate}
onCancel={() => setShowCreate(false)}
busy={busy}
submitLabel="Anlegen"
/>
</Modal>
</section>
)
}