Kairo-Jinkendo/frontend/src/widgets/WorkspaceTodayWidget.jsx
Lars 2734215833
Some checks failed
Deploy Development / deploy (push) Successful in 46s
Test Suite / pytest-backend (push) Failing after 1m48s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
fix: WidgetCard-Import wiederherstellen — weißer Bildschirm nach Login.
Beim AP1.9a-Routing-Umbau fehlten die Imports in zwei Cockpit-Widgets; React brach nach Anmeldung ab.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 13:01:46 +02:00

100 lines
3.2 KiB
JavaScript

import { useCallback, useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { listWorkspaceTodayActions } from '../api/workspace.js'
import { StatusBadge } from '../components/StatusBadge.jsx'
import { PriorityBadge } from '../components/PriorityBadge.jsx'
import { EmptyState } from '../components/EmptyState.jsx'
import { ErrorState } from '../components/ErrorState.jsx'
import { LoadingState } from '../components/LoadingState.jsx'
import { WidgetCard } from '../components/WidgetCard.jsx'
import { actionPath, scopedPath } from '../utils/routes.js'
function formatDue(iso) {
if (!iso) return null
try {
return new Date(iso).toLocaleString('de-DE', {
day: '2-digit',
month: '2-digit',
hour: '2-digit',
minute: '2-digit',
})
} catch {
return iso
}
}
export function WorkspaceTodayWidget() {
const [actions, setActions] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const load = useCallback(async () => {
setLoading(true)
setError(null)
try {
const data = await listWorkspaceTodayActions(10)
setActions(Array.isArray(data) ? data : [])
} catch (err) {
setError(err.message)
} finally {
setLoading(false)
}
}, [])
useEffect(() => {
load()
}, [load])
return (
<WidgetCard
title="Heute"
subtitle="Deine Maßnahmen — überfällig und dringend zuerst"
actions={
<button type="button" className="btn btn-ghost" onClick={load} disabled={loading}>
Aktualisieren
</button>
}
footer={
actions.length > 0 ? (
<Link to="/work/mine" className="link-inline">
Alle meine Maßnahmen
</Link>
) : null
}
>
{loading && <LoadingState />}
{!loading && error && <ErrorState message={error} onRetry={load} />}
{!loading && !error && actions.length === 0 && (
<EmptyState message="Keine Maßnahmen für heute — prüfe „Nächste sinnvolle Schritte“ oben." />
)}
{!loading && !error && actions.length > 0 && (
<ul className="item-list">
{actions.map((action) => (
<li key={action.id} className="list-item card-list-item">
<div className="list-item-main">
{action.is_overdue && (
<span className="badge status-badge status-blocked">Überfällig</span>
)}
<strong>{action.title}</strong>
{action.initiative_title && (
<span className="muted list-item-sub">{action.initiative_title}</span>
)}
{action.due_at && (
<span className="muted list-item-sub">Fällig: {formatDue(action.due_at)}</span>
)}
</div>
<div className="list-item-meta">
<StatusBadge status={action.status} />
<PriorityBadge priority={action.priority} />
<Link to={actionPath(action.id)} className="btn btn-secondary btn-sm">
Öffnen
</Link>
</div>
</li>
))}
</ul>
)}
</WidgetCard>
)
}