2026-07-05 18:45:36 +02:00
|
|
|
import { useState } from 'react'
|
2026-07-06 06:53:49 +02:00
|
|
|
import { Link } from 'react-router-dom'
|
2026-07-08 12:55:37 +02:00
|
|
|
import { gatePath } from '../utils/routes.js'
|
2026-07-05 18:45:36 +02:00
|
|
|
import {
|
|
|
|
|
ROADMAP_ITEM_TYPE_LABELS,
|
|
|
|
|
SEQUENCING_MODE_LABELS,
|
|
|
|
|
} from '../constants/status.js'
|
|
|
|
|
import { StatusBadge } from './StatusBadge.jsx'
|
|
|
|
|
import { EmptyState } from './EmptyState.jsx'
|
2026-07-10 15:41:42 +02:00
|
|
|
import { Modal } from './Modal.jsx'
|
|
|
|
|
import { RoadmapItemForm } from './RoadmapItemForm.jsx'
|
2026-07-05 18:45:36 +02:00
|
|
|
|
|
|
|
|
function formatDate(value) {
|
|
|
|
|
if (!value) return null
|
|
|
|
|
try {
|
|
|
|
|
return new Date(value.includes('T') ? value : `${value}T12:00:00`).toLocaleDateString(
|
2026-07-10 15:41:42 +02:00
|
|
|
'de-DE',
|
2026-07-05 18:45:36 +02:00
|
|
|
)
|
|
|
|
|
} catch {
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function RoadmapPlanSection({
|
2026-07-06 06:53:49 +02:00
|
|
|
initiativeId,
|
2026-07-05 18:45:36 +02:00
|
|
|
items,
|
|
|
|
|
canManage,
|
|
|
|
|
onCreate,
|
|
|
|
|
onDelete,
|
|
|
|
|
busy,
|
|
|
|
|
}) {
|
2026-07-10 15:41:42 +02:00
|
|
|
const [showCreate, setShowCreate] = useState(false)
|
2026-07-05 18:45:36 +02:00
|
|
|
|
2026-07-10 15:41:42 +02:00
|
|
|
async function handleCreateSubmit(payload) {
|
|
|
|
|
await onCreate(payload)
|
|
|
|
|
setShowCreate(false)
|
2026-07-05 18:45:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
2026-07-10 15:41:42 +02:00
|
|
|
<section className="card roadmap-plan-section">
|
2026-07-05 18:45:36 +02:00
|
|
|
<div className="section-header">
|
|
|
|
|
<div>
|
2026-07-06 08:19:05 +02:00
|
|
|
<h2>Zielzustände (Gates)</h2>
|
2026-07-05 18:45:36 +02:00
|
|
|
<p className="section-lead muted">
|
2026-07-10 15:41:42 +02:00
|
|
|
Überprüfbare Zielpunkte — optional. Bearbeitung und Verify auf der Gate-Detailseite,
|
|
|
|
|
nicht inline in der Liste.
|
2026-07-05 18:45:36 +02:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
{canManage && (
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="btn btn-primary btn-block-mobile"
|
2026-07-10 15:41:42 +02:00
|
|
|
onClick={() => setShowCreate(true)}
|
2026-07-05 18:45:36 +02:00
|
|
|
>
|
2026-07-10 15:41:42 +02:00
|
|
|
Plan-Element
|
2026-07-05 18:45:36 +02:00
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{items.length === 0 && (
|
|
|
|
|
<EmptyState message="Noch kein Plan — strukturiere das Vorhaben in überprüfbare Roadmap-Elemente." />
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<ul className="item-list milestone-list">
|
|
|
|
|
{items.map((item) => (
|
|
|
|
|
<li key={item.id} className="list-item card-list-item milestone-list-item">
|
|
|
|
|
<div className="list-item-main">
|
2026-07-06 06:53:49 +02:00
|
|
|
<strong>
|
|
|
|
|
{initiativeId ? (
|
2026-07-10 15:41:42 +02:00
|
|
|
<Link to={gatePath(item.id)} className="roadmap-plan-section__title-link">
|
2026-07-06 06:53:49 +02:00
|
|
|
{item.title}
|
|
|
|
|
</Link>
|
|
|
|
|
) : (
|
|
|
|
|
item.title
|
|
|
|
|
)}
|
|
|
|
|
</strong>
|
2026-07-05 18:45:36 +02:00
|
|
|
<p className="muted list-item-sub">
|
|
|
|
|
{ROADMAP_ITEM_TYPE_LABELS[item.item_type] || item.item_type}
|
|
|
|
|
{' · '}
|
|
|
|
|
{SEQUENCING_MODE_LABELS[item.sequencing_mode] || item.sequencing_mode}
|
|
|
|
|
</p>
|
|
|
|
|
{item.goal_description && (
|
|
|
|
|
<p className="list-item-desc">{item.goal_description}</p>
|
|
|
|
|
)}
|
|
|
|
|
{item.target_date && (
|
|
|
|
|
<p className="muted list-item-sub">
|
|
|
|
|
Zieltermin: {formatDate(item.target_date)}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="list-item-meta action-controls">
|
|
|
|
|
<StatusBadge kind="milestone" status={item.status} />
|
2026-07-10 15:41:42 +02:00
|
|
|
{initiativeId && (
|
|
|
|
|
<Link to={gatePath(item.id)} className="btn btn-secondary btn-sm">
|
|
|
|
|
Öffnen
|
|
|
|
|
</Link>
|
|
|
|
|
)}
|
2026-07-05 18:45:36 +02:00
|
|
|
{canManage && item.status !== 'reached' && (
|
2026-07-10 15:41:42 +02:00
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
className="btn btn-secondary btn-sm"
|
|
|
|
|
onClick={() => onDelete(item.id)}
|
|
|
|
|
disabled={busy}
|
|
|
|
|
>
|
|
|
|
|
Löschen
|
|
|
|
|
</button>
|
2026-07-05 18:45:36 +02:00
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
2026-07-10 15:41:42 +02:00
|
|
|
|
|
|
|
|
<Modal open={showCreate} title="Plan-Element anlegen" onClose={() => setShowCreate(false)}>
|
|
|
|
|
<RoadmapItemForm
|
|
|
|
|
onSubmit={handleCreateSubmit}
|
|
|
|
|
onCancel={() => setShowCreate(false)}
|
|
|
|
|
busy={busy}
|
|
|
|
|
submitLabel="Anlegen"
|
|
|
|
|
mode="create"
|
|
|
|
|
/>
|
|
|
|
|
</Modal>
|
2026-07-05 18:45:36 +02:00
|
|
|
</section>
|
|
|
|
|
)
|
|
|
|
|
}
|