Files
Web-Frontend/client/src/components/Dashboard.jsx
T

158 lines
4.0 KiB
React
Raw Normal View History

import Header from './Header/Header.jsx';
import Sidebar from './Sidebar/Sidebar.jsx';
import Canvas from './Canvas/Canvas.jsx';
2025-08-11 15:10:58 -07:00
import { Grid, GridItem, useRecipe, useDialog } from '@chakra-ui/react';
import { useState } from 'react';
2025-08-11 15:10:58 -07:00
import DialogPopup from './Canvas/CanvasComponents/DialogPopup.jsx';
export default function Dashboard() {
2025-07-28 13:32:03 -07:00
const recipe = useRecipe({ key: "dashboard" });
const styles = recipe();
2025-08-11 15:10:58 -07:00
const dialog = useDialog();
const [darkMode, setDarkMode] = useState(false);
const [view, setView] = useState("mydashboard");
const emptyDash = () => ({
layout: [],
widgetArray: [],
originalLayout: [],
originalWidgets: [],
isEditable: false,
isDelete: false,
})
// Add views as needed to initialize widget canvas views
const CANVAS_VIEWS = new Set([ "mydashboard", "gas" ]);
// Widget dashboard state
const [dashboards, setDashboards] = useState(() => ({
mydashboard: emptyDash(),
gas: emptyDash(),
}));
const isCanvasView = CANVAS_VIEWS.has(view);
const dash = dashboards[view] ?? emptyDash();
const updateDash = (key, updater) => {
setDashboards(prev => ({
...prev,
[key]: updater(prev[key] ?? emptyDash()),
}));
};
// Widget setter functions
const setLayout = (fnOrValue) => {
if (!isCanvasView) return;
updateDash(view, s => ({
...s,
layout: typeof fnOrValue === "function" ? fnOrValue( s.layout ) : fnOrValue,
}));
};
const setWidgetArray = (fnOrValue) => {
if (!isCanvasView) return;
updateDash(view, s => ({
...s,
widgetArray: typeof fnOrValue === "function" ? fnOrValue(s.widgetArray) : fnOrValue,
}));
};
const setIsEditable = (value) => {
if (!isCanvasView) return;
updateDash(view, s => ({ ...s, isEditable: value }));
};
const setIsDelete = (value) => {
if (!isCanvasView) return;
updateDash(view, s => ({ ...s, isDelete: value }));
};
const beginEditIfNeeded = () => {
if (!isCanvasView) return;
updateDash(view, s => {
if(s.isEditable) return s; // already editing
return {
...s,
originalLayout: s.layout,
originalWidgets: s.widgetArray,
};
});
};
const onCancel = () => {
if (!isCanvasView) return;
updateDash(view, s => ({
...s,
layout: (s.originalLayout?.length ? s.originalLayout : s.layout).map(it => ({
...it,
static: true,
})),
widgetArray: s.originalWidgets ?? s.widgetArray,
isEditable: false,
isDelete: false,
originalLayout: [],
originalWidgets: [],
}));
};
const onLayoutChange = (newLayout) => {
setLayout(newLayout);
};
const handleViewChange = (nextView) => {
// prevent nav only when current view is a widget canvas AND you're editing
if (CANVAS_VIEWS.has(view) && dash.isEditable) {
2025-08-12 09:55:57 -07:00
dialog.setOpen(true);
return;
}
setView(nextView);
};
2025-08-04 15:38:19 -07:00
// Prop Forwarding
const canvasProps = {
view,
onChangeView: handleViewChange,
// active canvas props
layout: dash.layout,
widgetArray: dash.widgetArray,
isEditable: dash.isEditable,
isDelete: dash.isDelete,
// handler functions
setLayout,
setWidgetArray,
setIsEditable,
setIsDelete,
beginEditIfNeeded,
onCancel,
onLayoutChange,
2025-08-04 15:38:19 -07:00
};
const sidebarProps = { view, onChangeView: handleViewChange, darkMode, setDarkMode };
const headerProps = { onChangeView: handleViewChange };
return (
2025-08-12 09:55:57 -07:00
<>
<DialogPopup dialog={dialog} />
<Grid css={styles}
templateRows="1fr 11fr"
// templateColumns="1fr 20fr"
templateColumns="auto 1fr"
height="100vh"
width="100vw"
>
<GridItem rowSpan={1} colSpan={2}>
2025-08-04 15:38:19 -07:00
<Header {...headerProps}/>
</GridItem>
<GridItem colSpan={1}>
2025-08-04 15:38:19 -07:00
<Sidebar {...sidebarProps}/>
</GridItem>
2025-07-24 13:48:41 -07:00
<GridItem colSpan={1} width="100%" overflow="auto">
2025-08-04 15:38:19 -07:00
<Canvas {...canvasProps}/>
2025-08-04 12:04:33 -07:00
</GridItem>
</Grid>
2025-08-12 09:55:57 -07:00
</>
);
}