From 7744d6b8ce4b546807bc1129b74a1cbdb34e6cf0 Mon Sep 17 00:00:00 2001 From: Christopher Hight Date: Mon, 8 Jun 2026 15:57:40 -0700 Subject: [PATCH] Refactor making changes to home and how widgets are altered --- client/src/App.jsx | 19 +- client/src/components/Canvas/views/Home.jsx | 224 +++++--------------- client/src/constants/widgetRegistry.jsx | 52 +++++ 3 files changed, 119 insertions(+), 176 deletions(-) create mode 100644 client/src/constants/widgetRegistry.jsx diff --git a/client/src/App.jsx b/client/src/App.jsx index b4c635c..c18c32e 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -1,6 +1,6 @@ import 'leaflet/dist/leaflet.css'; import { Routes, Route, Navigate, Outlet } from 'react-router-dom'; -import { useRecipe, Grid, GridItem, useDialog } from "@chakra-ui/react"; +import { useRecipe, Grid, GridItem, useDialog, Flex, Heading } from "@chakra-ui/react"; import { createContext } from "react"; import Login from "@/Login.jsx"; import Sidebar from "./components/Sidebar/Sidebar.jsx"; @@ -44,7 +44,11 @@ function AppFoundation() { // if (user) return children; // else return ; // } - +const Placeholder = ({ name }) => ( + + {name} Dashboard - Coming Soon + +); function App() { const sidebarContext = createContext(["Home", "Global Map", "Regional Map", "Volcano", "Admin"]); // const [user, setUser] = useState(null); @@ -56,7 +60,16 @@ function App() { {/*Non-Public Routes*/} }> - } /> + + }> + {/* We use our "pass" component to fill the Outlet until the real pages are built */} + } /> + } /> + } /> + } /> + } /> + + } /> } /> } /> diff --git a/client/src/components/Canvas/views/Home.jsx b/client/src/components/Canvas/views/Home.jsx index cb6383f..1ff06c7 100644 --- a/client/src/components/Canvas/views/Home.jsx +++ b/client/src/components/Canvas/views/Home.jsx @@ -1,186 +1,64 @@ -import { HStack, Flex, Tabs, Button } from "@chakra-ui/react"; -import { useState } from "react"; -import MyDashboard from "./HomeTabs/MyDashboard"; +import { HStack, Flex, Box } from "@chakra-ui/react"; +import { NavLink, Outlet, useLocation } from "react-router-dom"; import { SearchBar } from "../CanvasComponents/SearchBar"; import { SettingsButton } from "../CanvasComponents/SettingsButton"; -import { DailyActivity } from "./HomeTabs/DailyActivity"; -import { Gas } from "./HomeTabs/Gas"; -import { Seismic } from "./HomeTabs/Seismic"; -import { RemoteSensing } from "./HomeTabs/RemoteSensing"; -import { CancelButton } from "../CanvasComponents/CancelButton"; -import { SaveButton } from "../CanvasComponents/SaveButton"; -import DeleteAllButton from "../CanvasComponents/DeleteAllButton"; -import { v4 as uuid } from 'uuid'; -import { CanvasHeaderTabs } from '../CanvasComponents/CanvasHeaderTabs'; -import { DASHBOARD_TABS } from "@/constants/viewKeys"; export default function Home() { - const [isEditable, setIsEditable] = useState(false); // editable=true means static=false (vice versa) - const [isDelete, setIsDelete] = useState(false); - const [originalLayout, setOriginalLayout] = useState([]); - const [originalWidgets, setOriginalWidgets] = useState([]); - const [layout, setLayout] = useState([]); - const [widgetArray, setWidgetArray] = useState([]); + const location = useLocation(); + const isPersonalDashboard = location.pathname === "/home" || location.pathname === "/home/"; - function appendWidget(name, w, h, min_w, minh, max_w, max_h) { - saveLayoutState(); // Save state before anything else - - const newID = uuid(); // could be replaced with something else like guid - const COLS = 16; - const W = w ?? 3; - const H = h ?? 3; - - setWidgetArray([ // updating widget array containing info on the types of widgets - ...widgetArray, - {i: newID, widget: name } - ]); - // onAddWidget(newID, w, h, min_w, minh, max_w, max_h); // updating array containing info on layout of widgets - - setLayout(prev => [ - ...prev, - { - i: newID, - x: (prev.length * W) % COLS, - y: 0, - w: w, - h: h, - minW: min_w, - minH: minh, - maxW: max_w, - maxH: max_h, - static: false, - resizeHandles: ['se'] - }, - ]); - } - - const onSave = () => { - console.log("saving widgets..."); - // Set all widgets back to static: true - setLayout(prevLayout => - prevLayout.map(item => ({ - ...item, - static: true - })) - ); - setIsEditable(false); - setIsDelete(false); - setOriginalLayout([]); // Clear backup layout - setOriginalWidgets([]); - } - - const onEditWidgets = () => { - console.log("Start deleting widgets..."); - saveLayoutState(); // Save state before anything else - setLayout(prevLayout => - prevLayout.map(item => ({ - ...item, - static: false - })) - ); - setIsEditable(true); - setIsDelete(true); - } - - const DeleteWidget = (ID) => { - console.log("Deleting widget with id: ", ID); - setLayout(layout => layout.filter(w => w.i !== ID)); - setWidgetArray(widgetArray => widgetArray.filter(w => w.i !== ID)); - } - - const DeleteAll = () => { - const confirm = window.confirm( - "Are you sure you want to delete all widgets?" - ); - if (confirm) { - setLayout([]); - setWidgetArray([]); - onSave(); - } - else return; - } - - - const saveLayoutState = () => { - if ( !isEditable ) { - setOriginalLayout(layout); - setOriginalWidgets(widgetArray); + // 1. 🎨 CSS Magic: Replicates Chakra's `` exactly + const tabStyles = { + fontSize: "lg", + fontWeight: "normal", + color: "fg.muted", + px: 4, // Horizontal padding + py: 2, // Vertical padding + borderBottom: "2px solid transparent", + mb: "-2px", // 🔥 The trick: Pulls the active border down to overlap the container's line + transition: "all 0.2s", + _hover: { color: "fg" }, + _activeLink: { + color: "color", // Or whatever your primary text color is + borderColor: "currentColor", // The active underline } }; - const onCancel = () => { - console.log("canceling changes..."); - console.log(originalWidgets); - if (originalLayout.length) { - setLayout(originalLayout.map(item => ({ - ...item, - static: true - }))); - } - setWidgetArray(originalWidgets); - setIsEditable(false); - setIsDelete(false); - setOriginalLayout([]); - setOriginalWidgets([]); - } - - const onLayoutChange = (newLayout) => setLayout(newLayout); - - - // Prop Forwarding - const MyDashboardProps = { layout, onLayoutChange, isEditable, saveLayoutState, isDelete, DeleteWidget, widgetArray, appendWidget }; - const settingsButtonProps = { onEditWidgets, appendWidget }; - return ( - /* SUB HEADER */ - - - {/* TABS */} - {/* */} {/* TODO: rename to SubHeaderTabs */} - - {DASHBOARD_TABS.map(({ value, label }) => - - { label } - - )} - + + + {/* 2. 🛠️ SUB HEADER: Matches your original padding and background */} + + + {/* TABS CONTAINER - Replicates the Tabs.List line container */} + + My Dashboard + Gas + Seismic + Remote Sensing + Daily Activity + + + {/* EDIT MODE BUTTONS & CONTROLS */} + + {isPersonalDashboard ? ( + <> + + {/* This will eventually trigger your Zustand store's edit mode! */} + + + ) : ( + + )} + + + + + {/* 3. 🛠️ CANVAS AREA */} + + + - {/* EDIT MODE BUTTONS */} - - {isEditable ? ( - <> - - - {isDelete ? ( - - ):(null) - } - - ):( - <> - - - - )} - - - {/* CANVAS */} - - - - - - - - - - - - - - - - ); } \ No newline at end of file diff --git a/client/src/constants/widgetRegistry.jsx b/client/src/constants/widgetRegistry.jsx new file mode 100644 index 0000000..8d39b68 --- /dev/null +++ b/client/src/constants/widgetRegistry.jsx @@ -0,0 +1,52 @@ +// config/widgetRegistry.js + +// We assume a 12-column grid. +// w: 12 = full screen width +// w: 6 = half screen width +// w: 4 = one-third screen width +// w: 3 = one-quarter screen width + +export const WIDGET_REGISTRY = { + "vaa_activity": { + name: "VAA 7 Day Activity", + description: "Displays 7-day flight level timelines across multiple volcanoes.", + allowedSizes: { + large: { w: 12, h: 8 }, // Spans the entire width of the screen + } + }, + + "db_cache_health": { + name: "DB Cache Health", + description: "Bar chart showing cache table operational status.", + allowedSizes: { + medium: { w: 4, h: 6 }, // 1/3 width + large: { w: 6, h: 6 } // 1/2 width + } + }, + + "ivans_alerts": { + name: "IVANS", + description: "Feed of recent IVANS reports and reviewer statuses.", + allowedSizes: { + small: { w: 3, h: 6 }, // 1/4 width (tall and skinny) + medium: { w: 4, h: 8 } // 1/3 width + } + }, + + "remote_sensing": { + name: "Remote Sensing", + description: "Feed of recent remote sensing reports.", + allowedSizes: { + medium: { w: 4, h: 5 }, // 1/3 width + } + }, + + "alert_levels": { + name: "Alert Level Changes", + description: "List of 7-day alert level changes with trend arrows.", + allowedSizes: { + small: { w: 3, h: 5 }, + medium: { w: 4, h: 5 } + } + } +}; \ No newline at end of file