2026-06-09 14:06:01 -07:00
|
|
|
import { Box, Text, Flex } from "@chakra-ui/react";
|
|
|
|
|
import { Responsive, WidthProvider } from "react-grid-layout";
|
|
|
|
|
import { useDashboardStore } from "@/store/useDashboardStore.jsx";
|
2025-07-21 14:27:53 -07:00
|
|
|
|
2026-06-09 14:06:01 -07:00
|
|
|
// React-Grid-Layout requires this wrapper to automatically calculate screen width
|
|
|
|
|
const ResponsiveGridLayout = WidthProvider(Responsive);
|
2025-07-22 11:58:10 -07:00
|
|
|
|
2026-06-09 14:06:01 -07:00
|
|
|
export default function MyDashboard() {
|
|
|
|
|
// 1. ☁️ Connect to the Cloud (Zustand)
|
|
|
|
|
const widgets = useDashboardStore(state => state.widgets);
|
|
|
|
|
const isEditing = useDashboardStore(state => state.isEditing);
|
|
|
|
|
const updateLayoutPositions = useDashboardStore(state => state.updateLayoutPositions);
|
2025-07-22 13:41:32 -07:00
|
|
|
|
2026-06-09 14:06:01 -07:00
|
|
|
// 2. 🛠️ Format the data for RGL
|
|
|
|
|
// RGL expects a very specific array format for its layout prop
|
|
|
|
|
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.
|
|
|
|
|
}));
|
2025-08-08 13:00:33 -07:00
|
|
|
|
2025-08-04 12:04:33 -07:00
|
|
|
return (
|
2026-06-09 14:06:01 -07:00
|
|
|
<Box width="100%" height="100%">
|
|
|
|
|
<ResponsiveGridLayout
|
|
|
|
|
className="layout"
|
|
|
|
|
layouts={{ lg: rglLayout }} // We feed it the formatted layout map
|
|
|
|
|
breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
|
|
|
|
|
cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }} // Our 12-column master grid
|
|
|
|
|
rowHeight={30}
|
|
|
|
|
isDraggable={isEditing} // Only allows dragging when your Settings tools toggle this
|
|
|
|
|
isResizable={false} // Double lock-down
|
|
|
|
|
onLayoutChange={(newLayout) => updateLayoutPositions(newLayout)} // Fires when user drops a widget
|
|
|
|
|
compactType="vertical" // Auto-packs widgets to the top
|
|
|
|
|
>
|
|
|
|
|
{/* 3. 🎨 Paint the Widgets */}
|
|
|
|
|
{widgets.map(widget => (
|
|
|
|
|
<Box
|
|
|
|
|
key={widget.id}
|
|
|
|
|
bg="white"
|
|
|
|
|
borderRadius="md"
|
|
|
|
|
boxShadow={isEditing ? "outline" : "sm"} // Visual cue when editing
|
|
|
|
|
border={isEditing ? "2px dashed gray" : "1px solid"}
|
|
|
|
|
borderColor={isEditing ? "gray.400" : "gray.200"}
|
|
|
|
|
overflow="hidden"
|
|
|
|
|
cursor={isEditing ? "grab" : "default"}
|
|
|
|
|
>
|
|
|
|
|
{/* 🚧 Temporary Placeholder!
|
|
|
|
|
Eventually, we will swap this block out for a dynamic component loader
|
|
|
|
|
that looks at widget.type and loads the correct graph or table.
|
|
|
|
|
*/}
|
|
|
|
|
<Flex width="100%" height="100%" align="center" justify="center" direction="column">
|
|
|
|
|
<Text fontWeight="bold" color="gray.600">{widget.type}</Text>
|
|
|
|
|
<Text fontSize="sm" color="gray.400">Size: {widget.size}</Text>
|
|
|
|
|
</Flex>
|
|
|
|
|
</Box>
|
|
|
|
|
))}
|
|
|
|
|
</ResponsiveGridLayout>
|
|
|
|
|
|
|
|
|
|
{/* Empty State Helper */}
|
|
|
|
|
{widgets.length === 0 && (
|
|
|
|
|
<Flex width="100%" height="200px" align="center" justify="center">
|
|
|
|
|
<Text color="gray.400">Your dashboard is empty. Click Settings to add widgets.</Text>
|
2026-06-04 15:30:01 -07:00
|
|
|
</Flex>
|
2026-06-09 14:06:01 -07:00
|
|
|
)}
|
|
|
|
|
</Box>
|
2025-07-28 12:44:17 -07:00
|
|
|
);
|
2026-06-09 14:06:01 -07:00
|
|
|
}
|