"use client"; import { useState, useEffect, useCallback, useRef } from "react"; import type { ReactElement } from "react"; import type { WidgetPlacement } from "@mosaic/shared"; import { WidgetGrid } from "@/components/widgets/WidgetGrid"; import { WidgetPicker } from "@/components/widgets/WidgetPicker"; import { WidgetConfigDialog } from "@/components/widgets/WidgetConfigDialog"; import { DEFAULT_LAYOUT } from "@/components/widgets/defaultLayout"; import { fetchDefaultLayout, createLayout, updateLayout } from "@/lib/api/layouts"; import { useWorkspaceId } from "@/lib/hooks"; export default function DashboardPage(): ReactElement { const workspaceId = useWorkspaceId(); const [layout, setLayout] = useState(DEFAULT_LAYOUT); const [layoutId, setLayoutId] = useState(null); const [isEditing, setIsEditing] = useState(false); const [isPickerOpen, setIsPickerOpen] = useState(false); const [configWidgetId, setConfigWidgetId] = useState(null); const [isLoading, setIsLoading] = useState(true); // Debounce timer for auto-saving layout changes const saveTimerRef = useRef | null>(null); // Load the user's default layout (or create one) useEffect(() => { if (!workspaceId) { setIsLoading(false); return; } const wsId = workspaceId; const ac = new AbortController(); async function loadLayout(): Promise { try { const existing = await fetchDefaultLayout(wsId); if (ac.signal.aborted) return; if (existing) { setLayout(existing.layout); setLayoutId(existing.id); } else { const created = await createLayout(wsId, { name: "Default", isDefault: true, layout: DEFAULT_LAYOUT, }); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- aborted can change during await if (ac.signal.aborted) return; setLayout(created.layout); setLayoutId(created.id); } } catch (err: unknown) { console.error("[Dashboard] Failed to load layout:", err); } setIsLoading(false); } void loadLayout(); return (): void => { ac.abort(); }; }, [workspaceId]); // Save layout changes with debounce const saveLayout = useCallback( (newLayout: WidgetPlacement[]) => { if (!workspaceId || !layoutId) return; if (saveTimerRef.current) { clearTimeout(saveTimerRef.current); } saveTimerRef.current = setTimeout(() => { void updateLayout(workspaceId, layoutId, { layout: newLayout }).catch((err: unknown) => { console.error("[Dashboard] Failed to save layout:", err); }); }, 800); }, [workspaceId, layoutId] ); const handleLayoutChange = useCallback( (newLayout: WidgetPlacement[]) => { setLayout(newLayout); saveLayout(newLayout); }, [saveLayout] ); const handleRemoveWidget = useCallback( (widgetId: string) => { const updated = layout.filter((item) => item.i !== widgetId); setLayout(updated); saveLayout(updated); }, [layout, saveLayout] ); const handleAddWidget = useCallback( (placement: WidgetPlacement) => { const updated = [...layout, placement]; setLayout(updated); saveLayout(updated); }, [layout, saveLayout] ); const handleResetLayout = useCallback((): void => { setLayout(DEFAULT_LAYOUT); saveLayout(DEFAULT_LAYOUT); }, [saveLayout]); const handleEditWidget = useCallback((widgetId: string): void => { setConfigWidgetId(widgetId); }, []); if (isLoading) { return (
Loading dashboard...
); } return (
{/* Dashboard header with edit toggle */}

Dashboard

{isEditing && ( <> )}
{/* Widget grid */} {/* Widget config dialog */} {configWidgetId && ( { setConfigWidgetId(null); }} /> )} {/* Widget picker drawer */} { setIsPickerOpen(false); }} onAddWidget={handleAddWidget} currentLayout={layout} />
); }