import {Box, Text, Flex, IconButton, Spinner, Popover, useSlotRecipe} from "@chakra-ui/react"; import {X, MoreVertical} from "lucide-react"; import {Responsive, WidthProvider} from "react-grid-layout"; import {useDashboardStore} from "@/store/useDashboardStore.jsx"; import {Suspense, useEffect, useRef} from 'react'; // 1. Import database messenger import useAuthStore from "@/store/authStore"; // 2. Import registry import {WIDGET_REGISTRY} from '@/constants/widgetRegistry.jsx'; // React-Grid-Layout requires this wrapper to automatically calculate screen width const ResponsiveGridLayout = WidthProvider(Responsive); export default function MyDashboard() { // ☁️ Database Connection const {user} = useAuthStore(); // ☁️ Local UI Connections const widgets = useDashboardStore(state => state.widgets); const isEditing = useDashboardStore(state => state.isEditing); const updateLayoutPositions = useDashboardStore(state => state.updateLayoutPositions); const removeWidget = useDashboardStore(state => state.removeWidget); const setWidgets = useDashboardStore(state => state.setWidgets); // The injection action // 🔒 Safety lock to prevent infinite re-renders const hasHydrated = useRef(false); // 1. Pull the global slot recipes const recipe = useSlotRecipe({key: "glassPanel"}); const styles = recipe({ layout: "widget" }); const popoverStyles = recipe({ layout: "popover" }); // 2. Populate widgets useEffect(() => { if (user?.preferences?.dashboard_layout && !hasHydrated.current) { const savedLayout = user.preferences.dashboard_layout; // Safety check: Only inject if it's actually an array of widgets. // (Prevents a crash if MariaDB returns a default empty object {}) if (Array.isArray(savedLayout)) setWidgets(savedLayout); hasHydrated.current = true; } }, [user, setWidgets]); // 🛠️ Format the data for RGL const rglLayout = widgets.map(w => ({ i: w.id, x: w.x, y: w.y, w: w.w, h: w.h, isResizable: false // The magic lock! No resizing allowed globally. })); // 3. The component mapper const renderWidget = (widget) => { const registryEntry = WIDGET_REGISTRY[widget.type]; if (registryEntry && registryEntry.component) { const Component = registryEntry.component; // 1. Check if this widget type has a settings component registered const SettingsUI = registryEntry.settingsComponent; return ( <> {registryEntry.name} {/* WIDGET SETTINGS BUTTON (ELLIPSES) */} {SettingsUI && ( {/* NEW: The Positioner lifts the content out of the Flexbox flow */} }> )} ); } // Fallback if someone asks for a widget that doesn't exist return ( Error Widget '{widget.type}' not found. ); }; return ( updateLayoutPositions(newLayout)} // Fires when user drops a widget > {/* 🎨 Paint the Widgets */} {widgets.map(widget => ( {/* THE DELETE BUTTON */} {isEditing && ( removeWidget(widget.id)} onMouseDown={(e) => e.stopPropagation()} // 🚫 Stops RGL from grabbing the widget onTouchStart={(e) => e.stopPropagation()} // 🚫 Same protection for mobile touches > )} {/* SUSPENSE BOUNDARY wrapping the render function */} }> {renderWidget(widget)} ))} {/* Empty State Helper */} {widgets.length === 0 && ( Your dashboard is empty. Click Settings to add widgets. )} ); }