import { useCallback, useEffect, useState } from 'react' import { ChevronDown, ChevronUp, LayoutGrid } from 'lucide-react' import { Link } from 'react-router-dom' import { api, formatFastApiDetail } from '../utils/api' import { DASHBOARD_LAB_WIDGET_META } from '../app/areas/dashboardLab/dashboardLabWidgets' import PilotWelcome from '../components/pilot/PilotWelcome' import PilotQuickCapture from '../components/pilot/PilotQuickCapture' import PilotKpiBoard from '../components/pilot/PilotKpiBoard' import PilotBodySection from '../components/pilot/PilotBodySection' import PilotActivitySection from '../components/pilot/PilotActivitySection' const metaById = Object.fromEntries(DASHBOARD_LAB_WIDGET_META.map((m) => [m.id, m])) function moveWidget(layout, index, delta) { const next = [...layout.widgets] const j = index + delta if (j < 0 || j >= next.length) return layout ;[next[index], next[j]] = [next[j], next[index]] return { ...layout, widgets: next } } function toggleWidget(layout, index) { const next = layout.widgets.map((w, i) => i === index ? { ...w, enabled: !w.enabled } : w ) const anyOn = next.some((w) => w.enabled) if (!anyOn) return layout return { ...layout, widgets: next } } export default function DashboardLabPage() { const [refreshTick, setRefreshTick] = useState(0) const bump = () => setRefreshTick((t) => t + 1) const [bundle, setBundle] = useState(null) const [layout, setLayout] = useState(null) const [err, setErr] = useState(null) const [busy, setBusy] = useState(false) const [msg, setMsg] = useState(null) const load = useCallback(async () => { setErr(null) try { const b = await api.getAppDashboardLayout() setBundle(b) setLayout(b.layout) } catch (e) { setErr(formatFastApiDetail(null, e.message)) } }, []) useEffect(() => { load() }, [load]) const save = async () => { if (!layout) return setBusy(true) setMsg(null) setErr(null) try { await api.putAppDashboardLayout(layout) setMsg('Layout gespeichert.') await load() } catch (e) { setErr(formatFastApiDetail(null, e.message)) } finally { setBusy(false) } } const reset = async () => { if (!confirm('Persönliches Layout löschen und Standard wiederherstellen?')) return setBusy(true) setMsg(null) setErr(null) try { const r = await api.resetAppDashboardLayout() setLayout(r.layout) setMsg('Auf Standard zurückgesetzt.') await load() } catch (e) { setErr(formatFastApiDetail(null, e.message)) } finally { setBusy(false) } } const applyDefaultLocal = () => { if (bundle?.default_layout) { setLayout(structuredClone(bundle.default_layout)) setMsg('Standard geladen (noch nicht gespeichert).') } } const renderWidget = (id) => { switch (id) { case 'welcome': return case 'quick_capture': return case 'kpi_board': return case 'body_overview': return case 'activity_overview': return default: return null } } if (err && !layout) { return (

{err}

) } if (!layout) { return (
) } const enabledOrder = layout.widgets.filter((w) => w.enabled) return (
← Einstellungen

App-Bereich: Dashboard-Lab

Geschützte Route (Login erforderlich). Widget-Reihenfolge und Sichtbarkeit werden pro Profil in der Datenbank gespeichert — getrennt vom Produktiv-Dashboard. Vergleich:{' '} Pilot-Übersicht (festes Layout) .

Layout (v1)
{bundle && (

Status: {bundle.custom ? 'individuell gespeichert' : 'Standard (nicht in DB)'}

)} {err && (

{err}

)} {msg && (

{msg}

)}
    {layout.widgets.map((w, i) => { const label = metaById[w.id]?.label || w.id return (
  • ) })}
{enabledOrder.map((w) => renderWidget(w.id))}
) }