diff --git a/frontend/src/pages/DashboardLabPage.jsx b/frontend/src/pages/DashboardLabPage.jsx index 8aca6ba..ba246f7 100644 --- a/frontend/src/pages/DashboardLabPage.jsx +++ b/frontend/src/pages/DashboardLabPage.jsx @@ -28,15 +28,28 @@ export default function DashboardLabPage() { const [err, setErr] = useState(null) const [busy, setBusy] = useState(false) const [msg, setMsg] = useState(null) + /** Während der Fokus im Körper-Chart-Feld: Rohstring, damit Tippen (z. B. „14“) nicht sofort geclamped wird */ + const [bodyChartDaysDraft, setBodyChartDaysDraft] = useState(null) const metaById = catalogMetaById(catalog) + const commitBodyChartDraftToLayout = useCallback((draftStr, baseLayout) => { + const clamped = normalizeBodyChartDays(draftStr === '' || draftStr == null ? BODY_CHART_DAYS_DEFAULT : draftStr) + return { + ...baseLayout, + widgets: baseLayout.widgets.map((x) => + x.id !== 'body_overview' ? x : { ...x, config: { ...x.config, chart_days: clamped } } + ), + } + }, []) + const load = useCallback(async () => { setErr(null) try { const [cat, b] = await Promise.all([api.getAppWidgetsCatalog(), api.getAppDashboardLayout()]) setCatalog(cat) setBundle(b) + setBodyChartDaysDraft(null) setLayout(normalizeLayoutForEditor(b.layout)) } catch (e) { setErr(formatFastApiDetail(null, e.message)) @@ -49,11 +62,17 @@ export default function DashboardLabPage() { const save = async () => { if (!layout) return + let toSave = layout + if (bodyChartDaysDraft !== null) { + toSave = normalizeLayoutForEditor(commitBodyChartDraftToLayout(bodyChartDaysDraft, layout)) + setLayout(toSave) + setBodyChartDaysDraft(null) + } setBusy(true) setMsg(null) setErr(null) try { - await api.putAppDashboardLayout(layout) + await api.putAppDashboardLayout(toSave) setMsg('Layout gespeichert.') await load() } catch (e) { @@ -70,6 +89,7 @@ export default function DashboardLabPage() { setErr(null) try { const r = await api.resetAppDashboardLayout() + setBodyChartDaysDraft(null) setLayout(normalizeLayoutForEditor(r.layout)) setMsg('Auf Standard zurückgesetzt.') await load() @@ -82,6 +102,7 @@ export default function DashboardLabPage() { const applyDefaultLocal = () => { if (bundle?.default_layout) { + setBodyChartDaysDraft(null) setLayout(normalizeLayoutForEditor(structuredClone(bundle.default_layout))) setMsg('Standard geladen (noch nicht gespeichert).') } @@ -206,37 +227,29 @@ export default function DashboardLabPage() { Körper-Chart Zeitraum (Tage): {BODY_CHART_DAYS_MIN}–{BODY_CHART_DAYS_MAX} { - const v = parseInt(e.target.value, 10) - setLayout((L) => ({ - ...L, - widgets: L.widgets.map((x, j) => - j !== i - ? x - : { - ...x, - config: { - ...x.config, - chart_days: Number.isFinite(v) ? v : BODY_CHART_DAYS_DEFAULT, - }, - } - ), - })) + aria-label="Körper-Chart Zeitraum in Tagen" + value={ + bodyChartDaysDraft !== null + ? bodyChartDaysDraft + : String(chartDaysVal) + } + onFocus={() => setBodyChartDaysDraft(String(chartDaysVal))} + onChange={(e) => setBodyChartDaysDraft(e.target.value)} + onBlur={() => { + setLayout((L) => + normalizeLayoutForEditor( + commitBodyChartDraftToLayout(bodyChartDaysDraft ?? String(chartDaysVal), L) + ) + ) + setBodyChartDaysDraft(null) }} - onBlur={(e) => { - const clamped = normalizeBodyChartDays(e.target.value) - setLayout((L) => ({ - ...L, - widgets: L.widgets.map((x, j) => - j !== i ? x : { ...x, config: { ...x.config, chart_days: clamped } } - ), - })) + onKeyDown={(e) => { + if (e.key === 'Enter') e.currentTarget.blur() }} />