-
- {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" && (
- <>
-
- >
- )}
- {activeModule === "simulation" && (
- <>
-
- >
- )}
- {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" && (
+ <>
+
+
+ >
+ )}
+
) : (
<>
{activeModule !== "simulation" && (
-
setIsPlaying(false)}>
+
+
)}
>
)}
diff --git a/app/src/components/ui/footer/Footer.tsx b/app/src/components/ui/footer/Footer.tsx
index 93da68c..9f73284 100644
--- a/app/src/components/ui/footer/Footer.tsx
+++ b/app/src/components/ui/footer/Footer.tsx
@@ -1,10 +1,28 @@
import React from "react";
import { HelpIcon } from "../../icons/DashboardIcon";
import { useLogger } from "../log/LoggerContext";
+import {
+ LogInfoIcon,
+ ErrorIcon,
+ WarningIcon,
+} from "../../icons/ExportCommonIcons"; // Adjust path as needed
+
+const getLogIcon = (type: string) => {
+ switch (type) {
+ case "info":
+ return
;
+ case "error":
+ return
;
+ case "warning":
+ return
;
+ case "log":
+ default:
+ return
;
+ }
+};
const Footer = () => {
const { logs, setIsLogListVisible } = useLogger();
-
const lastLog = logs.length > 0 ? logs[logs.length - 1] : null;
return (
@@ -26,9 +44,14 @@ const Footer = () => {
setIsLogListVisible(true)}>
- {lastLog
- ? `[${lastLog.type.toUpperCase()}] ${lastLog.message}`
- : "No logs yet."}
+ {lastLog ? (
+ <>
+ {getLogIcon(lastLog.type)}
+ {lastLog.message}
+ >
+ ) : (
+ "No logs yet."
+ )}
V 0.01
diff --git a/app/src/components/ui/log/LogList.tsx b/app/src/components/ui/log/LogList.tsx
index 4a43933..1b39e2f 100644
--- a/app/src/components/ui/log/LogList.tsx
+++ b/app/src/components/ui/log/LogList.tsx
@@ -6,6 +6,7 @@ import {
LogInfoIcon,
WarningIcon,
ErrorIcon,
+ CloseIcon,
} from "../../icons/ExportCommonIcons"; // Adjust path as needed
import { useLogger } from "./LoggerContext";
@@ -47,7 +48,7 @@ const LogList: React.FC = () => {
Log List
setIsLogListVisible(false)}>
- X
+ {/* */}X
diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx
index 28f2fe5..e569250 100644
--- a/app/src/components/ui/simulation/simulationPlayer.tsx
+++ b/app/src/components/ui/simulation/simulationPlayer.tsx
@@ -12,25 +12,31 @@ import {
EndIcon,
ExpandIcon,
HourlySimulationIcon,
+ InfoIcon,
MonthlyROI,
SpeedIcon,
StartIcon,
} 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
+ 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 = () => {
@@ -113,6 +119,15 @@ const SimulationPlayer: React.FC = () => {
return color;
};
+ // Store colors for each process item
+ const [_, 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)
@@ -150,214 +165,236 @@ const SimulationPlayer: React.FC = () => {
};
return (
-
-
-
-
- {/* hourlySimulation */}
-
-
-
-
+ <>
+
+
+
+ {subModule === "analysis" && (
+
+ {/* hourlySimulation */}
+
+
+
+
+
+
Hourly Simulation
+
+
-
Hourly Simulation
-
-
-
- {/* dailyProduction */}
-
-
-
-
+ {/* dailyProduction */}
+
+
+
+
+
+
Daily Production
+
+
-
Daily Production
-
-
-
- {/* monthlyROI */}
-
-
-
-
+ {/* monthlyROI */}
+
-
Monthly ROI
-
{" "}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ )}
+ {subModule === "simulations" && (
+
+
+ {playSimulation
+ ? "Paused - system idle."
+ : "Running simulation..."}
-
-
23 April ,25
-
04:41 PM
-
-
-
-
- {intervals.map((label, index) => {
- const segmentProgress = (index / totalSegments) * 100;
- const isFilled = progress >= segmentProgress;
- return (
-
-
- {index < intervals.length - 1 && (
- = ((index + 1) / totalSegments) * 100
- ? "filled"
- : ""
- }`}
- >
- )}
-
- );
- })}
-
-
-
-
-
-
-
-
-
0.5X
-
-
-
-
-
-
-
-
-
-
+ )}
+
+
+
+
+ {subModule === "analysis" && (
-
-
-
4x
+ )}
-
-
-
00:00
-
24:00
-
-
-
- {process.map((item, index) => (
-
-
+
+
+
+
+
- ))}
+
+
23 April ,25
+
04:41 PM
+
+
+
+
+ {intervals.map((label, index) => {
+ const segmentProgress = (index / totalSegments) * 100;
+ const isFilled = progress >= segmentProgress;
+ return (
+
+
+ {index < intervals.length - 1 && (
+ = ((index + 1) / totalSegments) * 100
+ ? "filled"
+ : ""
+ }`}
+ >
+ )}
+
+ );
+ })}
+
+
+
+
+
+
+
+
+
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 caf37a1..dadaf9c 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",
@@ -145,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) => {
@@ -304,16 +302,7 @@ const RealTimeVisulization: React.FC = () => {
}
`}
-
+
{openConfirmationPopup && (
@@ -324,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 9a5343b..b4422cd 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,16 +23,19 @@ 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";
+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 { useLogger } from "../components/ui/log/LoggerContext";
const Project: React.FC = () => {
let navigate = useNavigate();
+ const logger = useLogger();
+
const { activeModule, setActiveModule } = useModuleStore();
const { loadingProgress } = useLoadingProgress();
const { setUserName } = useUserName();
@@ -54,48 +58,78 @@ const Project: React.FC = () => {
setOrganization(Organization);
setUserName(name);
}
+ logger.info("Log in success full");
} 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();
const { isLogListVisible } = useLogger();
+ // 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 &&
}
{isLogListVisible && (
)}
- {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/footer/footer.scss b/app/src/styles/components/footer/footer.scss
index 386b6a5..0fed13b 100644
--- a/app/src/styles/components/footer/footer.scss
+++ b/app/src/styles/components/footer/footer.scss
@@ -6,7 +6,7 @@
z-index: 1;
display: flex;
justify-content: space-between;
- padding: 6px;
+ padding: 12px 24px;
.selection-wrapper {
display: flex;
@@ -22,8 +22,7 @@
color: var(--text-color);
.selector {
- color: var(--text-button-color);
- font-weight: 200;
+ color: var(--text-color);
}
}
}
@@ -34,13 +33,14 @@
.logs-detail,
.version {
+
border-radius: 12px;
background: var(--background-color);
padding: 3px 6px;
- color: var(--text-button-color);
- font-weight: 200;
+ color: var(--text-color);
display: flex;
align-items: center;
+ gap: 6px;
}
.logs-detail {
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/logs/logs.scss b/app/src/styles/components/logs/logs.scss
index 99e7548..ba0f43d 100644
--- a/app/src/styles/components/logs/logs.scss
+++ b/app/src/styles/components/logs/logs.scss
@@ -1,8 +1,8 @@
.log-list-container {
width: 100vw;
height: 100vh;
- background: var(--background-color-secondary);
- backdrop-filter: blur(2px);
+ // background: var(--background-color-secondary);
+ // backdrop-filter: blur(2px);
.log-list-wrapper {
height: 50%;
@@ -18,6 +18,7 @@
display: flex;
flex-direction: column;
gap: 12px;
+ backdrop-filter: blur(50px);
.log-header {
display: flex;
@@ -30,6 +31,7 @@
}
.close {
+ // transform: scale(1.5);
cursor: pointer;
}
}
diff --git a/app/src/styles/components/simulation/simulation.scss b/app/src/styles/components/simulation/simulation.scss
index 66c2e24..88f85dc 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..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;
@@ -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 f4ccaa8..f8c022f 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%;
diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss
index d130af5..abc626a 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;
strokeWidth: 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;