From db162c9ffaebe7a955b94a187596467fca5d1316 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Fri, 2 May 2025 16:43:43 +0530 Subject: [PATCH 1/9] refactor: Update icon imports and improve UI components; enhance styles for better layout and responsiveness; modify event properties and simulation player functionality --- .../components/icons/ExportCommonIcons.tsx | 4 +- .../components/layout/sidebarLeft/Header.tsx | 4 +- .../layout/sidebarRight/analysis/Analysis.tsx | 64 ++---- .../properties/GlobalProperties.tsx | 4 +- .../eventProperties/EventProperties.tsx | 216 +++++++++--------- .../ui/simulation/simulationPlayer.tsx | 167 ++++++++------ .../visualization/RealTimeVisulization.tsx | 2 - .../components/simulation/simulation.scss | 13 +- app/src/styles/components/tools.scss | 2 + app/src/styles/layout/sidebar.scss | 28 +-- 10 files changed, 252 insertions(+), 252 deletions(-) diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index eaa7701..6925853 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -458,7 +458,7 @@ export function InfoIcon() { > { -
{ if (activeModule !== "market") { @@ -29,7 +29,7 @@ const Header: React.FC = () => { }} > -
+ ); }; diff --git a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx index 9d2889f..9b16186 100644 --- a/app/src/components/layout/sidebarRight/analysis/Analysis.tsx +++ b/app/src/components/layout/sidebarRight/analysis/Analysis.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { AI_Icon } from "../../../icons/ExportCommonIcons"; +import { AIIcon } from "../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../ui/inputs/RegularDropDown"; import { AnalysisPresetsType } from "../../../../types/analysis"; import RenderAnalysisInputs from "./RenderAnalysisInputs"; @@ -13,53 +13,24 @@ const Analysis: React.FC = () => { const AnalysisPresets: AnalysisPresetsType = { "Throughput time": [ - { type: "default", inputs: { label: "Height", activeOption: "mm" } }, - { type: "default", inputs: { label: "Width", activeOption: "mm" } }, - { type: "default", inputs: { label: "Length", activeOption: "mtr" } }, - { type: "default", inputs: { label: "Thickness", activeOption: "mm" } }, - { - type: "default", - inputs: { label: "Raw Material", activeOption: "mm" }, - }, - { - type: "range", - inputs: { label: "Material flow", activeOption: "m/min" }, - }, + { type: "default", inputs: { label: "Cycle time", activeOption: "s" } }, + { type: "default", inputs: { label: "machines / lines", activeOption: "item" } }, + { type: "default", inputs: { label: "Machine uptime", activeOption: "%" } }, ], "Production capacity": [ - { type: "default", inputs: { label: "Height", activeOption: "mm" } }, - { type: "default", inputs: { label: "Width", activeOption: "mm" } }, - { type: "default", inputs: { label: "Length", activeOption: "mtr" } }, - { type: "default", inputs: { label: "Thickness", activeOption: "mm" } }, - { - type: "default", - inputs: { label: "Raw Material", activeOption: "mm" }, - }, - { - type: "range", - inputs: { label: "Material flow", activeOption: "m/min" }, - }, - { - type: "range", - inputs: { label: "Shift 1", activeOption: "hr(s)" }, - }, - { - type: "range", - inputs: { label: "Shift 2", activeOption: "hr(s)" }, - }, - { - type: "range", - inputs: { label: "Over time", activeOption: "hr(s)" }, - }, + { type: "default", inputs: { label: "Shift length", activeOption: "hr" } }, + { type: "default", inputs: { label: "Shifts / day", activeOption: "unit" } }, + { type: "default", inputs: { label: "Working days / year", activeOption: "days" } }, + { type: "default", inputs: { label: "Yield rate", activeOption: "%" } }, ], ROI: [ { type: "default", - inputs: { label: "Equipment Cost", activeOption: "INR" }, + inputs: { label: "Selling price", activeOption: "INR" }, }, { type: "default", - inputs: { label: "Employee Salary", activeOption: "INR" }, + inputs: { label: "Material cost", activeOption: "INR" }, }, { type: "default", @@ -67,7 +38,7 @@ const Analysis: React.FC = () => { }, { type: "default", - inputs: { label: "Cost per unit", activeOption: "INR" }, + inputs: { label: "Maintenance cost", activeOption: "INR" }, }, { type: "default", @@ -75,20 +46,19 @@ const Analysis: React.FC = () => { }, { type: "default", - inputs: { label: "Upkeep Cost", activeOption: "INR" }, + inputs: { label: "Fixed costs", activeOption: "INR" }, }, { type: "default", - inputs: { label: "Working Hours", activeOption: "Hrs" }, + inputs: { label: "Salvage value", activeOption: "Hrs" }, }, { type: "default", - inputs: { label: "Power Usage", activeOption: "KWH" }, + inputs: { label: "Production period", activeOption: "yrs" }, }, - { type: "default", inputs: { label: "KWH", activeOption: "Mos" } }, { type: "default", - inputs: { label: "Man Power", activeOption: "Person" }, + inputs: { label: "Tax rate", activeOption: "%" }, }, ], }; @@ -98,7 +68,7 @@ const Analysis: React.FC = () => {
Object
- Generate Report + Generate Report
@@ -121,7 +91,7 @@ const Analysis: React.FC = () => { />
- +
Create Custom Analysis
diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index 8b91afc..514808a 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import InputRange from "../../../ui/inputs/InputRange"; import InputToggle from "../../../ui/inputs/InputToggle"; -import { AI_Icon } from "../../../icons/ExportCommonIcons"; +import { AIIcon } from "../../../icons/ExportCommonIcons"; import LabeledButton from "../../../ui/inputs/LabledButton"; import { useAzimuth, @@ -225,7 +225,7 @@ const GlobalProperties: React.FC = () => {
Environment
- + Optimize
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index 4fa9105..053fc14 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useState } from "react"; import { - useSelectedEventData, - useSelectedEventSphere, - useSelectedProduct, + useSelectedEventData, + useSelectedEventSphere, + useSelectedProduct, } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import ConveyorMechanics from "./mechanics/conveyorMechanics"; @@ -15,114 +15,118 @@ import { handleAddEventToProduct } from "../../../../../modules/simulation/event import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; const EventProperties: React.FC = () => { - const { selectedEventData } = useSelectedEventData(); - const { getEventByModelUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); - const [currentEventData, setCurrentEventData] = useState(null); - const [assetType, setAssetType] = useState(null); - const { products, addEvent } = useProductStore(); - const { selectedEventSphere } = useSelectedEventSphere(); + const { selectedEventData } = useSelectedEventData(); + const { getEventByModelUuid } = useProductStore(); + const { selectedProduct } = useSelectedProduct(); + const [currentEventData, setCurrentEventData] = useState( + null + ); + const [assetType, setAssetType] = useState(null); + const { products, addEvent } = useProductStore(); + const { selectedEventSphere } = useSelectedEventSphere(); - useEffect(() => { - const event = getCurrentEventData(); - setCurrentEventData(event); + useEffect(() => { + const event = getCurrentEventData(); + setCurrentEventData(event); - const type = determineAssetType(event); - setAssetType(type); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedEventData, selectedProduct]); - - const getCurrentEventData = () => { - if (!selectedEventData?.data || !selectedProduct) return null; - return ( - getEventByModelUuid( - selectedProduct.productId, - selectedEventData.data.modelUuid - ) ?? null - ); - }; - - const determineAssetType = (event: EventsSchema | null) => { - if (!event) return null; - - switch (event.type) { - case "transfer": - return "conveyor"; - case "vehicle": - return "vehicle"; - case "roboticArm": - return "roboticArm"; - case "machine": - return "machine"; - case "storageUnit": - return "storageUnit"; - default: - return null; - } - }; + const type = determineAssetType(event); + setAssetType(type); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedEventData, selectedProduct]); + const getCurrentEventData = () => { + if (!selectedEventData?.data || !selectedProduct) return null; return ( -
- {currentEventData && ( - <> -
-
- {selectedEventData?.data.modelName} -
-
- {assetType === "conveyor" && } - {assetType === "vehicle" && } - {assetType === "roboticArm" && } - {assetType === "machine" && } - {assetType === "storageUnit" && } - - )} - {!currentEventData && selectedEventSphere && ( -
-

- Oops! It looks like this object doesn't have an - event assigned yet. To continue, please link it to one of the - products below. -

- -
-

- Here are some products you can add it to: -

-
    - {products.map((product) => ( -
  • - -
  • - ))} -
-
-
- ) - } - {!selectedEventSphere && ( -
-

- Oops! It looks like you haven't selected an event - point yet. Please select an event to view its properties. -

-
- )} -
+ getEventByModelUuid( + selectedProduct.productId, + selectedEventData.data.modelUuid + ) ?? null ); + }; + + const determineAssetType = (event: EventsSchema | null) => { + if (!event) return null; + + switch (event.type) { + case "transfer": + return "conveyor"; + case "vehicle": + return "vehicle"; + case "roboticArm": + return "roboticArm"; + case "machine": + return "machine"; + case "storageUnit": + return "storageUnit"; + default: + return null; + } + }; + + return ( +
+ {currentEventData && ( + <> +
+
+ {selectedEventData?.data.modelName} +
+
+ {assetType === "conveyor" && } + {assetType === "vehicle" && } + {assetType === "roboticArm" && } + {assetType === "machine" && } + {assetType === "storageUnit" && } + + )} + {!currentEventData && selectedEventSphere && ( +
+

+ Oops! It looks like this object doesn't have an + event assigned yet. To continue, please link it to one of the + products below. +

+ +
+

+ Here are some products you can add it to: +

+
+ {products.map((product) => ( + + ))} +
+
+
+ )} + {!selectedEventSphere && ( +
+

+ Oops! It looks like you haven't selected an event + point yet. Please select an event to view its properties. +

+
+ )} +
+ ); }; export default EventProperties; diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 4c7c76d..901c537 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -12,25 +12,28 @@ import { EndIcon, ExpandIcon, HourlySimulationIcon, + InfoIcon, MonthlyROI, SpeedIcon, StartIcon, } from "../../icons/ExportCommonIcons"; import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; +import { useSubModuleStore } from "../../../store/useModuleStore"; const SimulationPlayer: React.FC = () => { const MAX_SPEED = 8; // Maximum speed + const isDragging = useRef(false); + const sliderRef = useRef(null); const [expand, setExpand] = useState(true); + const [playSimulation, setPlaySimulation] = useState(false); const { speed, setSpeed } = useAnimationPlaySpeed(); - const [playSimulation, setPlaySimulation] = useState(false); const { setIsPlaying } = usePlayButtonStore(); - const sliderRef = useRef(null); - const isDragging = useRef(false); const { setActiveTool } = useActiveTool(); const { isPaused, setIsPaused } = usePauseButtonStore(); const { isReset, setReset } = useResetButtonStore(); + const { subModule } = useSubModuleStore(); // Button functions const handleReset = () => { @@ -114,7 +117,7 @@ const SimulationPlayer: React.FC = () => { }; // Store colors for each process item - const [processColors, setProcessColors] = useState([]); + const [_, setProcessColors] = useState([]); // Generate colors on mount or when process changes useEffect(() => { @@ -162,50 +165,60 @@ const SimulationPlayer: React.FC = () => {
-
- {/* hourlySimulation */} -
-
-
- + {subModule === "analysis" && ( +
+ {/* hourlySimulation */} +
+
+
+ +
+
Hourly Simulation
+
+
+
-
Hourly Simulation
-
-
+ {/* dailyProduction */} +
+
+
+ +
+
Daily Production
+
+
+
+
+
+ {/* monthlyROI */} +
+
+
+ +
+
Monthly ROI
+
+
+
+
{" "}
- {/* dailyProduction */} -
-
-
- -
-
Daily Production
-
-
-
-
+ )} + {subModule === "simulations" && ( +
+ + {playSimulation + ? "Paused - system idle." + : "Running simulation..."}
- {/* monthlyROI */} -
-
-
- -
-
Monthly ROI
-
-
-
-
{" "} -
-
+ )}
- + {subModule === "analysis" && ( + + )}
@@ -330,37 +345,39 @@ const SimulationPlayer: React.FC = () => {
-
-
00:00
-
24:00
-
+ {subModule === "analysis" && ( +
+
00:00
+
24:00
- {process.map((item, index) => ( -
+
+ {process.map((item, index) => (
-
- ))} + key={index} + className="process" + style={{ + width: `${item.completed}%`, + backgroundColor: getAvatarColor(index), + }} + > +
+
+ ))} +
-
+ )}
); diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index caf37a1..ad24e58 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -76,8 +76,6 @@ const RealTimeVisulization: React.FC = () => { const { setSelectedChartId } = useWidgetStore(); const [waitingPanels, setWaitingPanels] = useState(null); - console.log("waitingPanels: ", waitingPanels); - OuterClick({ contextClassName: [ "chart-container", diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss index 0fc3df8..f40ead1 100644 --- a/app/src/styles/components/simulation/simulation.scss +++ b/app/src/styles/components/simulation/simulation.scss @@ -32,10 +32,17 @@ } .controls-container { - @include flex-center; + @include flex-space-between; gap: 12px; justify-content: space-between; - + .header{ + @include flex-center; + gap: 6px; + padding: 0 8px; + svg{ + scale: 1.3; + } + } .production-details, .controls-wrapper { @include flex-center; @@ -72,7 +79,7 @@ .expand-icon-container { @include flex-center; - padding: 6px 8px; + padding: 0 8px; cursor: pointer; } diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index e476c3c..0a23871 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -124,6 +124,8 @@ padding: 4px; border-radius: #{$border-radius-medium}; background: var(--background-color); + outline: 1px solid var(--border-color); + outline-offset: -1px; gap: 5px; position: relative; diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index c7f1694..f23d08e 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -58,12 +58,8 @@ fill: var(--icon-default-color-active); } &:hover { - rect { - stroke: var(--icon-default-color); - } - circle { - fill: var(--icon-default-color); - } + filter: saturate(0.8); + background: var(--background-color-accent); } } } @@ -714,10 +710,10 @@ .add-button { @include flex-center; - padding: 2px 4px; + padding: 4px 8px; background: var(--background-color-button); color: var(--text-button-color); - border-radius: #{$border-radius-small}; + border-radius: #{$border-radius-large}; cursor: pointer; outline: none; border: none; @@ -832,10 +828,10 @@ transform: translateX(4px); &:hover { - background: var(--accent-color); + background: var(--background-color-accent); path { - stroke: var(--primary-color); + stroke: var(--text-button-color); } } } @@ -1003,10 +999,10 @@ border-radius: 8px 0 0 8px; &:hover { - background: var(--accent-color); + background: var(--background-color-accent); path { - stroke: var(--primary-color); + stroke: var(--text-button-color); } } } @@ -1067,7 +1063,13 @@ .dropdown-content-container { padding: 6px 12px; } - + .value-field-container { + padding: 6px; + .dropdown { + min-width: 44px; + text-align: center; + } + } .input-range-container { .input-container { width: 75%; From 4b7a868d1afbc499f671c6459781fda85375fa36 Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Fri, 2 May 2025 17:14:36 +0530 Subject: [PATCH 2/9] added logs list --- app/src/app.tsx | 28 ++-- .../components/icons/ExportCommonIcons.tsx | 150 +++++++++++++++--- .../ui/analysis/ThroughputSummary.tsx | 9 +- app/src/components/ui/footer/Footer.tsx | 44 +++++ app/src/components/ui/log/LogList.tsx | 87 ++++++++++ app/src/components/ui/log/LoggerContext.tsx | 77 +++++++++ app/src/components/ui/log/logger.ts | 71 +++++++++ .../ui/simulation/simulationPlayer.tsx | 14 +- app/src/pages/Project.tsx | 13 +- app/src/styles/components/footer/footer.scss | 56 +++++++ app/src/styles/components/logs/logs.scss | 75 +++++++++ .../components/simulation/simulation.scss | 21 +++ app/src/styles/layout/sidebar.scss | 4 +- app/src/styles/main.scss | 2 + app/src/styles/pages/realTimeViz.scss | 4 +- 15 files changed, 604 insertions(+), 51 deletions(-) create mode 100644 app/src/components/ui/footer/Footer.tsx create mode 100644 app/src/components/ui/log/LogList.tsx create mode 100644 app/src/components/ui/log/LoggerContext.tsx create mode 100644 app/src/components/ui/log/logger.ts create mode 100644 app/src/styles/components/footer/footer.scss create mode 100644 app/src/styles/components/logs/logs.scss diff --git a/app/src/app.tsx b/app/src/app.tsx index f5e19b0..af3284b 100644 --- a/app/src/app.tsx +++ b/app/src/app.tsx @@ -4,23 +4,23 @@ import Dashboard from "./pages/Dashboard"; import Project from "./pages/Project"; import UserAuth from "./pages/UserAuth"; import ToastProvider from "./components/templates/ToastProvider"; -import "./styles/main.scss" +import "./styles/main.scss"; +import { LoggerProvider } from "./components/ui/log/LoggerContext"; const App: React.FC = () => { return ( - - - - } - /> - } /> - } /> - - - + + + + + } /> + } /> + } /> + + + + ); }; -export default App; +export default App; \ No newline at end of file diff --git a/app/src/components/icons/ExportCommonIcons.tsx b/app/src/components/icons/ExportCommonIcons.tsx index 8e03fd0..67d7211 100644 --- a/app/src/components/icons/ExportCommonIcons.tsx +++ b/app/src/components/icons/ExportCommonIcons.tsx @@ -785,21 +785,135 @@ export const SpeedIcon = () => { ); }; -// export const DublicateIcon = () => { -// return ( -// -// -// -// ); -// }; +export const LogListIcon = () => { + return ( + + + + ); +}; + +export const LogTickIcon = () => { + return ( + + + + + + + + + + + ); +}; + +export const LogInfoIcon = () => { + return ( + + + + + + + ); +}; + +export const WarningIcon = () => { + return ( + + + + + + + ); +}; + +export const ErrorIcon = () => { + return ( + + + + ); +}; diff --git a/app/src/components/ui/analysis/ThroughputSummary.tsx b/app/src/components/ui/analysis/ThroughputSummary.tsx index b92a82d..e9946ae 100644 --- a/app/src/components/ui/analysis/ThroughputSummary.tsx +++ b/app/src/components/ui/analysis/ThroughputSummary.tsx @@ -8,6 +8,7 @@ import { PointElement, } from "chart.js"; import { PowerIcon, ThroughputSummaryIcon } from "../../icons/analysis"; +import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; ChartJS.register(LineElement, CategoryScale, LinearScale, PointElement); @@ -142,13 +143,13 @@ const ThroughputSummary = () => {
{/* Dynamically create progress bars based on shiftUtilization array */} - {shiftUtilization.map((shift) => ( + {shiftUtilization.map((shift, index) => (
))} @@ -156,11 +157,11 @@ const ThroughputSummary = () => {
{/* Dynamically create shift indicators with random colors */} - {shiftUtilization.map((shift) => ( + {shiftUtilization.map((shift, index) => (
diff --git a/app/src/components/ui/footer/Footer.tsx b/app/src/components/ui/footer/Footer.tsx new file mode 100644 index 0000000..93da68c --- /dev/null +++ b/app/src/components/ui/footer/Footer.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { HelpIcon } from "../../icons/DashboardIcon"; +import { useLogger } from "../log/LoggerContext"; + +const Footer = () => { + const { logs, setIsLogListVisible } = useLogger(); + + const lastLog = logs.length > 0 ? logs[logs.length - 1] : null; + + return ( +
+
+
+
+
Selection
+
+
+
+
Rotate/Zoom
+
+
+
+
Pan/Context Menu
+
+
+ +
+
setIsLogListVisible(true)}> + {lastLog + ? `[${lastLog.type.toUpperCase()}] ${lastLog.message}` + : "No logs yet."} +
+
+ V 0.01 +
+ +
+
+
+
+ ); +}; + +export default Footer; diff --git a/app/src/components/ui/log/LogList.tsx b/app/src/components/ui/log/LogList.tsx new file mode 100644 index 0000000..4a43933 --- /dev/null +++ b/app/src/components/ui/log/LogList.tsx @@ -0,0 +1,87 @@ +// LogList.tsx +import React, { useState } from "react"; +import { + LogListIcon, + TickIcon, + LogInfoIcon, + WarningIcon, + ErrorIcon, +} from "../../icons/ExportCommonIcons"; // Adjust path as needed +import { useLogger } from "./LoggerContext"; + +const LogList: React.FC = () => { + const { logs, clear, setIsLogListVisible } = useLogger(); + const [selectedTab, setSelectedTab] = useState< + "all" | "info" | "warning" | "error" | "log" + >("all"); + + const getLogIcon = (type: string) => { + switch (type) { + case "info": + return ; + case "error": + return ; + case "warning": + return ; + case "log": + default: + return ; + } + }; + + const formatTimestamp = (date: Date) => new Date(date).toLocaleTimeString(); + + const filteredLogs = + selectedTab === "all" + ? [...logs].reverse() + : [...logs].filter((log) => log.type === selectedTab).reverse(); + + return ( +
+
+
+
+
+ +
+
Log List
+
+
setIsLogListVisible(false)}> + X +
+
+ + {/* Tabs */} +
+ {["all", "info", "warning", "error"].map((type) => ( +
setSelectedTab(type as any)} + > + {`${type.charAt(0).toUpperCase() + type.slice(1)} Logs`} +
+ ))} +
+ + {/* Log Entries */} +
+ {filteredLogs.map((log) => ( +
+
+ +
+
{getLogIcon(log.type)}
+
+ [{formatTimestamp(log.timestamp)}] [{log.type.toUpperCase()}]{" "} + {log.message} +
+
+ ))} +
+
+
+ ); +}; + +export default LogList; diff --git a/app/src/components/ui/log/LoggerContext.tsx b/app/src/components/ui/log/LoggerContext.tsx new file mode 100644 index 0000000..f323b93 --- /dev/null +++ b/app/src/components/ui/log/LoggerContext.tsx @@ -0,0 +1,77 @@ +import React, { createContext, useContext, useState, useCallback } from "react"; + +export type LogType = "log" | "info" | "warning" | "error"; + +export interface LogEntry { + id: string; + type: LogType; + message: string; + timestamp: Date; +} + +interface LoggerContextValue { + logs: LogEntry[]; + setLogs: React.Dispatch>; + isLogListVisible: boolean; + setIsLogListVisible: React.Dispatch>; + log: (message: string) => void; + info: (message: string) => void; + warn: (message: string) => void; + error: (message: string) => void; + clear: () => void; +} + +const LoggerContext = createContext(undefined); + +export const LoggerProvider: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const [logs, setLogs] = useState([]); + const [isLogListVisible, setIsLogListVisible] = useState(false); + + const generateId = useCallback( + () => Math.random().toString(36).substring(2, 9), + [] + ); + + const addLog = useCallback( + (type: LogType, message: string) => { + const newLog: LogEntry = { + id: generateId(), + type, + message, + timestamp: new Date(), + }; + setLogs((prevLogs) => [...prevLogs, newLog]); + }, + [generateId] + ); + + const loggerMethods: LoggerContextValue = { + logs, + setLogs, + isLogListVisible, + setIsLogListVisible, + log: (message: string) => addLog("log", message), + info: (message: string) => addLog("info", message), + warn: (message: string) => addLog("warning", message), + error: (message: string) => addLog("error", message), + clear: () => { + setLogs([]); + }, + }; + + return ( + + {children} + + ); +}; + +export const useLogger = () => { + const context = useContext(LoggerContext); + if (!context) { + throw new Error("useLogger must be used within a LoggerProvider"); + } + return context; +}; diff --git a/app/src/components/ui/log/logger.ts b/app/src/components/ui/log/logger.ts new file mode 100644 index 0000000..1781e26 --- /dev/null +++ b/app/src/components/ui/log/logger.ts @@ -0,0 +1,71 @@ +type LogType = 'log' | 'info' | 'warning' | 'error'; + +interface LogEntry { + type: LogType; + message: string; + timestamp: Date; + context?: string; +} + +class Logger { + private static instance: Logger; + private logs: LogEntry[] = []; + private subscribers: Array<(log: LogEntry) => void> = []; + + private constructor() {} + + public static getInstance(): Logger { + if (!Logger.instance) { + Logger.instance = new Logger(); + } + return Logger.instance; + } + + private notifySubscribers(log: LogEntry) { + this.subscribers.forEach(callback => callback(log)); + } + + private addLog(type: LogType, message: string, context?: string) { + const log: LogEntry = { type, message, timestamp: new Date(), context }; + this.logs.push(log); + this.notifySubscribers(log); + + if (process.env.NODE_ENV === 'development') { + const logMessage = context ? `[${context}] ${message}` : message; + console[type === 'warning' ? 'warn' : type](logMessage); + } + } + + public log(message: string, context?: string) { + this.addLog('log', message, context); + } + + public info(message: string, context?: string) { + this.addLog('info', message, context); + } + + public warning(message: string, context?: string) { + this.addLog('warning', message, context); + } + + public error(message: string, context?: string) { + this.addLog('error', message, context); + } + + public getLogs(): LogEntry[] { + return [...this.logs]; + } + + public clear() { + this.logs = []; + } + + public subscribe(callback: (log: LogEntry) => void) { + this.subscribers.push(callback); + return () => { + this.subscribers = this.subscribers.filter(sub => sub !== callback); + }; + } +} + +export const logger = Logger.getInstance(); diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 86c5372..6ab6738 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -16,6 +16,7 @@ import { SpeedIcon, StartIcon, } from "../../icons/ExportCommonIcons"; +import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; const SimulationPlayer: React.FC = () => { const { speed, setSpeed } = useAnimationPlaySpeed(); @@ -110,15 +111,6 @@ const SimulationPlayer: React.FC = () => { return color; }; - // Store colors for each process item - const [processColors, setProcessColors] = useState([]); - - // Generate colors on mount or when process changes - useEffect(() => { - const generatedColors = process.map(() => getRandomColor()); - setProcessColors(generatedColors); - }, []); - const intervals = [10, 20, 30, 40, 50, 60]; // in minutes const totalSegments = intervals.length; const progress = 20; // percent (example) @@ -328,6 +320,8 @@ const SimulationPlayer: React.FC = () => {
+
00:00
+
24:00
{ className="process" style={{ width: `${item.completed}%`, - backgroundColor: processColors[index], + backgroundColor: getAvatarColor(index), }} >
))} diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index bdefb8b..c3b70e7 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -25,6 +25,10 @@ import FollowPerson from "../components/templates/FollowPerson"; import ProductionCapacity from "../components/ui/analysis/ProductionCapacity"; import ThroughputSummary from "../components/ui/analysis/ThroughputSummary"; import ROISummary from "../components/ui/analysis/ROISummary"; +import Footer from "../components/ui/footer/Footer"; +import RenderOverlay from "../components/templates/Overlay"; +import LogList from "../components/ui/log/LogList"; +import { useLogger } from "../components/ui/log/LoggerContext"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -58,6 +62,7 @@ const Project: React.FC = () => { const { isPlaying } = usePlayButtonStore(); const { toggleThreeD } = useThreeDStore(); const { selectedUser } = useSelectedUserStore(); + const { isLogListVisible } = useLogger(); return (
@@ -69,7 +74,7 @@ const Project: React.FC = () => {
*/} - {loadingProgress > 0 && } + {/* {loadingProgress > 0 && } */} {!isPlaying && ( <> {toggleThreeD && } @@ -85,7 +90,13 @@ const Project: React.FC = () => { {activeModule !== "market" && } {isPlaying && activeModule === "simulation" && } {/* {} */} + {isLogListVisible && ( + + + + )} {selectedUser && } +
); }; diff --git a/app/src/styles/components/footer/footer.scss b/app/src/styles/components/footer/footer.scss new file mode 100644 index 0000000..a595db0 --- /dev/null +++ b/app/src/styles/components/footer/footer.scss @@ -0,0 +1,56 @@ +.footer-wrapper { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + z-index: 1; + display: flex; + justify-content: space-between; + + .selection-wrapper { + display: flex; + gap: 6px; + + .selector-wrapper { + display: flex; + gap: 6px; + align-items: center; + background: var(--background-color); + padding: 4px 6px; + border-radius: 12px; + color: var(--text-color); + + .selector { + color: var(--text-button-color); + font-weight: 200; + } + } + } + + .logs-wrapper { + display: flex; + gap: 6px; + + .logs-detail, + .version { + border-radius: 12px; + background: var(--background-color); + padding: 4px 6px; + color: var(--text-button-color); + font-weight: 200; + display: flex; + align-items: center; + } + + .logs-detail { + background-color: #fff; + cursor: pointer; + } + + .version { + display: flex; + gap: 6px; + + } + } +} \ No newline at end of file diff --git a/app/src/styles/components/logs/logs.scss b/app/src/styles/components/logs/logs.scss new file mode 100644 index 0000000..99e7548 --- /dev/null +++ b/app/src/styles/components/logs/logs.scss @@ -0,0 +1,75 @@ +.log-list-container { + width: 100vw; + height: 100vh; + background: var(--background-color-secondary); + backdrop-filter: blur(2px); + + .log-list-wrapper { + height: 50%; + min-width: 50%; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 5; + background: var(--background-color); + padding: 14px 12px; + border-radius: 15px; + display: flex; + flex-direction: column; + gap: 12px; + + .log-header { + display: flex; + justify-content: space-between; + + .log-header-wrapper { + display: flex; + align-items: center; + gap: 6px; + } + + .close { + cursor: pointer; + } + } + + .log-nav-wrapper { + display: flex; + gap: 6px; + + .log-nav { + padding: 8px 16px; + border-radius: 19px; + } + + .log-nav.active { + background-color: var(--accent-color); + color: var(--text-button-color); + } + } + + .log-entry-wrapper { + height: 100%; + display: flex; + flex-direction: column; + gap: 4px; + background: var(--background-color); + padding: 18px 10px; + border-radius: 16px; + + .log-entry { + padding: 4px; + border-radius: 4px; + font-size: var(--font-size-small); + display: flex; + align-items: center; + gap: 6px; + + &:nth-child(odd) { + background: var(--background-color); + } + } + } + } +} \ No newline at end of file diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss index ec53e6f..61655e4 100644 --- a/app/src/styles/components/simulation/simulation.scss +++ b/app/src/styles/components/simulation/simulation.scss @@ -312,6 +312,22 @@ padding: 14px 6px; position: relative; + .timmer { + width: auto; + position: absolute; + bottom: 0; + font-size: var(--font-size-tiny); + } + + .start-displayer { + left: 8px; + } + + .end-displayer { + width: auto; + right: 8px; + } + .process-player { position: absolute; top: 50%; @@ -344,6 +360,11 @@ .simulation-player-container.open { + .start-displayer, + .end-displayer { + display: none; + } + .progresser-wrapper { padding-top: 4px; } diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index c7f1694..f4ccaa8 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -420,7 +420,7 @@ outline: none; path { stroke: var(--text-button-color); - stroke-width: 1.3; + strokeWidth: 1.3; } } } @@ -686,7 +686,7 @@ path { stroke: var(--accent-color); - stroke-width: 1.5px; + strokeWidth: 1.5px; } &:hover { diff --git a/app/src/styles/main.scss b/app/src/styles/main.scss index 66a60e7..9fe7222 100644 --- a/app/src/styles/main.scss +++ b/app/src/styles/main.scss @@ -27,6 +27,8 @@ @use 'components/confirmationPopUp'; @use 'components/analysis/analysis'; @use 'components/analysis/ROISummary.scss'; +@use 'components/logs/logs'; +@use 'components/footer/footer.scss'; // layout @use 'layout/loading'; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 7348eff..b5fff7e 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -416,7 +416,7 @@ path { stroke: var(--text-color); - stroke-width: 2; + strokeWidth: 2; } } @@ -428,7 +428,7 @@ path { stroke: #f65648; - stroke-width: 1.3; + strokeWidth: 1.3; } From 44e3f5c207cf5090186bbb85575046dc606e3b90 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Fri, 2 May 2025 17:39:11 +0530 Subject: [PATCH 3/9] Refactor RealTimeVisualization component and handle widget drop functionality - Commented out the handleDrop function in RealTimeVisualization.tsx and moved its logic to a new utility function createHandleDrop for better separation of concerns. - Updated Project.tsx to utilize the new createHandleDrop function, improving readability and maintainability. - Enhanced styling for the scene container and real-time visualization components to improve layout and responsiveness. - Removed unnecessary styles and consolidated button and input styles for consistency. - Cleaned up unused imports and variables in various files to streamline the codebase. --- app/src/components/icons/SimulationIcons.tsx | 12 +- app/src/components/ui/Tools.tsx | 497 +++++++++--------- .../ui/simulation/simulationPlayer.tsx | 435 +++++++-------- .../visualization/RealTimeVisulization.tsx | 193 +++---- .../visualization/functions/handleUiDrop.ts | 122 +++++ app/src/pages/Project.tsx | 81 ++- .../visualization/useDroppedObjectsStore.ts | 1 - app/src/styles/base/global.scss | 32 +- app/src/styles/base/reset.scss | 7 - .../components/analysis/ROISummary.scss | 16 +- .../styles/components/analysis/analysis.scss | 466 ++++++++-------- app/src/styles/components/button.scss | 24 + app/src/styles/components/input.scss | 15 - app/src/styles/components/tools.scss | 2 +- app/src/styles/pages/realTimeViz.scss | 26 +- 15 files changed, 1031 insertions(+), 898 deletions(-) create mode 100644 app/src/modules/visualization/functions/handleUiDrop.ts diff --git a/app/src/components/icons/SimulationIcons.tsx b/app/src/components/icons/SimulationIcons.tsx index ef23c8f..1e89a51 100644 --- a/app/src/components/icons/SimulationIcons.tsx +++ b/app/src/components/icons/SimulationIcons.tsx @@ -125,21 +125,21 @@ export function ResetIcon() { > @@ -158,7 +158,7 @@ export function PlayStopIcon() { > @@ -177,7 +177,7 @@ export function ExitIcon() { > diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 21ea6a7..14bc517 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -36,7 +36,6 @@ import { import useToggleStore from "../../store/useUIToggleStore"; import { use3DWidget, - useDroppedObjectsStore, useFloatingWidget, } from "../../store/visualization/useDroppedObjectsStore"; @@ -57,20 +56,18 @@ const Tools: React.FC = () => { const { widgets3D } = use3DWidget(); - const zones = useDroppedObjectsStore((state) => state.zones); - // wall options const { toggleView, setToggleView } = useToggleView(); const { setDeleteTool } = useDeleteTool(); const { setAddAction } = useAddAction(); const { setSelectedWallItem } = useSelectedWallItem(); - const { transformMode, setTransformMode } = useTransformMode(); - const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); - const { movePoint, setMovePoint } = useMovePoint(); - const { toolMode, setToolMode } = useToolMode(); + const { setTransformMode } = useTransformMode(); + const { setDeletePointOrLine } = useDeletePointOrLine(); + const { setMovePoint } = useMovePoint(); + const { setToolMode } = useToolMode(); const { activeTool, setActiveTool } = useActiveTool(); - const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); + const { setRefTextUpdate } = useRefTextUpdate(); // Reset activeTool whenever activeModule changes useEffect(() => { @@ -209,268 +206,266 @@ const Tools: React.FC = () => { return ( <> {!isPlaying ? ( - <> -
-
-
- {activeSubTool == "cursor" && ( -
{ - setActiveTool("cursor"); - }} - > - -
- )} - {activeSubTool == "free-hand" && ( -
{ - setActiveTool("free-hand"); - }} - > - -
- )} - {activeSubTool == "delete" && ( -
{ - setActiveTool("delete"); - }} - > - -
- )} - {activeModule !== "visualization" && ( -
{ - setOpenDrop(!openDrop); - }} - > - - {openDrop && ( -
-
{ - setOpenDrop(false); - setActiveTool("cursor"); - setActiveSubTool("cursor"); - }} - > -
- {activeSubTool === "cursor" && } -
- -
Cursor
-
-
{ - setOpenDrop(false); - setActiveTool("free-hand"); - setActiveSubTool("free-hand"); - }} - > -
- {activeSubTool === "free-hand" && } -
- -
Free Hand
-
-
{ - setOpenDrop(false); - setActiveTool("delete"); - setActiveSubTool("delete"); - }} - > -
- {activeSubTool === "delete" && } -
- -
Delete
-
-
- )} -
- )} -
-
- {!toggleThreeD && activeModule === "builder" && ( - <> -
-
-
{ - setActiveTool("draw-wall"); - }} - title="Wall" - > - -
-
{ - setActiveTool("draw-zone"); - }} - title="Zone" - > - -
-
{ - setActiveTool("draw-aisle"); - }} - title="Aisle" - > - -
-
{ - setActiveTool("draw-floor"); - }} - title="Floor" - > - -
-
- - )} - {activeModule === "builder" && ( - <> -
-
-
{ - setActiveTool("measure"); - }} - title="Measure" - > - -
-
- - )} - {activeModule === "simulation" && ( - <> -
-
-
{ - setActiveTool("pen"); - }} - > - -
-
- - )} - {activeModule === "visualization" && ( - <> -
-
-
{ - handleSaveTemplate({ - addTemplate, - floatingWidget, - widgets3D, - selectedZone, - templates, - visualizationSocket, - }); - }} - > - -
-
- - )} -
-
-
{ - setActiveTool("comment"); - }} - > - -
- {toggleThreeD && ( +
+
+
+ {activeSubTool == "cursor" && (
{ - setIsPlaying(!isPlaying); + setActiveTool("cursor"); }} > - + +
+ )} + {activeSubTool == "free-hand" && ( +
{ + setActiveTool("free-hand"); + }} + > + +
+ )} + {activeSubTool == "delete" && ( +
{ + setActiveTool("delete"); + }} + > + +
+ )} + {activeModule !== "visualization" && ( +
{ + setOpenDrop(!openDrop); + }} + > + + {openDrop && ( +
+
{ + setOpenDrop(false); + setActiveTool("cursor"); + setActiveSubTool("cursor"); + }} + > +
+ {activeSubTool === "cursor" && } +
+ +
Cursor
+
+
{ + setOpenDrop(false); + setActiveTool("free-hand"); + setActiveSubTool("free-hand"); + }} + > +
+ {activeSubTool === "free-hand" && } +
+ +
Free Hand
+
+
{ + setOpenDrop(false); + setActiveTool("delete"); + setActiveSubTool("delete"); + }} + > +
+ {activeSubTool === "delete" && } +
+ +
Delete
+
+
+ )}
)}
- {activeModule === "builder" && ( - <> -
+
+ {!toggleThreeD && activeModule === "builder" && ( + <> +
+
{ + setActiveTool("draw-wall"); + }} + title="Wall" > -
- 2d -
-
- 3d -
+
- +
{ + setActiveTool("draw-zone"); + }} + title="Zone" + > + +
+
{ + setActiveTool("draw-aisle"); + }} + title="Aisle" + > + +
+
{ + setActiveTool("draw-floor"); + }} + title="Floor" + > + +
+
+ + )} + {activeModule === "builder" && ( + <> +
+
+
{ + setActiveTool("measure"); + }} + title="Measure" + > + +
+
+ + )} + {activeModule === "simulation" && ( + <> +
+
+
{ + setActiveTool("pen"); + }} + > + +
+
+ + )} + {activeModule === "visualization" && ( + <> +
+
+
{ + handleSaveTemplate({ + addTemplate, + floatingWidget, + widgets3D, + selectedZone, + templates, + visualizationSocket, + }); + }} + > + +
+
+ + )} +
+
+
{ + setActiveTool("comment"); + }} + > + +
+ {toggleThreeD && ( +
{ + setIsPlaying(!isPlaying); + }} + > + +
)}
- + {activeModule === "builder" && ( + <> +
+
+
+ 2d +
+
+ 3d +
+
+ + )} +
) : ( <> {activeModule !== "simulation" && ( -
setIsPlaying(false)}> +
+ )} )} diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 901c537..e569250 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -19,6 +19,9 @@ import { } from "../../icons/ExportCommonIcons"; import { getAvatarColor } from "../../../modules/collaboration/functions/getAvatarColor"; import { useSubModuleStore } from "../../../store/useModuleStore"; +import ProductionCapacity from "../analysis/ProductionCapacity"; +import ThroughputSummary from "../analysis/ThroughputSummary"; +import ROISummary from "../analysis/ROISummary"; const SimulationPlayer: React.FC = () => { const MAX_SPEED = 8; // Maximum speed @@ -162,224 +165,236 @@ const SimulationPlayer: React.FC = () => { }; return ( -
-
-
- {subModule === "analysis" && ( -
- {/* hourlySimulation */} -
-
-
- -
-
Hourly Simulation
-
-
-
-
-
- {/* dailyProduction */} -
-
-
- -
-
Daily Production
-
-
-
-
-
- {/* monthlyROI */} -
-
-
- -
-
Monthly ROI
-
-
-
-
{" "} -
-
- )} - {subModule === "simulations" && ( -
- - {playSimulation - ? "Paused - system idle." - : "Running simulation..."} -
- )} -
- - - + <> +
+
+
{subModule === "analysis" && ( - - )} -
-
-
-
-
-
- -
-
-
23 April ,25
-
04:41 PM
-
-
-
-
- {intervals.map((label, index) => { - const segmentProgress = (index / totalSegments) * 100; - const isFilled = progress >= segmentProgress; - return ( - -
-
{label} mins
-
-
- {index < intervals.length - 1 && ( -
= ((index + 1) / totalSegments) * 100 - ? "filled" - : "" - }`} - >
- )} -
- ); - })} -
-
- -
-
-
00:10:20
-
-
- -
-
-
-
-
-
- -
- Speed -
-
-
0.5X
-
-
-
-
-
-
-
-
-
-
- - -
-
4x
-
-
-
- {subModule === "analysis" && ( -
-
00:00
-
24:00
-
-
- {process.map((item, index) => ( -
+
+ {/* hourlySimulation */} +
+
+
+ +
+
Hourly Simulation
+
+
- ))} +
+ {/* dailyProduction */} +
+
+
+ +
+
Daily Production
+
+
+
+
+
+ {/* monthlyROI */} +
+
+
+ +
+
Monthly ROI
+
+
+
+
{" "} +
+
+ )} + {subModule === "simulations" && ( +
+ + {playSimulation + ? "Paused - system idle." + : "Running simulation..."} +
+ )} +
+ + + + {subModule === "analysis" && ( + + )} +
+
+
+
+
+
+ +
+
+
23 April ,25
+
04:41 PM
+
+
+
+
+ {intervals.map((label, index) => { + const segmentProgress = (index / totalSegments) * 100; + const isFilled = progress >= segmentProgress; + return ( + +
+
{label} mins
+
+
+ {index < intervals.length - 1 && ( +
= ((index + 1) / totalSegments) * 100 + ? "filled" + : "" + }`} + >
+ )} +
+ ); + })} +
+
+ +
+
+
00:10:20
+
+
+ +
+
+
+
+
+
+ +
+ Speed +
+
+
0.5X
+
+
+
+
+
+
+
+
+
+
+ + +
+
4x
- )} + {subModule === "analysis" && ( +
+
00:00
+
24:00
+
+
+ {process.map((item, index) => ( +
+
+
+ ))} +
+
+
+ )} +
-
+
+
+ + +
+ +
+ ); }; diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index ad24e58..dadaf9c 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -143,109 +143,109 @@ const RealTimeVisulization: React.FC = () => { }); }, [selectedZone]); - const handleDrop = async (event: React.DragEvent) => { - event.preventDefault(); - try { - const email = localStorage.getItem("email") ?? ""; - const organization = email?.split("@")[1]?.split(".")[0]; + // const handleDrop = async (event: React.DragEvent) => { + // event.preventDefault(); + // try { + // const email = localStorage.getItem("email") ?? ""; + // const organization = email?.split("@")[1]?.split(".")[0]; - const data = event.dataTransfer.getData("text/plain"); - if (widgetSubOption === "3D") return; - if (!data || selectedZone.zoneName === "") return; + // const data = event.dataTransfer.getData("text/plain"); + // if (widgetSubOption === "3D") return; + // if (!data || selectedZone.zoneName === "") return; - const droppedData = JSON.parse(data); - const canvasElement = document.getElementById("real-time-vis-canvas"); - if (!canvasElement) throw new Error("Canvas element not found"); + // const droppedData = JSON.parse(data); + // const canvasElement = document.getElementById("real-time-vis-canvas"); + // if (!canvasElement) throw new Error("Canvas element not found"); - const rect = canvasElement.getBoundingClientRect(); - const relativeX = event.clientX - rect.left; - const relativeY = event.clientY - rect.top; + // const rect = canvasElement.getBoundingClientRect(); + // const relativeX = event.clientX - rect.left; + // const relativeY = event.clientY - rect.top; - // Widget dimensions - const widgetWidth = droppedData.width ?? 125; - const widgetHeight = droppedData.height ?? 100; + // // Widget dimensions + // const widgetWidth = droppedData.width ?? 125; + // const widgetHeight = droppedData.height ?? 100; - // Center the widget at cursor - const centerOffsetX = widgetWidth / 2; - const centerOffsetY = widgetHeight / 2; + // // Center the widget at cursor + // const centerOffsetX = widgetWidth / 2; + // const centerOffsetY = widgetHeight / 2; - const adjustedX = relativeX - centerOffsetX; - const adjustedY = relativeY - centerOffsetY; + // const adjustedX = relativeX - centerOffsetX; + // const adjustedY = relativeY - centerOffsetY; - const finalPosition = determinePosition(rect, adjustedX, adjustedY); - const [activeProp1, activeProp2] = getActiveProperties(finalPosition); + // const finalPosition = determinePosition(rect, adjustedX, adjustedY); + // const [activeProp1, activeProp2] = getActiveProperties(finalPosition); - let finalY = 0; - let finalX = 0; + // let finalY = 0; + // let finalX = 0; - if (activeProp1 === "top") { - finalY = adjustedY; - } else { - finalY = rect.height - (adjustedY + widgetHeight); - } + // if (activeProp1 === "top") { + // finalY = adjustedY; + // } else { + // finalY = rect.height - (adjustedY + widgetHeight); + // } - if (activeProp2 === "left") { - finalX = adjustedX; - } else { - finalX = rect.width - (adjustedX + widgetWidth); - } + // if (activeProp2 === "left") { + // finalX = adjustedX; + // } else { + // finalX = rect.width - (adjustedX + widgetWidth); + // } - // Clamp to boundaries - finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX)); - finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY)); + // // Clamp to boundaries + // finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX)); + // finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY)); - const boundedPosition = { - ...finalPosition, - [activeProp1]: finalY, - [activeProp2]: finalX, - [activeProp1 === "top" ? "bottom" : "top"]: "auto", - [activeProp2 === "left" ? "right" : "left"]: "auto", - }; + // const boundedPosition = { + // ...finalPosition, + // [activeProp1]: finalY, + // [activeProp2]: finalX, + // [activeProp1 === "top" ? "bottom" : "top"]: "auto", + // [activeProp2 === "left" ? "right" : "left"]: "auto", + // }; - const newObject = { - ...droppedData, - id: generateUniqueId(), - position: boundedPosition, - }; + // const newObject = { + // ...droppedData, + // id: generateUniqueId(), + // position: boundedPosition, + // }; - const existingZone = - useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; - if (!existingZone) { - useDroppedObjectsStore - .getState() - .setZone(selectedZone.zoneName, selectedZone.zoneId); - } + // const existingZone = + // useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; + // if (!existingZone) { + // useDroppedObjectsStore + // .getState() + // .setZone(selectedZone.zoneName, selectedZone.zoneId); + // } - const addFloatingWidget = { - organization, - widget: newObject, - zoneId: selectedZone.zoneId, - }; + // const addFloatingWidget = { + // organization, + // widget: newObject, + // zoneId: selectedZone.zoneId, + // }; - if (visualizationSocket) { - visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); - } + // if (visualizationSocket) { + // visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); + // } - useDroppedObjectsStore - .getState() - .addObject(selectedZone.zoneName, newObject); + // useDroppedObjectsStore + // .getState() + // .addObject(selectedZone.zoneName, newObject); - const droppedObjectsStore = useDroppedObjectsStore.getState(); - const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; + // const droppedObjectsStore = useDroppedObjectsStore.getState(); + // const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; - if (currentZone && currentZone.zoneId === selectedZone.zoneId) { - console.log( - `Objects for Zone ${selectedZone.zoneId}:`, - currentZone.objects - ); - setFloatingWidget(currentZone.objects); - } else { - console.warn("Zone not found or zoneId mismatch"); - } - } catch (error) { - console.error("Error in handleDrop:", error); - } - }; + // if (currentZone && currentZone.zoneId === selectedZone.zoneId) { + // console.log( + // `Objects for Zone ${selectedZone.zoneId}:`, + // currentZone.objects + // ); + // setFloatingWidget(currentZone.objects); + // } else { + // console.warn("Zone not found or zoneId mismatch"); + // } + // } catch (error) { + // console.error("Error in handleDrop:", error); + // } + // }; useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -302,16 +302,7 @@ const RealTimeVisulization: React.FC = () => { } `} -
+
{openConfirmationPopup && ( @@ -322,20 +313,6 @@ const RealTimeVisulization: React.FC = () => { /> )} -
handleDrop(event)} - onDragOver={(event) => event.preventDefault()} - > - -
{activeModule === "visualization" && selectedZone.zoneName !== "" && ( )} diff --git a/app/src/modules/visualization/functions/handleUiDrop.ts b/app/src/modules/visualization/functions/handleUiDrop.ts new file mode 100644 index 0000000..a70742e --- /dev/null +++ b/app/src/modules/visualization/functions/handleUiDrop.ts @@ -0,0 +1,122 @@ +import { generateUniqueId } from "../../../functions/generateUniqueId"; +import { useDroppedObjectsStore } from "../../../store/visualization/useDroppedObjectsStore"; +import { determinePosition } from "./determinePosition"; +import { getActiveProperties } from "./getActiveProperties"; + +interface HandleDropProps { + widgetSubOption: any; + visualizationSocket: any; + selectedZone: any; + setFloatingWidget: (value: any) => void; + event: React.DragEvent +} + +export const createHandleDrop = ({ + widgetSubOption, + visualizationSocket, + selectedZone, + setFloatingWidget, + event, +}: HandleDropProps) => { + event.preventDefault(); + try { + const email = localStorage.getItem("email") ?? ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + const data = event.dataTransfer.getData("text/plain"); + if (widgetSubOption === "3D") return; + if (!data || selectedZone.zoneName === "") return; + + const droppedData = JSON.parse(data); + const canvasElement = document.getElementById("real-time-vis-canvas"); + if (!canvasElement) throw new Error("Canvas element not found"); + + const rect = canvasElement.getBoundingClientRect(); + const relativeX = event.clientX - rect.left; + const relativeY = event.clientY - rect.top; + + // Widget dimensions + const widgetWidth = droppedData.width ?? 125; + const widgetHeight = droppedData.height ?? 100; + + // Center the widget at cursor + const centerOffsetX = widgetWidth / 2; + const centerOffsetY = widgetHeight / 2; + + const adjustedX = relativeX - centerOffsetX; + const adjustedY = relativeY - centerOffsetY; + + const finalPosition = determinePosition(rect, adjustedX, adjustedY); + const [activeProp1, activeProp2] = getActiveProperties(finalPosition); + + let finalY = 0; + let finalX = 0; + + if (activeProp1 === "top") { + finalY = adjustedY; + } else { + finalY = rect.height - (adjustedY + widgetHeight); + } + + if (activeProp2 === "left") { + finalX = adjustedX; + } else { + finalX = rect.width - (adjustedX + widgetWidth); + } + + // Clamp to boundaries + finalX = Math.max(0, Math.min(rect.width - widgetWidth, finalX)); + finalY = Math.max(0, Math.min(rect.height - widgetHeight, finalY)); + + const boundedPosition = { + ...finalPosition, + [activeProp1]: finalY, + [activeProp2]: finalX, + [activeProp1 === "top" ? "bottom" : "top"]: "auto", + [activeProp2 === "left" ? "right" : "left"]: "auto", + }; + + const newObject = { + ...droppedData, + id: generateUniqueId(), + position: boundedPosition, + }; + + const existingZone = + useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; + if (!existingZone) { + useDroppedObjectsStore + .getState() + .setZone(selectedZone.zoneName, selectedZone.zoneId); + } + + const addFloatingWidget = { + organization, + widget: newObject, + zoneId: selectedZone.zoneId, + }; + + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); + } + + useDroppedObjectsStore + .getState() + .addObject(selectedZone.zoneName, newObject); + + const droppedObjectsStore = useDroppedObjectsStore.getState(); + const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; + + if (currentZone && currentZone.zoneId === selectedZone.zoneId) { + console.log( + `Objects for Zone ${selectedZone.zoneId}:`, + currentZone.objects + ); + setFloatingWidget(currentZone.objects); + } else { + console.warn("Zone not found or zoneId mismatch"); + } + } catch (error) { + console.error("Error in handleDrop:", error); + } +}; diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index bdefb8b..9bb7d0b 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -13,6 +13,7 @@ import { useWallItems, useZones, useLoadingProgress, + useWidgetSubOption, } from "../store/store"; import { useNavigate } from "react-router-dom"; import { usePlayButtonStore } from "../store/usePlayButtonStore"; @@ -22,9 +23,10 @@ import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys"; import { useSelectedUserStore } from "../store/useCollabStore"; import FollowPerson from "../components/templates/FollowPerson"; -import ProductionCapacity from "../components/ui/analysis/ProductionCapacity"; -import ThroughputSummary from "../components/ui/analysis/ThroughputSummary"; -import ROISummary from "../components/ui/analysis/ROISummary"; +import Scene from "../modules/scene/scene"; +import { createHandleDrop } from "../modules/visualization/functions/handleUiDrop"; +import { useSelectedZoneStore } from "../store/visualization/useZoneStore"; +import { useFloatingWidget } from "../store/visualization/useDroppedObjectsStore"; const Project: React.FC = () => { let navigate = useNavigate(); @@ -53,38 +55,67 @@ const Project: React.FC = () => { } else { navigate("/"); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const { isPlaying } = usePlayButtonStore(); + // global store const { toggleThreeD } = useThreeDStore(); + + // simulation store + const { isPlaying } = usePlayButtonStore(); + + // collaboration store const { selectedUser } = useSelectedUserStore(); + // real-time visualization store + const { widgetSubOption } = useWidgetSubOption(); + const { visualizationSocket } = useSocketStore(); + const { selectedZone } = useSelectedZoneStore(); + const { setFloatingWidget } = useFloatingWidget(); + return (
- {/*
-
- - -
- -
*/} - - {loadingProgress > 0 && } - {!isPlaying && ( + {!selectedUser && ( <> - {toggleThreeD && } - - + + {loadingProgress > 0 && } + {!isPlaying && ( + <> + {toggleThreeD && } + + + + )} + + {activeModule === "market" && } + {activeModule !== "market" && } + {isPlaying && activeModule === "simulation" && } )} - {/* - - */} - {activeModule === "market" && } - - {activeModule !== "market" && } - {isPlaying && activeModule === "simulation" && } - {/* {} */} +
+ createHandleDrop({ + widgetSubOption, + visualizationSocket, + selectedZone, + setFloatingWidget, + event, + }) + } + onDragOver={(event) => event.preventDefault()} + > + +
{selectedUser && }
); diff --git a/app/src/store/visualization/useDroppedObjectsStore.ts b/app/src/store/visualization/useDroppedObjectsStore.ts index 5c4527b..bbe4cde 100644 --- a/app/src/store/visualization/useDroppedObjectsStore.ts +++ b/app/src/store/visualization/useDroppedObjectsStore.ts @@ -1,5 +1,4 @@ import { create } from "zustand"; -import { addingFloatingWidgets } from "../../services/visulization/zone/addFloatingWidgets"; import { useSocketStore } from "../store"; import useChartStore from "./useChartStore"; diff --git a/app/src/styles/base/global.scss b/app/src/styles/base/global.scss index d90e6fb..f86ba0f 100644 --- a/app/src/styles/base/global.scss +++ b/app/src/styles/base/global.scss @@ -1,11 +1,29 @@ @use "../abstracts/variables" as *; @use "../abstracts/mixins" as *; -section, .section{ - padding: 4px; - outline: 1px solid var(--border-color); - outline-offset: -1px; - border-radius: #{$border-radius-large}; - background: var(--background-color); - margin: 4px 0; +section, +.section { + padding: 4px; + outline: 1px solid var(--border-color); + outline-offset: -1px; + border-radius: #{$border-radius-large}; + background: var(--background-color); + margin: 4px 0; +} + +.scene-container { + width: calc(100% - (320px + 270px + 90px)); + height: calc(100% - (250px)); + position: absolute; + top: 50%; + left: calc(270px + 45px); + overflow: hidden; + z-index: 1; + transform: translate(0, -50%); + transition: all 0.2s; + box-shadow: $box-shadow-medium; + canvas { + outline: none; + border: none; + } } diff --git a/app/src/styles/base/reset.scss b/app/src/styles/base/reset.scss index ab77f9a..82d286e 100644 --- a/app/src/styles/base/reset.scss +++ b/app/src/styles/base/reset.scss @@ -12,10 +12,3 @@ input[type="password"]::-webkit-clear-button, /* For Chrome/Safari clear button input[type="password"]::-webkit-inner-spin-button { /* Just in case */ display: none; } - -button{ - border: none; - outline: none; - background: none; - cursor: pointer; -} \ No newline at end of file diff --git a/app/src/styles/components/analysis/ROISummary.scss b/app/src/styles/components/analysis/ROISummary.scss index 96b4a5d..5e2f78a 100644 --- a/app/src/styles/components/analysis/ROISummary.scss +++ b/app/src/styles/components/analysis/ROISummary.scss @@ -1,3 +1,6 @@ +@use "../../abstracts/variables" as *; +@use "../../abstracts/mixins" as *; + .roiSummary-container { .roiSummary-wrapper { background-color: var(--background-color); @@ -64,7 +67,7 @@ width: 100%; border-radius: 6px; border: 1px solid #00FF56; - background: #436D51; + background: #17eb5d65; display: flex; flex-direction: column; padding: 4px 6px; @@ -223,12 +226,11 @@ background: none; .btn { - background-color: var(--accent-color); - color: var(--background-color); - padding: 4px 6px; - border-radius: 5px; + color: var(--text-button-color); + background: var(--background-color-button); + padding: 4px 12px; + border-radius: #{$border-radius-large}; display: inline-block; - font-size: 14px; text-align: center; } } @@ -244,7 +246,6 @@ height: 250px; border-radius: 50%; position: relative; - transition: background 0.5s ease; } .progress-cover { position: absolute; @@ -252,7 +253,6 @@ height: 75%; top: 12.5%; left: 12.5%; - background: #000000cc; border-radius: 50%; } } diff --git a/app/src/styles/components/analysis/analysis.scss b/app/src/styles/components/analysis/analysis.scss index 030a79f..00a9c32 100644 --- a/app/src/styles/components/analysis/analysis.scss +++ b/app/src/styles/components/analysis/analysis.scss @@ -1,279 +1,269 @@ .analysis { - position: fixed; - top: 0; - left: 0; + position: fixed; + top: 0; + left: 0; + display: flex; + justify-content: space-between; + align-items: start; + width: 100%; + height: 100vh; + pointer-events: none; + padding: 10px; + z-index: 2; + + .analysis-wrapper { display: flex; - justify-content: space-between; - align-items: start; - width: 100%; - height: 100vh; - // pointer-events: none; - z-index: 10000; - - .analysis-wrapper { - display: flex; - flex-direction: column; - gap: 12px; - } -} - -.analysis-card { + flex-direction: column; + gap: 12px; + } + .analysis-card { min-width: 333px; background: var(--background-color); border-radius: 20px; - padding: 8px; + backdrop-filter: blur(10px); + outline: 1px solid var(--border-color); + outline-offset: -1px; + pointer-events: all; .analysis-card-wrapper { - width: 100%; - background: var(--background-color); - border-radius: 14px; - padding: 16px; + width: 100%; + background: var(--background-color); + border-radius: 14px; + padding: 16px; + display: flex; + flex-direction: column; + gap: 14px; + .card-header { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + + .main-header { + line-height: 20px; + font-size: var(--font-size-regular); + } + } + + .process-container { display: flex; flex-direction: column; - gap: 14px; - .card-header { + .throughput-value { + font-size: 1rem; + + .value { + font-weight: bold; + font-size: 1.5rem; + } + } + + .progress-bar-wrapper { + display: flex; + gap: 8px; + margin-top: 6px; + } + + .progress-bar { + position: relative; + width: 100%; + height: 4px; + border-radius: 13px; + overflow: hidden; + background: #fbebd7; + + .bar-fill { + position: absolute; + height: 100%; + top: 0; + left: 0; + background: #fc9d2f; + border-radius: 13px; + } + + .bar-fill.full { width: 100%; - display: flex; - justify-content: space-between; - align-items: center; + } - .main-header { - line-height: 20px; - font-size: var(--font-size-regular); - } + .bar-fill.partial { + width: 0; // inline style will override this + } } + } - .process-container { - display: flex; - flex-direction: column; + .metrics-section { + padding-top: 16px; + border-top: 1px solid var(--background-color-gray); - .throughput-value { - font-size: 1rem; + .metric { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; + margin-bottom: 8px; - .value { - font-weight: bold; - font-size: 1.5rem; - } - } + .label { + color: var(--text-color); + } - .progress-bar-wrapper { - display: flex; - gap: 8px; - margin-top: 6px; - } - - .progress-bar { - position: relative; - // width: 36px; - width: 100%; - height: 4px; - border-radius: 13px; - overflow: hidden; - background: #FBEBD7; - - .bar-fill { - position: absolute; - height: 100%; - top: 0; - left: 0; - background: #FC9D2F; - border-radius: 13px; - } - - .bar-fill.full { - width: 100%; - } - - .bar-fill.partial { - width: 0; // inline style will override this - } - } - } - - .metrics-section { - padding-top: 16px; - border-top: 1px solid var(--background-color-gray); - - .metric { - display: flex; - justify-content: space-between; - align-items: center; - font-size: 14px; - margin-bottom: 8px; - - .label { - color: var(--text-color); - } - - .value { - font-weight: bold; - } - } + .value { + font-weight: bold; + } } + } } -} - - -.throughoutSummary { .throughoutSummary-wrapper { - .process-container { + .process-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + gap: 16px; + width: 100%; + + .throughput-value { + font-size: var(--font-size-small); + flex: 1; + display: flex; + flex-direction: column; + + .value { + color: var(--accent-color); + } + + /* Let the text take available space */ + } + + .lineChart { + max-width: 200px; + height: 100px; + position: relative; + + .assetUsage { + text-align: right; + position: absolute; + right: 0; + top: 0; + } + + canvas { + background: transparent; + } + } + } + + .footer { + display: flex; + gap: 16px; // Space between cards + margin-top: 24px; + + .footer-card { + width: 100%; + background: var(--background-color-gray); + border-radius: 6px; + padding: 8px; + display: flex; + flex-direction: column; + gap: 6px; + + &:first-child { + width: 85%; + } + + .header { + font-size: var(--font-size-regular); + } + + .value-container { display: flex; flex-direction: row; align-items: center; + justify-content: end; + gap: 6px; + } + } + + .shiftUtilization { + .value-container { + flex-direction: column; + align-items: flex-start; justify-content: flex-start; - gap: 16px; - width: 100%; - .throughput-value { - font-size: var(--font-size-small); - flex: 1; - display: flex; - flex-direction: column; - - .value { - color: var(--accent-color); - } - - /* Let the text take available space */ + .value { + font-size: var(--font-size-xlarge); } - .lineChart { - max-width: 200px; - height: 100px; - position: relative; + .progress-wrapper { + width: 100%; + display: flex; + gap: 6px; - .assetUsage { - text-align: right; - position: absolute; - right: 0; - top: 0; - } - - canvas { - background: transparent; - } - } - } - - .footer { - display: flex; - gap: 16px; // Space between cards - margin-top: 24px; - - .footer-card { - width: 100%; - background: var(--background-color-gray); + .progress { border-radius: 6px; - padding: 8px; + height: 5px; + + &:nth-child(1) { + background: #f3c64d; + } + + &:nth-child(2) { + background: #67b3f4; + } + + &:nth-child(3) { + background: #7981f5; + } + } + } + + .progress-indicator { + display: flex; + justify-content: space-between; + width: 100%; + gap: 6px; + + .shift-wrapper { display: flex; - flex-direction: column; - gap: 6px; + align-items: center; + gap: 5px; - &:first-child { - width: 85%; + /* Align items vertically */ + &:nth-child(1) { + .indicator { + background: #f3c64d; + } } - .header { - font-size: var(--font-size-regular); + &:nth-child(2) { + .indicator { + background: #67b3f4; + } } - .value-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: end; - gap: 6px; + &:nth-child(3) { + .indicator { + background: #7981f5; + } } + + label { + font-size: var(--font-size-small); + position: relative; + } + + .indicator { + display: inline-block; + width: 5px; + height: 5px; + border-radius: 50%; + } + } } - - .shiftUtilization { - .value-container { - flex-direction: column; - align-items: flex-start; - justify-content: flex-start; - - .value { - font-size: var(--font-size-xlarge); - } - - .progress-wrapper { - width: 100%; - display: flex; - gap: 6px; - - .progress { - border-radius: 6px; - height: 5px; - - &:nth-child(1) { - background: #F3C64D; - } - - &:nth-child(2) { - background: #67B3F4; - } - - &:nth-child(3) { - background: #7981F5; - } - } - } - - .progress-indicator { - display: flex; - justify-content: space-between; - width: 100%; - gap: 6px; - - .shift-wrapper { - display: flex; - align-items: center; - gap: 5px; - - /* Align items vertically */ - &:nth-child(1) { - .indicator { - - background: #F3C64D; - } - } - - &:nth-child(2) { - .indicator { - - background: #67B3F4; - } - } - - &:nth-child(3) { - .indicator { - - background: #7981F5; - } - } - - label { - font-size: var(--font-size-small); - position: relative; - } - - .indicator { - display: inline-block; - width: 5px; - height: 5px; - border-radius: 50%; - - } - } - } - } - } - + } } - - + } } -} \ No newline at end of file + } +} diff --git a/app/src/styles/components/button.scss b/app/src/styles/components/button.scss index e69de29..dad9120 100644 --- a/app/src/styles/components/button.scss +++ b/app/src/styles/components/button.scss @@ -0,0 +1,24 @@ +@use "../abstracts/variables" as *; +@use "../abstracts/mixins" as *; + +.labeled-button-container { + @include flex-space-between; + padding: 6px 12px; + + button { + padding: 2px 32px; + border: none; + border-radius: #{$border-radius-large}; + color: var(--text-button-color); + background: var(--background-color-button); + transition: all 0.2s; + cursor: pointer; + } +} + +button { + border: none; + outline: none; + background: none; + cursor: pointer; +} diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index e3b9585..d4c6544 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -639,21 +639,6 @@ input[type="number"] { } } -.labeled-button-container { - @include flex-space-between; - padding: 6px 12px; - - button { - padding: 2px 32px; - border: none; - border-radius: #{$border-radius-large}; - color: var(--text-button-color); - background: var(--background-color-button); - transition: all 0.2s; - cursor: pointer; - } -} - .value-field-container { margin-bottom: 6px; padding: 6px 12px; diff --git a/app/src/styles/components/tools.scss b/app/src/styles/components/tools.scss index 0a23871..29d37b4 100644 --- a/app/src/styles/components/tools.scss +++ b/app/src/styles/components/tools.scss @@ -15,7 +15,7 @@ transition: width 0.2s; background: var(--background-color); backdrop-filter: blur(8px); - z-index: #{$z-index-default}; + z-index: 2; outline: 1px solid var(--border-color); outline-offset: -1px; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index fa1b86c..319a75c 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -3,8 +3,6 @@ // Main Container .realTime-viz { - background: #131313; - box-shadow: $box-shadow-medium; width: calc(100% - (320px + 270px + 90px)); height: calc(100% - (250px)); position: absolute; @@ -12,8 +10,8 @@ left: calc(270px + 45px); transform: translate(0, -50%); border-radius: #{$border-radius-medium}; - transition: all 0.2s; - z-index: #{$z-index-default}; + z-index: 2; + pointer-events: none; .realTime-viz-wrapper { width: 100%; @@ -39,10 +37,6 @@ z-index: 1; } - .scene-container { - overflow: hidden; - } - .icon { display: flex; align-items: center; @@ -74,6 +68,8 @@ z-index: 3; transform: translate(-50%, -10%); transition: transform 0.5s linear; + pointer-events: all; + &::-webkit-scrollbar { display: none; } @@ -367,6 +363,7 @@ border-radius: 2px; transition: transform 0.3s ease; box-shadow: #{$box-shadow-medium}; + pointer-events: all; svg { stroke: var(--icon-default-color) !important; @@ -428,8 +425,6 @@ stroke: #f65648; stroke-width: 1.3; } - - } } @@ -778,17 +773,10 @@ } } - - - .panel-content { background: var(--background-color); - } - - - /* RIGHT */ .panel-content.right-opening { animation: rightExpand 0.5s ease-in-out forwards; @@ -913,9 +901,6 @@ } } - - - // Add button .extra-Bs-addopening { @@ -926,7 +911,6 @@ animation: slideUp 0.3s ease forwards; } - @keyframes slideDown { from { opacity: 0; From 52c6ab8a658006b796b73aa1ffaa7d4953360059 Mon Sep 17 00:00:00 2001 From: Nalvazhuthi Date: Fri, 2 May 2025 18:06:29 +0530 Subject: [PATCH 4/9] added echo logs list --- app/src/pages/Project.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index b4422cd..83e4497 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -34,7 +34,7 @@ import LogList from "../components/ui/log/LogList"; const Project: React.FC = () => { let navigate = useNavigate(); - const logger = useLogger(); + const echo = useLogger(); const { activeModule, setActiveModule } = useModuleStore(); const { loadingProgress } = useLoadingProgress(); @@ -58,7 +58,7 @@ const Project: React.FC = () => { setOrganization(Organization); setUserName(name); } - logger.info("Log in success full"); + echo.info("Log in success full"); } else { navigate("/"); } From 6a1bf7f769cc22a1c38873699d36ca9b6c7339a5 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Fri, 2 May 2025 18:16:22 +0530 Subject: [PATCH 5/9] refactor: Update ROISummary component to use ArrowIcon for expand functionality; enhance styles in ROISummary, global, and analysis components for improved layout and responsiveness --- app/src/components/ui/analysis/ROISummary.tsx | 3 +- app/src/styles/base/base.scss | 6 +- app/src/styles/base/global.scss | 1 + .../components/analysis/ROISummary.scss | 561 +++++++++--------- .../styles/components/analysis/analysis.scss | 7 +- 5 files changed, 277 insertions(+), 301 deletions(-) diff --git a/app/src/components/ui/analysis/ROISummary.tsx b/app/src/components/ui/analysis/ROISummary.tsx index 11101fd..63ae707 100644 --- a/app/src/components/ui/analysis/ROISummary.tsx +++ b/app/src/components/ui/analysis/ROISummary.tsx @@ -1,6 +1,7 @@ import React, { useState } from "react"; import { ROISummaryIcon } from "../../icons/analysis"; import SemiCircleProgress from "./SemiCircleProgress"; +import { ArrowIcon } from "../../icons/ExportCommonIcons"; const ROISummary = ({ roiSummaryData = { @@ -121,7 +122,7 @@ const ROISummary = ({
- {isTableOpen ? "⌵" : "⌵"} +
Date: Fri, 2 May 2025 18:31:00 +0530 Subject: [PATCH 6/9] refactor: Clean up LogList component by removing unused TickIcon; enhance footer and logs styles for better layout and readability --- app/src/components/ui/log/LogList.tsx | 3 - app/src/styles/abstracts/variables.scss | 27 +++- app/src/styles/components/footer/footer.scss | 108 +++++++------- app/src/styles/components/logs/logs.scss | 143 +++++++++---------- 4 files changed, 155 insertions(+), 126 deletions(-) diff --git a/app/src/components/ui/log/LogList.tsx b/app/src/components/ui/log/LogList.tsx index 1b39e2f..fe25aee 100644 --- a/app/src/components/ui/log/LogList.tsx +++ b/app/src/components/ui/log/LogList.tsx @@ -69,9 +69,6 @@ const LogList: React.FC = () => {
{filteredLogs.map((log) => (
-
- -
{getLogIcon(log.type)}
[{formatTimestamp(log.timestamp)}] [{log.type.toUpperCase()}]{" "} diff --git a/app/src/styles/abstracts/variables.scss b/app/src/styles/abstracts/variables.scss index f4a6495..29976dc 100644 --- a/app/src/styles/abstracts/variables.scss +++ b/app/src/styles/abstracts/variables.scss @@ -22,7 +22,11 @@ $text-button-color-dark: #f3f3fd; // background colors // ---------- light mode ---------- $background-color: linear-gradient(-45deg, #fcfdfd71 0%, #fcfdfd79 100%); -$background-color-solid-gradient: linear-gradient(-45deg, #fcfdfd 0%, #fcfdfd 100%); +$background-color-solid-gradient: linear-gradient( + -45deg, + #fcfdfd 0%, + #fcfdfd 100% +); $background-color-solid: #fcfdfd; $background-color-secondary: #fcfdfd4d; $background-color-accent: #6f42c1; @@ -45,7 +49,11 @@ $background-radial-gray-gradient: radial-gradient( // ---------- dark mode ---------- $background-color-dark: linear-gradient(-45deg, #333333b3 0%, #2d2437b3 100%); -$background-color-solid-gradient-dark: linear-gradient(-45deg, #333333 0%, #2d2437 100%); +$background-color-solid-gradient-dark: linear-gradient( + -45deg, + #333333 0%, + #2d2437 100% +); $background-color-solid-dark: #19191d; $background-color-secondary-dark: #19191d99; $background-color-accent-dark: #6f42c1; @@ -104,6 +112,21 @@ $color3: #b186ff; $color4: #8752e8; $color5: #c7a8ff; +// log indication colors +// ------------ text ------------- +$log-default-text-color: #6f42c1; +$log-info-text-color: #488ef6; +$log-warn-text-color: #f3a50c; +$log-error-text-color: #f65648; +$log-success-text-color: #43c06d; + +// ------------ background ------------- +$log-default-backgroung-color: #6e42c133; +$log-info-background-color: #488ef633; +$log-warn-background-color: #f3a50c33; +$log-error-background-color: #f6564833; +$log-success-background-color: #43c06d33; + // old variables $accent-color: #6f42c1; $accent-color-dark: #c4abf1; diff --git a/app/src/styles/components/footer/footer.scss b/app/src/styles/components/footer/footer.scss index 0fed13b..d3a3d92 100644 --- a/app/src/styles/components/footer/footer.scss +++ b/app/src/styles/components/footer/footer.scss @@ -1,57 +1,67 @@ +@use "../../abstracts/variables" as *; +@use "../../abstracts/mixins" as *; + .footer-wrapper { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - z-index: 1; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + z-index: 1; + display: flex; + justify-content: space-between; + padding: 2px 12px; + + .selection-wrapper { display: flex; - justify-content: space-between; - padding: 12px 24px; + gap: 6px; - .selection-wrapper { - display: flex; - gap: 6px; + .selector-wrapper { + display: flex; + gap: 6px; + align-items: center; + background: var(--background-color); + padding: 3px 6px; + border-radius: 12px; + color: var(--text-color); - .selector-wrapper { - display: flex; - gap: 6px; - align-items: center; - background: var(--background-color); - padding: 3px 6px; - border-radius: 12px; - color: var(--text-color); + .selector { + color: var(--text-color); + } + } + } - .selector { - color: var(--text-color); - } - } + .logs-wrapper { + display: flex; + gap: 6px; + + .logs-detail, + .version { + border-radius: 12px; + background: var(--background-color); + padding: 3px 6px; + color: var(--text-color); + display: flex; + align-items: center; + gap: 6px; } - .logs-wrapper { - display: flex; - gap: 6px; - - .logs-detail, - .version { - - border-radius: 12px; - background: var(--background-color); - padding: 3px 6px; - color: var(--text-color); - display: flex; - align-items: center; - gap: 6px; - } - - .logs-detail { - // background-color: #fff; - cursor: pointer; - } - - .version { - display: flex; - gap: 6px; - - } + .logs-detail { + padding: 2px 12px; + cursor: pointer; + .log-icon { + @include flex-center; + } + .log-message { + max-width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } } -} \ No newline at end of file + + .version { + display: flex; + gap: 6px; + } + } +} diff --git a/app/src/styles/components/logs/logs.scss b/app/src/styles/components/logs/logs.scss index ba0f43d..d2535aa 100644 --- a/app/src/styles/components/logs/logs.scss +++ b/app/src/styles/components/logs/logs.scss @@ -1,77 +1,76 @@ .log-list-container { - width: 100vw; - height: 100vh; - // background: var(--background-color-secondary); - // backdrop-filter: blur(2px); + width: 100vw; + height: 100vh; + // background: var(--background-color-secondary); + // backdrop-filter: blur(2px); - .log-list-wrapper { - height: 50%; - min-width: 50%; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - z-index: 5; - background: var(--background-color); - padding: 14px 12px; - border-radius: 15px; + .log-list-wrapper { + height: 50%; + min-width: 50%; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 5; + background: var(--background-color); + padding: 14px 12px; + border-radius: 15px; + display: flex; + flex-direction: column; + gap: 12px; + backdrop-filter: blur(50px); + + .log-header { + display: flex; + justify-content: space-between; + + .log-header-wrapper { display: flex; - flex-direction: column; - gap: 12px; - backdrop-filter: blur(50px); + align-items: center; + gap: 6px; + } - .log-header { - display: flex; - justify-content: space-between; - - .log-header-wrapper { - display: flex; - align-items: center; - gap: 6px; - } - - .close { - // transform: scale(1.5); - cursor: pointer; - } - } - - .log-nav-wrapper { - display: flex; - gap: 6px; - - .log-nav { - padding: 8px 16px; - border-radius: 19px; - } - - .log-nav.active { - background-color: var(--accent-color); - color: var(--text-button-color); - } - } - - .log-entry-wrapper { - height: 100%; - display: flex; - flex-direction: column; - gap: 4px; - background: var(--background-color); - padding: 18px 10px; - border-radius: 16px; - - .log-entry { - padding: 4px; - border-radius: 4px; - font-size: var(--font-size-small); - display: flex; - align-items: center; - gap: 6px; - - &:nth-child(odd) { - background: var(--background-color); - } - } - } + .close { + cursor: pointer; + } } -} \ No newline at end of file + + .log-nav-wrapper { + display: flex; + gap: 6px; + + .log-nav { + padding: 8px 16px; + border-radius: 19px; + } + + .log-nav.active { + background-color: var(--background-color-accent); + color: var(--text-button-color); + } + } + + .log-entry-wrapper { + height: 100%; + display: flex; + flex-direction: column; + gap: 4px; + background: var(--background-color); + padding: 18px 10px; + border-radius: 16px; + + .log-entry { + padding: 4px; + border-radius: 4px; + font-size: var(--font-size-small); + display: flex; + align-items: center; + gap: 6px; + + &:nth-child(odd) { + background: var(--background-color); + } + } + } + } +} From 70b48b39cfa59d1efb1def4dbcd3c83b0e1c447e Mon Sep 17 00:00:00 2001 From: Vishnu Date: Fri, 2 May 2025 19:09:05 +0530 Subject: [PATCH 7/9] refactor: Enhance LogList component layout and styles; improve footer and logs styles for better readability and responsiveness --- app/src/components/ui/log/LogList.tsx | 28 +++++++++++------ app/src/styles/components/footer/footer.scss | 4 +++ app/src/styles/components/logs/logs.scss | 33 ++++++++++++++++++-- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/app/src/components/ui/log/LogList.tsx b/app/src/components/ui/log/LogList.tsx index fe25aee..fad277c 100644 --- a/app/src/components/ui/log/LogList.tsx +++ b/app/src/components/ui/log/LogList.tsx @@ -2,7 +2,6 @@ import React, { useState } from "react"; import { LogListIcon, - TickIcon, LogInfoIcon, WarningIcon, ErrorIcon, @@ -38,8 +37,17 @@ const LogList: React.FC = () => { : [...logs].filter((log) => log.type === selectedTab).reverse(); return ( -
-
+ // eslint-disable-next-line +
setIsLogListVisible(false)} + > +
{ + e.stopPropagation(); + }} + >
@@ -47,9 +55,9 @@ const LogList: React.FC = () => {
Log List
-
setIsLogListVisible(false)}> - {/* */}X -
+
{/* Tabs */} @@ -70,9 +78,11 @@ const LogList: React.FC = () => { {filteredLogs.map((log) => (
{getLogIcon(log.type)}
-
- [{formatTimestamp(log.timestamp)}] [{log.type.toUpperCase()}]{" "} - {log.message} +
+
{log.message}
+
+ {formatTimestamp(log.timestamp)} +
))} diff --git a/app/src/styles/components/footer/footer.scss b/app/src/styles/components/footer/footer.scss index d3a3d92..b2d85d0 100644 --- a/app/src/styles/components/footer/footer.scss +++ b/app/src/styles/components/footer/footer.scss @@ -60,8 +60,12 @@ } .version { + font-size: var(--font-size-tiny); display: flex; gap: 6px; + .icon{ + @include flex-center; + } } } } diff --git a/app/src/styles/components/logs/logs.scss b/app/src/styles/components/logs/logs.scss index d2535aa..f07708b 100644 --- a/app/src/styles/components/logs/logs.scss +++ b/app/src/styles/components/logs/logs.scss @@ -1,8 +1,10 @@ +@use "../../abstracts/variables" as *; +@use "../../abstracts/mixins" as *; + .log-list-container { width: 100vw; height: 100vh; - // background: var(--background-color-secondary); - // backdrop-filter: blur(2px); + background: var(--background-color-secondary); .log-list-wrapper { height: 50%; @@ -19,6 +21,7 @@ flex-direction: column; gap: 12px; backdrop-filter: blur(50px); + outline: 1px solid var(--border-color); .log-header { display: flex; @@ -31,7 +34,13 @@ } .close { + @include flex-center; + height: 28px; + width: 28px; cursor: pointer; + svg { + scale: 1.6; + } } } @@ -58,6 +67,8 @@ background: var(--background-color); padding: 18px 10px; border-radius: 16px; + outline: 1px solid var(--border-color); + outline-offset: -1px; .log-entry { padding: 4px; @@ -67,6 +78,24 @@ align-items: center; gap: 6px; + .log-icon { + @include flex-center; + } + .log-entry-message-container { + @include flex-space-between; + gap: 12px; + width: 100%; + .message-time { + font-size: var(--font-size-tiny); + font-weight: 300; + opacity: 0.8; + text-wrap: nowrap; + } + .log-entry-message{ + width: 100%; + } + } + &:nth-child(odd) { background: var(--background-color); } From ac49f62bb03c373030c0b245ddf712603be7e22f Mon Sep 17 00:00:00 2001 From: Vishnu Date: Sat, 3 May 2025 09:45:29 +0530 Subject: [PATCH 8/9] refactor: Remove unused analysis and ROISummary styles; consolidate simulation styles for improved organization --- .../styles/components/analysis/analysis.scss | 268 ----------------- .../analysis.scss} | 273 +++++++++++++++++- app/src/styles/main.scss | 5 +- 3 files changed, 272 insertions(+), 274 deletions(-) delete mode 100644 app/src/styles/components/analysis/analysis.scss rename app/src/styles/components/{analysis/ROISummary.scss => simulation/analysis.scss} (50%) diff --git a/app/src/styles/components/analysis/analysis.scss b/app/src/styles/components/analysis/analysis.scss deleted file mode 100644 index 3185ed6..0000000 --- a/app/src/styles/components/analysis/analysis.scss +++ /dev/null @@ -1,268 +0,0 @@ -.analysis { - position: fixed; - top: 0; - left: 0; - display: flex; - justify-content: space-between; - align-items: start; - width: 100%; - height: 100vh; - pointer-events: none; - padding: 10px; - z-index: 2; - - .analysis-wrapper { - display: flex; - flex-direction: column; - gap: 12px; - } - .analysis-card { - min-width: 333px; - border-radius: 20px; - padding: 8px; - pointer-events: all; - - .analysis-card-wrapper { - width: 100%; - background: var(--background-color); - border-radius: 14px; - padding: 16px; - display: flex; - flex-direction: column; - gap: 14px; - backdrop-filter: blur(10px); - outline: 1px solid var(--border-color); - outline-offset: -1px; - - .card-header { - width: 100%; - display: flex; - justify-content: space-between; - align-items: center; - - .main-header { - line-height: 20px; - font-size: var(--font-size-regular); - } - } - - .process-container { - display: flex; - flex-direction: column; - - .throughput-value { - font-size: 1rem; - - .value { - font-weight: bold; - font-size: 1.5rem; - } - } - - .progress-bar-wrapper { - display: flex; - gap: 8px; - margin-top: 6px; - } - - .progress-bar { - position: relative; - width: 100%; - height: 4px; - border-radius: 13px; - overflow: hidden; - background: #fbebd7; - - .bar-fill { - position: absolute; - height: 100%; - top: 0; - left: 0; - background: #fc9d2f; - border-radius: 13px; - } - - .bar-fill.full { - width: 100%; - } - - .bar-fill.partial { - width: 0; // inline style will override this - } - } - } - - .metrics-section { - padding-top: 16px; - border-top: 1px solid var(--background-color-gray); - - .metric { - display: flex; - justify-content: space-between; - align-items: center; - font-size: 14px; - margin-bottom: 8px; - - .label { - color: var(--text-color); - } - - .value { - font-weight: bold; - } - } - } - } - .throughoutSummary-wrapper { - .process-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: flex-start; - gap: 16px; - width: 100%; - - .throughput-value { - font-size: var(--font-size-small); - flex: 1; - display: flex; - flex-direction: column; - - .value { - color: var(--accent-color); - } - - /* Let the text take available space */ - } - - .lineChart { - max-width: 200px; - height: 100px; - position: relative; - - .assetUsage { - text-align: right; - position: absolute; - right: 0; - top: 0; - } - - canvas { - background: transparent; - } - } - } - - .footer { - display: flex; - gap: 16px; // Space between cards - margin-top: 24px; - - .footer-card { - width: 100%; - background: var(--background-color-gray); - border-radius: 6px; - padding: 8px; - display: flex; - flex-direction: column; - gap: 6px; - - &:first-child { - width: 85%; - } - - .header { - font-size: var(--font-size-regular); - } - - .value-container { - display: flex; - flex-direction: row; - align-items: center; - justify-content: end; - gap: 6px; - } - } - - .shiftUtilization { - .value-container { - flex-direction: column; - align-items: flex-start; - justify-content: flex-start; - - .value { - font-size: var(--font-size-xlarge); - } - - .progress-wrapper { - width: 100%; - display: flex; - gap: 6px; - - .progress { - border-radius: 6px; - height: 5px; - - &:nth-child(1) { - background: #f3c64d; - } - - &:nth-child(2) { - background: #67b3f4; - } - - &:nth-child(3) { - background: #7981f5; - } - } - } - - .progress-indicator { - display: flex; - justify-content: space-between; - width: 100%; - gap: 6px; - - .shift-wrapper { - display: flex; - align-items: center; - gap: 5px; - - /* Align items vertically */ - &:nth-child(1) { - .indicator { - background: #f3c64d; - } - } - - &:nth-child(2) { - .indicator { - background: #67b3f4; - } - } - - &:nth-child(3) { - .indicator { - background: #7981f5; - } - } - - label { - font-size: var(--font-size-small); - position: relative; - } - - .indicator { - display: inline-block; - width: 5px; - height: 5px; - border-radius: 50%; - } - } - } - } - } - } - } - } -} diff --git a/app/src/styles/components/analysis/ROISummary.scss b/app/src/styles/components/simulation/analysis.scss similarity index 50% rename from app/src/styles/components/analysis/ROISummary.scss rename to app/src/styles/components/simulation/analysis.scss index 1f6f824..9aed5c8 100644 --- a/app/src/styles/components/analysis/ROISummary.scss +++ b/app/src/styles/components/simulation/analysis.scss @@ -1,7 +1,273 @@ @use "../../abstracts/variables" as *; @use "../../abstracts/mixins" as *; -.roiSummary-container { +.analysis { + position: fixed; + top: 0; + left: 0; + display: flex; + justify-content: space-between; + align-items: start; + width: 100%; + height: 100vh; + pointer-events: none; + padding: 10px; + z-index: 2; + + .analysis-wrapper { + display: flex; + flex-direction: column; + gap: 12px; + } + .analysis-card { + min-width: 333px; + border-radius: 20px; + padding: 8px; + pointer-events: all; + + .analysis-card-wrapper { + width: 100%; + background: var(--background-color); + border-radius: 14px; + padding: 16px; + display: flex; + flex-direction: column; + gap: 14px; + backdrop-filter: blur(10px); + outline: 1px solid var(--border-color); + outline-offset: -1px; + + .card-header { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + + .main-header { + line-height: 20px; + font-size: var(--font-size-regular); + } + } + + .process-container { + display: flex; + flex-direction: column; + + .throughput-value { + font-size: 1rem; + + .value { + font-weight: bold; + font-size: 1.5rem; + } + } + + .progress-bar-wrapper { + display: flex; + gap: 8px; + margin-top: 6px; + } + + .progress-bar { + position: relative; + width: 100%; + height: 4px; + border-radius: 13px; + overflow: hidden; + background: #fbebd7; + + .bar-fill { + position: absolute; + height: 100%; + top: 0; + left: 0; + background: #fc9d2f; + border-radius: 13px; + } + + .bar-fill.full { + width: 100%; + } + + .bar-fill.partial { + width: 0; // inline style will override this + } + } + } + + .metrics-section { + padding-top: 16px; + border-top: 1px solid var(--background-color-gray); + + .metric { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 14px; + margin-bottom: 8px; + + .label { + color: var(--text-color); + } + + .value { + font-weight: bold; + } + } + } + } + .throughoutSummary-wrapper { + .process-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + gap: 16px; + width: 100%; + + .throughput-value { + font-size: var(--font-size-small); + flex: 1; + display: flex; + flex-direction: column; + + .value { + color: var(--accent-color); + } + + /* Let the text take available space */ + } + + .lineChart { + max-width: 200px; + height: 100px; + position: relative; + + .assetUsage { + text-align: right; + position: absolute; + right: 0; + top: 0; + } + + canvas { + background: transparent; + } + } + } + + .footer { + display: flex; + gap: 16px; // Space between cards + margin-top: 24px; + + .footer-card { + width: 100%; + background: var(--background-color-gray); + border-radius: 6px; + padding: 8px; + display: flex; + flex-direction: column; + gap: 6px; + + &:first-child { + width: 85%; + } + + .header { + font-size: var(--font-size-regular); + } + + .value-container { + display: flex; + flex-direction: row; + align-items: center; + justify-content: end; + gap: 6px; + } + } + + .shiftUtilization { + .value-container { + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + + .value { + font-size: var(--font-size-xlarge); + } + + .progress-wrapper { + width: 100%; + display: flex; + gap: 6px; + + .progress { + border-radius: 6px; + height: 5px; + + &:nth-child(1) { + background: #f3c64d; + } + + &:nth-child(2) { + background: #67b3f4; + } + + &:nth-child(3) { + background: #7981f5; + } + } + } + + .progress-indicator { + display: flex; + justify-content: space-between; + width: 100%; + gap: 6px; + + .shift-wrapper { + display: flex; + align-items: center; + gap: 5px; + + /* Align items vertically */ + &:nth-child(1) { + .indicator { + background: #f3c64d; + } + } + + &:nth-child(2) { + .indicator { + background: #67b3f4; + } + } + + &:nth-child(3) { + .indicator { + background: #7981f5; + } + } + + label { + font-size: var(--font-size-small); + position: relative; + } + + .indicator { + display: inline-block; + width: 5px; + height: 5px; + border-radius: 50%; + } + } + } + } + } + } + } + } .roiSummary-wrapper { max-width: 470px; background-color: var(--background-color); @@ -264,8 +530,6 @@ } } -// Breakdown Table Open/Close Logic - .breakdown-table-wrapper { &.closed { max-height: 0; @@ -288,3 +552,6 @@ } } } + +// Breakdown Table Open/Close Logic + diff --git a/app/src/styles/main.scss b/app/src/styles/main.scss index 9fe7222..6bea32f 100644 --- a/app/src/styles/main.scss +++ b/app/src/styles/main.scss @@ -22,11 +22,10 @@ @use 'components/visualization/ui/styledWidgets'; @use 'components/visualization/floating/common'; @use 'components/marketPlace/marketPlace'; -@use 'components/simulation/simulation'; @use 'components/menu/menu'; @use 'components/confirmationPopUp'; -@use 'components/analysis/analysis'; -@use 'components/analysis/ROISummary.scss'; +@use 'components/simulation/simulation'; +@use 'components/simulation/analysis'; @use 'components/logs/logs'; @use 'components/footer/footer.scss'; From 39c0017a5bc16f1e593dc875e6e1f7a3280b4847 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Sat, 3 May 2025 10:02:40 +0530 Subject: [PATCH 9/9] refactor: Reintroduce Footer component with updated log handling; remove unused layouts styles --- app/src/components/{ui => }/footer/Footer.tsx | 8 ++++---- app/src/pages/Project.tsx | 2 +- app/src/styles/components/layouts.scss | 0 app/src/styles/main.scss | 1 - 4 files changed, 5 insertions(+), 6 deletions(-) rename app/src/components/{ui => }/footer/Footer.tsx (88%) delete mode 100644 app/src/styles/components/layouts.scss diff --git a/app/src/components/ui/footer/Footer.tsx b/app/src/components/footer/Footer.tsx similarity index 88% rename from app/src/components/ui/footer/Footer.tsx rename to app/src/components/footer/Footer.tsx index 9f73284..19fc6c5 100644 --- a/app/src/components/ui/footer/Footer.tsx +++ b/app/src/components/footer/Footer.tsx @@ -1,11 +1,11 @@ import React from "react"; -import { HelpIcon } from "../../icons/DashboardIcon"; -import { useLogger } from "../log/LoggerContext"; +import { HelpIcon } from "../icons/DashboardIcon"; import { LogInfoIcon, ErrorIcon, WarningIcon, -} from "../../icons/ExportCommonIcons"; // Adjust path as needed +} from "../icons/ExportCommonIcons"; // Adjust path as needed +import { useLogger } from "../ui/log/LoggerContext"; const getLogIcon = (type: string) => { switch (type) { @@ -21,7 +21,7 @@ const getLogIcon = (type: string) => { } }; -const Footer = () => { +const Footer: React.FC = () => { const { logs, setIsLogListVisible } = useLogger(); const lastLog = logs.length > 0 ? logs[logs.length - 1] : null; diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 83e4497..17a6315 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -28,9 +28,9 @@ import { createHandleDrop } from "../modules/visualization/functions/handleUiDro import { useSelectedZoneStore } from "../store/visualization/useZoneStore"; import { useFloatingWidget } from "../store/visualization/useDroppedObjectsStore"; import { useLogger } from "../components/ui/log/LoggerContext"; -import Footer from "../components/ui/footer/Footer"; import RenderOverlay from "../components/templates/Overlay"; import LogList from "../components/ui/log/LogList"; +import Footer from "../components/footer/Footer"; const Project: React.FC = () => { let navigate = useNavigate(); diff --git a/app/src/styles/components/layouts.scss b/app/src/styles/components/layouts.scss deleted file mode 100644 index e69de29..0000000 diff --git a/app/src/styles/main.scss b/app/src/styles/main.scss index 6bea32f..3adfc0f 100644 --- a/app/src/styles/main.scss +++ b/app/src/styles/main.scss @@ -13,7 +13,6 @@ @use 'components/button'; @use 'components/form'; @use 'components/input'; -@use 'components/layouts'; @use 'components/lists'; @use 'components/moduleToggle'; @use 'components/templates';