From d3ea36d1bacf15f5930f6638dce4281b54426cf6 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 29 May 2025 12:00:16 +0530 Subject: [PATCH] feat: Refactor product selection and comparison functionality - Created a new store for selected products using Zustand and immer for state management. - Introduced `useMainProduct` and `useComparisonProduct` hooks to manage main and comparison products. - Implemented `ComparisonScene` and `ComparisonSceneProvider` components to handle product comparisons. - Updated `MainScene` to allow selection of main products with a dropdown. - Enhanced styles for comparison layout and product selection UI. - Established a context for product management to streamline state access across components. --- .../layout/scenes/ComparisonScene.tsx | 48 + .../layout/scenes/ComparisonSceneProvider.tsx | 12 + .../components/layout/scenes/MainScene.tsx | 113 ++ .../layout/scenes/MainSceneProvider.tsx | 12 + .../eventProperties/EventProperties.tsx | 5 +- .../components/ActionsList.tsx | 10 +- .../mechanics/conveyorMechanics.tsx | 6 +- .../mechanics/machineMechanics.tsx | 6 +- .../mechanics/roboticArmMechanics.tsx | 9 +- .../mechanics/storageMechanics.tsx | 6 +- .../mechanics/vehicleMechanics.tsx | 5 +- .../eventProperties/trigger/Trigger.tsx | 26 +- .../sidebarRight/simulation/Simulations.tsx | 9 +- .../ui/compareVersion/CompareLayOut.tsx | 40 +- app/src/modules/builder/asset/assetsGroup.tsx | 4 +- .../builder/asset/models/model/model.tsx | 10 +- .../selectionControls/moveControls.tsx | 5 +- .../selectionControls/rotateControls.tsx | 9 +- .../transformControls/transformControls.tsx | 5 +- app/src/modules/scene/scene.tsx | 8 +- app/src/modules/scene/sceneContext.tsx | 16 +- .../conveyor/actionHandler/useSpawnHandler.ts | 5 +- .../actionHandler/useProcessHandler.ts | 5 +- .../actionHandler/usePickAndPlaceHandler.ts | 5 +- .../actionHandler/useRetrieveHandler.ts | 5 +- .../actionHandler/useStoreHandler.ts | 5 +- .../vehicle/actionHandler/useTravelHandler.ts | 5 +- .../simulation/analysis/ROI/roiData.tsx | 5 +- .../analysis/throughPut/throughPutData.tsx | 5 +- .../conveyorInstance/conveyorInstance.tsx | 7 +- .../events/points/creator/pointsCreator.tsx | 5 +- .../triggerConnections/triggerConnector.tsx | 5 +- .../machineInstance/machineInstance.tsx | 5 +- .../instances/instance/materialInstance.tsx | 9 +- .../simulation/products/productContext.tsx | 37 + .../modules/simulation/products/products.tsx | 34 +- .../armInstance/roboticArmInstance.tsx | 5 +- .../simulation/simulator/simulator.tsx | 5 +- .../simulation/spatialUI/arm/armBotUI.tsx | 6 +- .../spatialUI/arm/useDraggableGLTF.ts | 12 +- .../spatialUI/vehicle/vehicleUI.tsx | 7 +- .../triggerHandler/useTriggerHandler.ts | 5 +- .../instances/instance/vehicleInstance.tsx | 5 +- app/src/pages/Project.tsx | 126 +- .../store/simulation/useSimulationStore.ts | 82 +- app/src/styles/layout/compareLayout.scss | 1013 +++++++++-------- 46 files changed, 996 insertions(+), 776 deletions(-) create mode 100644 app/src/components/layout/scenes/ComparisonScene.tsx create mode 100644 app/src/components/layout/scenes/ComparisonSceneProvider.tsx create mode 100644 app/src/components/layout/scenes/MainScene.tsx create mode 100644 app/src/components/layout/scenes/MainSceneProvider.tsx create mode 100644 app/src/modules/simulation/products/productContext.tsx diff --git a/app/src/components/layout/scenes/ComparisonScene.tsx b/app/src/components/layout/scenes/ComparisonScene.tsx new file mode 100644 index 0000000..d823d5b --- /dev/null +++ b/app/src/components/layout/scenes/ComparisonScene.tsx @@ -0,0 +1,48 @@ +import { useProductContext } from '../../../modules/simulation/products/productContext' +import RegularDropDown from '../../ui/inputs/RegularDropDown'; +import { useProductStore } from '../../../store/simulation/useProductStore'; +import { useSaveVersion } from '../../../store/builder/store'; +import useModuleStore from '../../../store/useModuleStore'; +import CompareLayOut from '../../ui/compareVersion/CompareLayOut'; +import ComparisonResult from '../../ui/compareVersion/ComparisonResult'; +import { useComparisonProduct } from '../../../store/simulation/useSimulationStore'; +import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; + +function ComparisonScene() { + const { isPlaying } = usePlayButtonStore(); + const { products } = useProductStore(); + const { isVersionSaved } = useSaveVersion(); + const { activeModule } = useModuleStore(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); + const { comparisonProduct, setComparisonProduct } = useComparisonProduct(); + + const handleSelectLayout = (option: string) => { + const product = products.find((product) => product.productName === option); + if (product) { + setComparisonProduct(product.productId, product.productName); + } + }; + return ( + <> + {isVersionSaved && activeModule === "simulation" && selectedProduct && ( + <> + {comparisonProduct && !isPlaying && +
+ l.productName)} // Pass layout names as options + onSelect={handleSelectLayout} + search={false} + /> +
+ } + + {false && } + + )} + + ) +} + +export default ComparisonScene; diff --git a/app/src/components/layout/scenes/ComparisonSceneProvider.tsx b/app/src/components/layout/scenes/ComparisonSceneProvider.tsx new file mode 100644 index 0000000..e47805c --- /dev/null +++ b/app/src/components/layout/scenes/ComparisonSceneProvider.tsx @@ -0,0 +1,12 @@ +import { ProductProvider } from '../../../modules/simulation/products/productContext' +import ComparisonScene from './ComparisonScene'; + +function ComparisonSceneProvider() { + return ( + + + + ) +} + +export default ComparisonSceneProvider \ No newline at end of file diff --git a/app/src/components/layout/scenes/MainScene.tsx b/app/src/components/layout/scenes/MainScene.tsx new file mode 100644 index 0000000..3101be5 --- /dev/null +++ b/app/src/components/layout/scenes/MainScene.tsx @@ -0,0 +1,113 @@ +import React from 'react' +import { useLoadingProgress, useSaveVersion, useSocketStore, useWidgetSubOption } from '../../../store/builder/store'; +import useModuleStore, { useThreeDStore } from '../../../store/useModuleStore'; +import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; +import { useSelectedZoneStore } from '../../../store/visualization/useZoneStore'; +import { useFloatingWidget } from '../../../store/visualization/useDroppedObjectsStore'; +import { useSelectedUserStore } from '../../../store/collaboration/useCollabStore'; +import KeyPressListener from '../../../utils/shortcutkeys/handleShortcutKeys'; +import LoadingPage from '../../templates/LoadingPage'; +import ModuleToggle from '../../ui/ModuleToggle'; +import SideBarLeft from '../sidebarLeft/SideBarLeft'; +import SideBarRight from '../sidebarRight/SideBarRight'; +import RealTimeVisulization from '../../../modules/visualization/RealTimeVisulization'; +import MarketPlace from '../../../modules/market/MarketPlace'; +import Tools from '../../ui/Tools'; +import SimulationPlayer from '../../ui/simulation/simulationPlayer'; +import ControlsPlayer from '../controls/ControlsPlayer'; +import SelectFloorPlan from '../../temporary/SelectFloorPlan'; +import { createHandleDrop } from '../../../modules/visualization/functions/handleUiDrop'; +import Scene from '../../../modules/scene/scene'; +import { useMainProduct } from '../../../store/simulation/useSimulationStore'; +import { useProductContext } from '../../../modules/simulation/products/productContext'; +import { useProductStore } from '../../../store/simulation/useProductStore'; +import RegularDropDown from '../../ui/inputs/RegularDropDown'; + +function MainScene() { + const { products } = useProductStore(); + const { setMainProduct } = useMainProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); + const { isVersionSaved } = useSaveVersion(); + const { activeModule } = useModuleStore(); + const { selectedUser } = useSelectedUserStore(); + const { loadingProgress } = useLoadingProgress(); + const { toggleThreeD } = useThreeDStore(); + const { isPlaying } = usePlayButtonStore(); + const { widgetSubOption } = useWidgetSubOption(); + const { visualizationSocket } = useSocketStore(); + const { selectedZone } = useSelectedZoneStore(); + const { setFloatingWidget } = useFloatingWidget(); + + const handleSelectLayout = (option: string) => { + const product = products.find((product) => product.productName === option); + if (product) { + setMainProduct(product.productId, product.productName); + } + }; + + return ( + <> + {!selectedUser && ( + <> + + {loadingProgress > 0 && } + {!isPlaying && ( + <> + {toggleThreeD && } + + + + )} + + {activeModule === "market" && } + {activeModule !== "market" && !isPlaying && !isVersionSaved && ( + + )} + {isPlaying && activeModule === "simulation" && } + {isPlaying && activeModule !== "simulation" && } + + {/* remove this later */} + {activeModule === "builder" && !toggleThreeD && } + + )} +
+ createHandleDrop({ + widgetSubOption, + visualizationSocket, + selectedZone, + setFloatingWidget, + event, + }) + } + onDragOver={(event) => event.preventDefault()} + > + +
+ + {selectedProduct && isVersionSaved && !isPlaying && ( +
+ l.productName)} // Pass layout names as options + onSelect={handleSelectLayout} + search={false} + /> +
+ )} + + ) +} + +export default MainScene \ No newline at end of file diff --git a/app/src/components/layout/scenes/MainSceneProvider.tsx b/app/src/components/layout/scenes/MainSceneProvider.tsx new file mode 100644 index 0000000..17971fa --- /dev/null +++ b/app/src/components/layout/scenes/MainSceneProvider.tsx @@ -0,0 +1,12 @@ +import { ProductProvider } from '../../../modules/simulation/products/productContext' +import MainScene from './MainScene' + +function MainSceneProvider() { + return ( + + + + ) +} + +export default MainSceneProvider \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx index b9550ae..c47a169 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/EventProperties.tsx @@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react"; import { useSelectedEventData, useSelectedEventSphere, - useSelectedProduct, } from "../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import ConveyorMechanics from "./mechanics/conveyorMechanics"; @@ -13,11 +12,13 @@ import StorageMechanics from "./mechanics/storageMechanics"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import { handleAddEventToProduct } from "../../../../../modules/simulation/events/points/functions/handleAddEventToProduct"; import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; +import { useProductContext } from "../../../../../modules/simulation/products/productContext"; const EventProperties: React.FC = () => { const { selectedEventData } = useSelectedEventData(); const { getEventByModelUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const [currentEventData, setCurrentEventData] = useState( null ); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx index 632805b..52cd9db 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/components/ActionsList.tsx @@ -8,10 +8,10 @@ import RenameInput from "../../../../../ui/inputs/RenameInput"; import { handleResize } from "../../../../../../functions/handleResizePannel"; import { useSelectedAction, - useSelectedProduct, } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; +import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; interface ActionsListProps { selectedPointData: any; @@ -33,7 +33,8 @@ const ActionsList: React.FC = ({ // store const { renameAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { selectedAction, setSelectedAction } = useSelectedAction(); const handleRenameAction = (newName: string) => { @@ -87,11 +88,10 @@ const ActionsList: React.FC = ({ selectedPointData?.actions?.map((action: any) => (
@@ -286,7 +287,7 @@ function RoboticArmMechanics() { {}} + onSelect={() => { }} disabled={true} /> diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index 4ea5687..1c27ad1 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -6,9 +6,10 @@ import StorageAction from "../actions/StorageAction"; import ActionsList from "../components/ActionsList"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; -import { useSelectedAction, useSelectedEventData, useSelectedProduct } from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore"; import * as THREE from 'three'; import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; +import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; function StorageMechanics() { const { storageUnitStore } = useSceneContext(); @@ -16,7 +17,8 @@ function StorageMechanics() { const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); const { getPointByUuid, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { setSelectedAction, clearSelectedAction } = useSelectedAction(); const { setCurrentMaterials, clearCurrentMaterials, updateCurrentLoad, getStorageUnitById } = storageUnitStore(); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index 8e61dcf..786f38e 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -7,13 +7,13 @@ import { useSelectedAction, useSelectedEventData, useSelectedEventSphere, - useSelectedProduct, } from "../../../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import TravelAction from "../actions/TravelAction"; import ActionsList from "../components/ActionsList"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; +import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; function VehicleMechanics() { const { vehicleStore } = useSceneContext(); @@ -21,7 +21,8 @@ function VehicleMechanics() { const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { setSelectedAction, clearSelectedAction } = useSelectedAction(); const { getVehicleById } = vehicleStore(); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx index fb0b97a..d94b553 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -11,9 +11,9 @@ import { handleResize } from "../../../../../../functions/handleResizePannel"; import { useProductStore } from "../../../../../../store/simulation/useProductStore"; import { useSelectedAction, - useSelectedProduct, } from "../../../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; +import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; type TriggerProps = { selectedPointData?: PointsScheme | undefined; @@ -22,7 +22,8 @@ type TriggerProps = { const Trigger = ({ selectedPointData, type }: TriggerProps) => { const [currentAction, setCurrentAction] = useState(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { getActionByUuid, getEventByModelUuid, @@ -60,10 +61,10 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { ) { actionUuid = ( selectedPointData as - | ConveyorPointSchema - | VehiclePointSchema - | MachinePointSchema - | StoragePointSchema + | ConveyorPointSchema + | VehiclePointSchema + | MachinePointSchema + | StoragePointSchema ).action?.actionUuid; } else if ( type === "RoboticArm" && @@ -153,10 +154,10 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { return [ ( model as - | VehicleEventSchema - | RoboticArmEventSchema - | MachineEventSchema - | StorageEventSchema + | VehicleEventSchema + | RoboticArmEventSchema + | MachineEventSchema + | StorageEventSchema ).point, ]; } @@ -416,11 +417,10 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { {triggers.map((trigger) => (
setSelectedTrigger(trigger)} >
- {selectedLayout && ( + {comparisonProduct && (
- +
)} {width !== "0px" && - !selectedLayout && ( // Show only if no layout selected + !comparisonProduct && ( // Show only if no layout selected
@@ -177,16 +173,6 @@ const CompareLayOut: React.FC = ({ dummyLayouts }) => { )} {/* Always show after layout is selected */} - {width !== "0px" && selectedLayout && ( -
- l.productName)} // Pass layout names as options - onSelect={handleSelectLayout} - search={false} - /> -
- )}
); diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index 5b6008d..e407d3c 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -12,6 +12,7 @@ import useModuleStore from "../../../store/useModuleStore"; import { useThree } from "@react-three/fiber"; import { CameraControls } from "@react-three/drei"; import addAssetModel from "./functions/addAssetModel"; +import { useSceneContext } from "../../scene/sceneContext"; const gltfLoaderWorker = new Worker( new URL( @@ -20,8 +21,9 @@ const gltfLoaderWorker = new Worker( ) ); -function AssetsGroup({ floorGroup, plane }: { floorGroup: RefGroup, plane: RefMesh }) { +function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, readonly plane: RefMesh }) { const { activeModule } = useModuleStore(); + const { layout } = useSceneContext(); const { socket } = useSocketStore(); const { controls, gl, pointer, camera, raycaster } = useThree(); const { setLoadingProgress } = useLoadingProgress(); diff --git a/app/src/modules/builder/asset/models/model/model.tsx b/app/src/modules/builder/asset/models/model/model.tsx index d7af8d4..39fb4be 100644 --- a/app/src/modules/builder/asset/models/model/model.tsx +++ b/app/src/modules/builder/asset/models/model/model.tsx @@ -12,7 +12,8 @@ import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; import useModuleStore, { useSubModuleStore } from '../../../../../store/useModuleStore'; import { useLeftData, useTopData } from '../../../../../store/visualization/useZone3DWidgetStore'; -import { useSelectedAsset, useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; +import { useSelectedAsset } from '../../../../../store/simulation/useSimulationStore'; +import { useProductContext } from '../../../../simulation/products/productContext'; function Model({ asset }: { readonly asset: Asset }) { const { camera, controls, gl } = useThree(); @@ -24,7 +25,8 @@ function Model({ asset }: { readonly asset: Asset }) { const { setLeft } = useLeftData(); const { getIsEventInProduct } = useProductStore(); const { getEventByModelUuid } = useEventsStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { setSelectedAsset, clearSelectedAsset } = useSelectedAsset(); const { socket } = useSocketStore(); const { deletableFloorItem, setDeletableFloorItem } = useDeletableFloorItem(); @@ -199,7 +201,7 @@ function Model({ asset }: { readonly asset: Asset }) { } } - + const handleContextMenu = (asset: Asset, evt: ThreeEvent) => { if (activeTool === "cursor" && subModule === 'simulations') { @@ -250,10 +252,10 @@ function Model({ asset }: { readonly asset: Asset }) { userData={asset} onDoubleClick={(e) => { e.stopPropagation(); + handleDblClick(asset); }} onClick={(e) => { e.stopPropagation(); - handleDblClick(asset); handleClick(asset); }} onPointerOver={(e) => { diff --git a/app/src/modules/scene/controls/selectionControls/moveControls.tsx b/app/src/modules/scene/controls/selectionControls/moveControls.tsx index d28e852..3a68e96 100644 --- a/app/src/modules/scene/controls/selectionControls/moveControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/moveControls.tsx @@ -11,11 +11,11 @@ import * as Types from "../../../../types/world/worldTypes"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { snapControls } from "../../../../utils/handleSnap"; import DistanceFindingControls from "./distanceFindingControls"; import { useAssetsStore } from "../../../../store/builder/useAssetStore"; +import { useProductContext } from "../../../simulation/products/productContext"; function MoveControls({ movedObjects, @@ -34,7 +34,8 @@ function MoveControls({ const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { socket } = useSocketStore(); const [keyEvent, setKeyEvent] = useState<"Ctrl" | "Shift" | "Ctrl+Shift" | "">(""); const email = localStorage.getItem("email"); diff --git a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx index 83a1eb4..0418d46 100644 --- a/app/src/modules/scene/controls/selectionControls/rotateControls.tsx +++ b/app/src/modules/scene/controls/selectionControls/rotateControls.tsx @@ -6,9 +6,9 @@ import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../st import * as Types from "../../../../types/world/worldTypes"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { useAssetsStore } from "../../../../store/builder/useAssetStore"; +import { useProductContext } from "../../../simulation/products/productContext"; function RotateControls({ rotatedObjects, @@ -27,7 +27,8 @@ function RotateControls({ const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { socket } = useSocketStore(); const email = localStorage.getItem('email') @@ -208,7 +209,7 @@ function RotateControls({ if (obj.userData.eventData) { const eventData = useEventsStore.getState().getEventByModelUuid(obj.userData.modelUuid); - const productData = useProductStore.getState().getEventByModelUuid(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid); + const productData = useProductStore.getState().getEventByModelUuid(selectedProductStore.getState().selectedProduct.productId, obj.userData.modelUuid); if (eventData) { useEventsStore.getState().updateEvent(obj.userData.modelUuid, { @@ -217,7 +218,7 @@ function RotateControls({ }) } if (productData) { - const event = useProductStore.getState().updateEvent(useSelectedProduct.getState().selectedProduct.productId, obj.userData.modelUuid, { + const event = useProductStore.getState().updateEvent(selectedProductStore.getState().selectedProduct.productId, obj.userData.modelUuid, { position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: [obj.rotation.x, obj.rotation.y, obj.rotation.z], }) diff --git a/app/src/modules/scene/controls/transformControls/transformControls.tsx b/app/src/modules/scene/controls/transformControls/transformControls.tsx index 66e965f..3c66589 100644 --- a/app/src/modules/scene/controls/transformControls/transformControls.tsx +++ b/app/src/modules/scene/controls/transformControls/transformControls.tsx @@ -8,10 +8,10 @@ import { useEffect, useState } from "react"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; import { useAssetsStore } from "../../../../store/builder/useAssetStore"; +import { useProductContext } from "../../../simulation/products/productContext"; export default function TransformControl() { const state = useThree(); @@ -21,7 +21,8 @@ export default function TransformControl() { const { setObjectRotation } = useObjectRotation(); const { activeTool } = useActiveTool(); const { socket } = useSocketStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { updateAsset, getAssetById } = useAssetsStore(); const email = localStorage.getItem('email') diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index 00c5bbc..7777a30 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -1,5 +1,6 @@ import { useMemo } from "react"; import { Canvas } from "@react-three/fiber"; +import { Color } from "three"; import { KeyboardControls } from "@react-three/drei"; import { SceneProvider } from "./sceneContext"; @@ -9,7 +10,7 @@ import Setup from "./setup/setup"; import Simulation from "../simulation/simulation"; import Collaboration from "../collaboration/collaboration"; -export default function Scene() { +export default function Scene({ layout }: { readonly layout: 'Main Layout' | 'Comparison Layout' }) { const map = useMemo(() => [ { name: "forward", keys: ["ArrowUp", "w", "W"] }, { name: "backward", keys: ["ArrowDown", "s", "S"] }, @@ -18,7 +19,7 @@ export default function Scene() { ], []); return ( - + { e.preventDefault(); }} + onCreated={(e) => { + e.scene.background = new Color(0x19191d); + }} > diff --git a/app/src/modules/scene/sceneContext.tsx b/app/src/modules/scene/sceneContext.tsx index 1eea293..0145b45 100644 --- a/app/src/modules/scene/sceneContext.tsx +++ b/app/src/modules/scene/sceneContext.tsx @@ -13,11 +13,18 @@ type SceneContextValue = { conveyorStore: ConveyorStoreType; vehicleStore: VehicleStoreType; storageUnitStore: StorageUnitStoreType; + layout: 'Main Layout' | 'Comparison Layout'; }; const SceneContext = createContext(null); -export function SceneProvider({ children }: { readonly children: React.ReactNode }) { +export function SceneProvider({ + children, + layout +}: { + readonly children: React.ReactNode; + readonly layout: 'Main Layout' | 'Comparison Layout'; +}) { const materialStore = useMemo(() => createMaterialStore(), []); const armBotStore = useMemo(() => createArmBotStore(), []); const machineStore = useMemo(() => createMachineStore(), []); @@ -32,9 +39,10 @@ export function SceneProvider({ children }: { readonly children: React.ReactNode machineStore, conveyorStore, vehicleStore, - storageUnitStore + storageUnitStore, + layout } - ), [materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore]); + ), [materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout]); return ( @@ -50,4 +58,4 @@ export function useSceneContext() { throw new Error('useSceneContext must be used within a SceneProvider'); } return context; -} +} \ No newline at end of file diff --git a/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts b/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts index a2efcfb..d546b12 100644 --- a/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts +++ b/app/src/modules/simulation/actions/conveyor/actionHandler/useSpawnHandler.ts @@ -2,9 +2,9 @@ import { useCallback, useEffect, useState } from "react"; import * as THREE from 'three'; import { useFrame } from "@react-three/fiber"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { usePlayButtonStore, useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; interface SpawnInstance { lastSpawnTime: number | null; @@ -30,7 +30,8 @@ export function useSpawnHandler() { const { isPaused } = usePauseButtonStore(); const { speed } = useAnimationPlaySpeed(); const { isReset } = useResetButtonStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const [activeSpawns, setActiveSpawns] = useState>(new Map()); diff --git a/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts b/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts index c7dc10b..378975a 100644 --- a/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts +++ b/app/src/modules/simulation/actions/machine/actionHandler/useProcessHandler.ts @@ -1,14 +1,15 @@ import { useCallback } from "react"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function useProcessHandler() { const { materialStore, machineStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { getMaterialById, setMaterial } = materialStore(); const { addCurrentAction } = machineStore(); const { getModelUuidByActionUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const processLogStatus = (materialUuid: string, status: string) => { echo.log(`${materialUuid}, ${status}`); diff --git a/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts index 9f53c80..cfa62f9 100644 --- a/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts +++ b/app/src/modules/simulation/actions/roboticArm/actionHandler/usePickAndPlaceHandler.ts @@ -1,14 +1,15 @@ import { useCallback } from "react"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function usePickAndPlaceHandler() { const { materialStore, armBotStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { getMaterialById } = materialStore(); const { addCurrentAction } = armBotStore(); const { getModelUuidByActionUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const pickAndPlaceLogStatus = (materialUuid: string, status: string) => { echo.warn(`${materialUuid}, ${status}`); diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts index 3f4f9a8..5d4ea93 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts @@ -1,17 +1,18 @@ import { useCallback, useState, useEffect, useRef } from "react"; import { useFrame } from "@react-three/fiber"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function useRetrieveHandler() { const { materialStore, armBotStore, vehicleStore, storageUnitStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { addMaterial } = materialStore(); const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = useProductStore(); const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore(); const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { getArmBotById, addCurrentAction } = armBotStore(); const { isPlaying } = usePlayButtonStore(); const { speed } = useAnimationPlaySpeed(); diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts index 61e1f94..2656457 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useStoreHandler.ts @@ -1,14 +1,15 @@ import { useCallback } from "react"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function useStoreHandler() { const { materialStore, storageUnitStore } = useSceneContext(); const { getMaterialById, removeMaterial, setEndTime } = materialStore(); const { addCurrentMaterial, updateCurrentLoad } = storageUnitStore(); const { getModelUuidByActionUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const storeLogStatus = (materialUuid: string, status: string) => { echo.info(`${materialUuid}, ${status}`); diff --git a/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts b/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts index 69c18b5..fe3dd4a 100644 --- a/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts +++ b/app/src/modules/simulation/actions/vehicle/actionHandler/useTravelHandler.ts @@ -1,13 +1,14 @@ import { useCallback } from "react"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import { useSceneContext } from "../../../../scene/sceneContext"; +import { useProductContext } from "../../../products/productContext"; export function useTravelHandler() { const { materialStore, vehicleStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { getMaterialById } = materialStore(); const { getModelUuidByActionUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { incrementVehicleLoad, addCurrentMaterial } = vehicleStore(); const travelLogStatus = (materialUuid: string, status: string) => { diff --git a/app/src/modules/simulation/analysis/ROI/roiData.tsx b/app/src/modules/simulation/analysis/ROI/roiData.tsx index f1ddda5..4d6444d 100644 --- a/app/src/modules/simulation/analysis/ROI/roiData.tsx +++ b/app/src/modules/simulation/analysis/ROI/roiData.tsx @@ -1,12 +1,13 @@ import React, { useEffect, useState } from 'react' import { useInputValues, useProductionCapacityData, useROISummaryData } from '../../../../store/builder/store'; -import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; +import { useProductContext } from '../../products/productContext'; export default function ROIData() { + const { selectedProductStore } = useProductContext(); const { inputValues } = useInputValues(); const { productionCapacityData } = useProductionCapacityData() - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { isPlaying } = usePlayButtonStore(); const { setRoiSummaryData } = useROISummaryData(); useEffect(() => { diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx index 6fde8db..6b9062f 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -1,14 +1,15 @@ import { useEffect } from 'react'; -import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useProductStore } from '../../../../store/simulation/useProductStore'; import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; import { useMachineCount, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store'; import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; import { useSceneContext } from '../../../scene/sceneContext'; +import { useProductContext } from '../../products/productContext'; export default function ThroughPutData() { const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { products, getProductById } = useProductStore(); const { armBots } = armBotStore(); const { vehicles } = vehicleStore(); diff --git a/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx index 69061d6..67db5b9 100644 --- a/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx +++ b/app/src/modules/simulation/conveyor/instances/conveyorInstance/conveyorInstance.tsx @@ -1,13 +1,14 @@ import { useEffect } from 'react' import { useResetButtonStore } from '../../../../../store/usePlayButtonStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; // import { findConveyorSubsequence } from '../../../simulator/functions/getConveyorSequencesInProduct'; -function ConveyorInstance({ conveyor }: { conveyor: ConveyorStatus }) { +function ConveyorInstance({ conveyor }: { readonly conveyor: ConveyorStatus }) { const { getProductById } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { materialStore, conveyorStore } = useSceneContext(); const { getMaterialsByCurrentModelUuid, materials } = materialStore(); const { isReset } = useResetButtonStore(); diff --git a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx index c1b7d23..89513ec 100644 --- a/app/src/modules/simulation/events/points/creator/pointsCreator.tsx +++ b/app/src/modules/simulation/events/points/creator/pointsCreator.tsx @@ -2,7 +2,6 @@ import { useEffect, useRef, useState } from "react"; import * as THREE from "three"; import { useEventsStore } from "../../../../../store/simulation/useEventsStore"; import { useProductStore } from "../../../../../store/simulation/useProductStore"; -import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore"; import useModuleStore, { useSubModuleStore } from "../../../../../store/useModuleStore"; import { TransformControls } from "@react-three/drei"; import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys"; @@ -10,13 +9,15 @@ import { useSelectedEventSphere, useSelectedEventData, } from "../../../../../st import { useThree } from "@react-three/fiber"; import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore"; import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi"; +import { useProductContext } from "../../../products/productContext"; function PointsCreator() { const { gl, raycaster, scene, pointer, camera } = useThree(); const { subModule } = useSubModuleStore(); + const { selectedProductStore } = useProductContext(); const { events, updatePoint, getPointByUuid, getEventByModelUuid } = useEventsStore(); const { getEventByModelUuid: getEventByModelUuidFromProduct, updatePoint: updatePointFromProduct, getEventByModelUuid: getEventByModelUuidFromProduct2, getPointByUuid: getPointByUuidFromProduct } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { activeModule } = useModuleStore(); const transformRef = useRef(null); const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null); diff --git a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx index 2a420ae..d082419 100644 --- a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx +++ b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx @@ -5,13 +5,13 @@ import { useSubModuleStore } from "../../../../store/useModuleStore"; import { useSelectedAction, useSelectedAsset } from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; -import { useSelectedProduct } from "../../../../store/simulation/useSimulationStore"; import { handleAddEventToProduct } from "../points/functions/handleAddEventToProduct"; import { QuadraticBezierLine } from "@react-three/drei"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; import { useDeleteTool } from "../../../../store/builder/store"; import { usePlayButtonStore } from "../../../../store/usePlayButtonStore"; import { ArrowOnQuadraticBezier, Arrows } from "../arrows/arrows"; +import { useProductContext } from "../../products/productContext"; interface ConnectionLine { id: string; @@ -23,9 +23,10 @@ interface ConnectionLine { function TriggerConnector() { const { gl, raycaster, scene, pointer, camera } = useThree(); const { subModule } = useSubModuleStore(); + const { selectedProductStore } = useProductContext(); const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, removeTrigger, addEvent, getEventByModelUuid, getPointUuidByActionUuid, getProductById } = useProductStore(); const { selectedAsset, clearSelectedAsset } = useSelectedAsset(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const [hoveredLineKey, setHoveredLineKey] = useState(null); const groupRefs = useRef>({}); const [helperlineColor, setHelperLineColor] = useState("red"); diff --git a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx index da8ea2f..2356e76 100644 --- a/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx +++ b/app/src/modules/simulation/machine/instances/machineInstance/machineInstance.tsx @@ -2,9 +2,9 @@ import { useEffect, useRef, useState } from 'react' import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import MachineAnimator from '../animator/machineAnimator'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; function MachineInstance({ machineDetail }: { readonly machineDetail: MachineStatus }) { const [currentPhase, setCurrentPhase] = useState('idle'); @@ -17,8 +17,9 @@ function MachineInstance({ machineDetail }: { readonly machineDetail: MachineSta const isPausedRef = useRef(false); const { isPlaying } = usePlayButtonStore(); const { machineStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { machines, setMachineState, setMachineActive, incrementIdleTime, incrementActiveTime, resetTime } = machineStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { getActionByUuid } = useProductStore(); const { triggerPointActions } = useTriggerHandler(); const { speed } = useAnimationPlaySpeed(); diff --git a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx index fce425a..9826ad9 100644 --- a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx +++ b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx @@ -1,18 +1,19 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react' +import { useMemo, useRef } from 'react' import * as THREE from 'three'; import MaterialAnimator from '../animator/materialAnimator'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { MaterialModel } from '../material/materialModel'; import { useThree } from '@react-three/fiber'; import { useAnimationPlaySpeed } from '../../../../../store/usePlayButtonStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; +import { useProductContext } from '../../../products/productContext'; -function MaterialInstance({ material }: { material: MaterialSchema }) { +function MaterialInstance({ material }: { readonly material: MaterialSchema }) { const matRef: any = useRef(); const { scene } = useThree(); + const { selectedProductStore } = useProductContext(); const { getModelUuidByPointUuid, getPointByUuid, getEventByModelUuid, getActionByUuid, getTriggerByUuid, getActionByPointUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { speed } = useAnimationPlaySpeed(); const { triggerPointActions } = useTriggerHandler(); diff --git a/app/src/modules/simulation/products/productContext.tsx b/app/src/modules/simulation/products/productContext.tsx new file mode 100644 index 0000000..ba95435 --- /dev/null +++ b/app/src/modules/simulation/products/productContext.tsx @@ -0,0 +1,37 @@ +import { createContext, useContext, useMemo } from 'react'; +import { createSelectedProductStore, SelectedProductType } from '../../../store/simulation/useSimulationStore'; + +type ProductContextValue = { + selectedProductStore: SelectedProductType, +}; + +const ProductContext = createContext(null); + +export function ProductProvider({ + children, +}: { + readonly children: React.ReactNode; +}) { + const selectedProductStore = useMemo(() => createSelectedProductStore(), []); + + const contextValue = useMemo(() => ( + { + selectedProductStore + } + ), [selectedProductStore]); + + return ( + + {children} + + ); +} + +// Base hook to get the context +export function useProductContext() { + const context = useContext(ProductContext); + if (!context) { + throw new Error('useProductContext must be used within a ProductProvider'); + } + return context; +} \ No newline at end of file diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index 49310e2..1b08013 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -1,16 +1,18 @@ import * as THREE from 'three'; import { useEffect } from 'react'; import { useProductStore } from '../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; import { upsertProductOrEventApi } from '../../../services/simulation/products/UpsertProductOrEventApi'; import { getAllProductsApi } from '../../../services/simulation/products/getallProductsApi'; import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore'; import { useSceneContext } from '../../scene/sceneContext'; +import { useProductContext } from './productContext'; +import { useComparisonProduct, useMainProduct } from '../../../store/simulation/useSimulationStore'; function Products() { - const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); + const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout } = useSceneContext(); const { products, getProductById, addProduct, setProducts } = useProductStore(); - const { selectedProduct, setSelectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct, setSelectedProduct } = selectedProductStore(); const { addVehicle, clearvehicles } = vehicleStore(); const { addArmBot, clearArmBots } = armBotStore(); const { addMachine, clearMachines } = machineStore(); @@ -18,6 +20,24 @@ function Products() { const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = storageUnitStore(); const { isReset } = useResetButtonStore(); const { isPlaying } = usePlayButtonStore(); + const { mainProduct } = useMainProduct(); + const { comparisonProduct } = useComparisonProduct(); + + useEffect(() => { + if (layout === 'Main Layout' && mainProduct) { + setSelectedProduct(mainProduct.productId, mainProduct.productName); + } + }, [mainProduct]) + + useEffect(() => { + if (layout === 'Comparison Layout' && comparisonProduct) { + setSelectedProduct(comparisonProduct.productId, comparisonProduct.productName); + } + }, [comparisonProduct]) + + useEffect(() => { + console.log(selectedProduct); + }, [selectedProduct]) useEffect(() => { const email = localStorage.getItem('email') @@ -28,10 +48,14 @@ function Products() { const name = 'Product 1'; addProduct(name, id); upsertProductOrEventApi({ productName: name, productId: id, organization: organization }) - setSelectedProduct(id, name); + if (layout === 'Main Layout') { + setSelectedProduct(id, name); + } } else { setProducts(data); - setSelectedProduct(data[0].productId, data[0].productName); + if (layout === 'Main Layout') { + setSelectedProduct(data[0].productId, data[0].productName); + } } }) }, []) diff --git a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx index e0c26bc..40cd0f1 100644 --- a/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx +++ b/app/src/modules/simulation/roboticArm/instances/armInstance/roboticArmInstance.tsx @@ -7,9 +7,9 @@ import MaterialAnimator from '../animator/materialAnimator'; import armModel from "../../../../../assets/gltf-glb/rigged/ik_arm_1.glb"; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) { @@ -25,12 +25,13 @@ function RoboticArmInstance({ armBot }: { readonly armBot: ArmBotStatus }) { const isSpeedRef = useRef(null); let startTime: number; + const { selectedProductStore } = useProductContext(); const { materialStore, armBotStore, vehicleStore, storageUnitStore } = useSceneContext(); const { setArmBotActive, setArmBotState, removeCurrentAction, incrementActiveTime, incrementIdleTime } = armBotStore(); const { decrementVehicleLoad, removeLastMaterial } = vehicleStore(); const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = storageUnitStore(); const { getMaterialById, setIsVisible, setIsPaused } = materialStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { getActionByUuid, getEventByActionUuid, getEventByModelUuid } = useProductStore(); const { triggerPointActions } = useTriggerHandler(); const { isPlaying } = usePlayButtonStore(); diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx index aa0b9f6..ecd50b2 100644 --- a/app/src/modules/simulation/simulator/simulator.tsx +++ b/app/src/modules/simulation/simulator/simulator.tsx @@ -3,12 +3,13 @@ import { useProductStore } from '../../../store/simulation/useProductStore'; import { useActionHandler } from '../actions/useActionHandler'; import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayButtonStore'; import { determineExecutionOrder } from './functions/determineExecutionOrder'; -import { useSelectedProduct } from '../../../store/simulation/useSimulationStore'; +import { useProductContext } from '../products/productContext'; function Simulator() { + const { selectedProductStore } = useProductContext(); const { products, getProductById } = useProductStore(); const { handleAction } = useActionHandler(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { isPlaying } = usePlayButtonStore(); const { isReset } = useResetButtonStore(); diff --git a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx index 7a835f7..5624582 100644 --- a/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx +++ b/app/src/modules/simulation/spatialUI/arm/armBotUI.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { useSelectedAction, useSelectedEventSphere, useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; +import { useSelectedAction, useSelectedEventSphere } from '../../../../store/simulation/useSimulationStore'; import { useGLTF } from '@react-three/drei'; import { useThree } from '@react-three/fiber'; import { useProductStore } from '../../../../store/simulation/useProductStore'; @@ -11,6 +11,7 @@ import armPick from "../../../../assets/gltf-glb/ui/arm_ui_pick.glb"; import armDrop from "../../../../assets/gltf-glb/ui/arm_ui_drop.glb"; import { upsertProductOrEventApi } from '../../../../services/simulation/products/UpsertProductOrEventApi'; import { useSceneContext } from '../../../scene/sceneContext'; +import { useProductContext } from '../../products/productContext'; type Positions = { pick: [number, number, number]; @@ -21,7 +22,8 @@ type Positions = { const ArmBotUI = () => { const { getEventByModelUuid, updateAction, getActionByUuid } = useProductStore(); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { scene } = useThree(); const { selectedAction } = useSelectedAction(); const { armBotStore } = useSceneContext(); diff --git a/app/src/modules/simulation/spatialUI/arm/useDraggableGLTF.ts b/app/src/modules/simulation/spatialUI/arm/useDraggableGLTF.ts index e1f7fbf..8794ffd 100644 --- a/app/src/modules/simulation/spatialUI/arm/useDraggableGLTF.ts +++ b/app/src/modules/simulation/spatialUI/arm/useDraggableGLTF.ts @@ -4,21 +4,19 @@ import { ThreeEvent, useThree } from "@react-three/fiber"; import { useProductStore } from "../../../../store/simulation/useProductStore"; import { useSelectedEventData, - useSelectedProduct, } from "../../../../store/simulation/useSimulationStore"; +import { useProductContext } from "../../products/productContext"; type OnUpdateCallback = (object: THREE.Object3D) => void; export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { - const { getEventByModelUuid, updateAction, getActionByUuid } = - useProductStore(); + const { getEventByModelUuid } = useProductStore(); const { selectedEventData } = useSelectedEventData(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { camera, gl, controls } = useThree(); const activeObjRef = useRef(null); - const planeRef = useRef( - new THREE.Plane(new THREE.Vector3(0, 1, 0), 0) - ); + const planeRef = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); const offsetRef = useRef(new THREE.Vector3()); const initialPositionRef = useRef(new THREE.Vector3()); diff --git a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx index c60e7e9..8765d14 100644 --- a/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx +++ b/app/src/modules/simulation/spatialUI/vehicle/vehicleUI.tsx @@ -5,7 +5,6 @@ import { useFrame, useThree } from "@react-three/fiber"; import { useSelectedEventSphere, useIsDragging, - useSelectedProduct, useIsRotating, } from "../../../../store/simulation/useSimulationStore"; import { useProductStore } from "../../../../store/simulation/useProductStore"; @@ -15,6 +14,7 @@ import { DoubleSide, Group, Plane, Vector3 } from "three"; import startPoint from "../../../../assets/gltf-glb/ui/arrow_green.glb"; import startEnd from "../../../../assets/gltf-glb/ui/arrow_red.glb"; import { useSceneContext } from "../../../scene/sceneContext"; +import { useProductContext } from "../../products/productContext"; const VehicleUI = () => { const { scene: startScene } = useGLTF(startPoint) as any; @@ -23,8 +23,9 @@ const VehicleUI = () => { const endMarker = useRef(null); const prevMousePos = useRef({ x: 0, y: 0 }); const { selectedEventSphere } = useSelectedEventSphere(); - const { selectedProduct } = useSelectedProduct(); - const { vehicleStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); + const { vehicleStore } = useSceneContext(); + const { selectedProduct } = selectedProductStore(); const { vehicles, getVehicleById } = vehicleStore(); const { updateEvent } = useProductStore(); const [startPosition, setStartPosition] = useState<[number, number, number]>([ diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts index 8ef5d1a..e349880 100644 --- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts +++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts @@ -1,17 +1,18 @@ import { useCallback } from 'react'; import { useActionHandler } from '../../actions/useActionHandler'; import { useProductStore } from '../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore'; import { useArmBotEventManager } from '../../roboticArm/eventManager/useArmBotEventManager'; import { useConveyorEventManager } from '../../conveyor/eventManager/useConveyorEventManager'; import { useVehicleEventManager } from '../../vehicle/eventManager/useVehicleEventManager'; import { useMachineEventManager } from '../../machine/eventManager/useMachineEventManager'; import { useSceneContext } from '../../../scene/sceneContext'; +import { useProductContext } from '../../products/productContext'; export function useTriggerHandler() { const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore } = useSceneContext(); + const { selectedProductStore } = useProductContext(); const { handleAction } = useActionHandler(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProduct } = selectedProductStore(); const { getEventByTriggerUuid, getEventByModelUuid, getActionByUuid, getModelUuidByActionUuid } = useProductStore(); const { getArmBotById } = armBotStore(); const { getConveyorById } = conveyorStore(); diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index b9339cc..38d38a8 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -5,10 +5,10 @@ import { NavMeshQuery } from '@recast-navigation/core'; import { useNavMesh } from '../../../../../store/builder/store'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore'; import { useProductStore } from '../../../../../store/simulation/useProductStore'; -import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore'; import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler'; import MaterialAnimator from '../animator/materialAnimator'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) { const { navMesh } = useNavMesh(); @@ -20,7 +20,8 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) const { getConveyorById } = conveyorStore(); const { triggerPointActions } = useTriggerHandler(); const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = useProductStore(); - const { selectedProduct } = useSelectedProduct(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = vehicleStore(); const [currentPhase, setCurrentPhase] = useState('stationed'); diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 2863e40..cca83af 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -1,61 +1,39 @@ -import React, { useEffect, useState } from "react"; -import ModuleToggle from "../components/ui/ModuleToggle"; -import SideBarLeft from "../components/layout/sidebarLeft/SideBarLeft"; -import SideBarRight from "../components/layout/sidebarRight/SideBarRight"; -import useModuleStore, { useThreeDStore } from "../store/useModuleStore"; -import RealTimeVisulization from "../modules/visualization/RealTimeVisulization"; -import Tools from "../components/ui/Tools"; +import React, { useEffect } from "react"; +import useModuleStore from "../store/useModuleStore"; import { useSocketStore, useOrganization, useUserName, useWallItems, useZones, - useLoadingProgress, - useWidgetSubOption, useSaveVersion, } from "../store/builder/store"; import { useNavigate } from "react-router-dom"; -import { usePlayButtonStore } from "../store/usePlayButtonStore"; -import MarketPlace from "../modules/market/MarketPlace"; -import LoadingPage from "../components/templates/LoadingPage"; -import KeyPressListener from "../utils/shortcutkeys/handleShortcutKeys"; import { useSelectedUserStore } from "../store/collaboration/useCollabStore"; import FollowPerson from "../components/templates/FollowPerson"; -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 RenderOverlay from "../components/templates/Overlay"; import LogList from "../components/ui/log/LogList"; import Footer from "../components/footer/Footer"; -import SelectFloorPlan from "../components/temporary/SelectFloorPlan"; -import ControlsPlayer from "../components/layout/controls/ControlsPlayer"; -import CompareLayOut from "../components/ui/compareVersion/CompareLayOut"; import { useToggleStore } from "../store/useUIToggleStore"; -import RegularDropDown from "../components/ui/inputs/RegularDropDown"; import VersionSaved from "../components/layout/sidebarRight/versionHisory/VersionSaved"; -import SimulationPlayer from "../components/ui/simulation/simulationPlayer"; import { useAssetsStore } from "../store/builder/useAssetStore"; -import { useProductStore } from "../store/simulation/useProductStore"; -import ThreadChat from "../components/ui/collaboration/ThreadChat"; -import ComparisonResult from "../components/ui/compareVersion/ComparisonResult"; +import ComparisonSceneProvider from "../components/layout/scenes/ComparisonSceneProvider"; +import MainSceneProvider from "../components/layout/scenes/MainSceneProvider"; const Project: React.FC = () => { let navigate = useNavigate(); const echo = useLogger(); const { setToggleUI } = useToggleStore(); - const { activeModule, setActiveModule } = useModuleStore(); - const { loadingProgress } = useLoadingProgress(); const { setAssets } = useAssetsStore(); const { setUserName } = useUserName(); const { setOrganization } = useOrganization(); const { setWallItems } = useWallItems(); const { setZones } = useZones(); const { isVersionSaved } = useSaveVersion(); - const { products } = useProductStore(); + const { selectedUser } = useSelectedUserStore(); + const { isLogListVisible } = useLogger(); useEffect(() => { if (!isVersionSaved) { @@ -85,84 +63,10 @@ const Project: React.FC = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - // 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(); - - const [selectedLayout, setSelectedLayout] = useState(null); // Track selected layout - - const dummyLayouts = [ - { id: 1, name: "Layout 1" }, - { id: 2, name: "Layout 2" }, - { id: 3, name: "Layout 3" }, - { id: 4, name: "Layout 4" }, - ]; - - const handleSelectLayout = (option: string) => { - setSelectedLayout(option); // Set selected layout - console.log("Selected layout:", option); - }; return (
- {!selectedUser && ( - <> - - {loadingProgress > 0 && } - {!isPlaying && ( - <> - {toggleThreeD && } - - - - )} - - {activeModule === "market" && } - {activeModule !== "market" && !isPlaying && !isVersionSaved && ( - - )} - {isPlaying && activeModule === "simulation" && } - {isPlaying && activeModule !== "simulation" && } - - {/* remove this later */} - {activeModule === "builder" && !toggleThreeD && } - - )} -
- createHandleDrop({ - widgetSubOption, - visualizationSocket, - selectedZone, - setFloatingWidget, - event, - }) - } - onDragOver={(event) => event.preventDefault()} - > - -
+ + {selectedUser && } {isLogListVisible && ( @@ -170,20 +74,6 @@ const Project: React.FC = () => { )} {activeModule !== "market" && !selectedUser &&
} - {isVersionSaved && activeModule === "simulation" && ( - <> -
- l.productName)} // Pass layout names as options - onSelect={handleSelectLayout} - search={false} - /> -
- - {false && } - - )}
); diff --git a/app/src/store/simulation/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts index b3d3c78..9d9df4b 100644 --- a/app/src/store/simulation/useSimulationStore.ts +++ b/app/src/store/simulation/useSimulationStore.ts @@ -74,23 +74,27 @@ interface SelectedProductState { clearSelectedProduct: () => void; } -export const useSelectedProduct = create()( - immer((set) => ({ - selectedProduct: { productId: '', productName: '' }, - setSelectedProduct: (productId, productName) => { - set((state) => { - state.selectedProduct.productId = productId; - state.selectedProduct.productName = productName; - }); - }, - clearSelectedProduct: () => { - set((state) => { - state.selectedProduct.productId = ''; - state.selectedProduct.productName = ''; - }); - }, - })) -); +export const createSelectedProductStore = () => { + return create()( + immer((set) => ({ + selectedProduct: { productId: '', productName: '' }, + setSelectedProduct: (productId, productName) => { + set((state) => { + state.selectedProduct.productId = productId; + state.selectedProduct.productName = productName; + }); + }, + clearSelectedProduct: () => { + set((state) => { + state.selectedProduct.productId = ''; + state.selectedProduct.productName = ''; + }); + }, + })) + ) +} + +export type SelectedProductType = ReturnType; interface SelectedActionState { selectedAction: { actionId: string | null; actionName: string | null }; @@ -146,4 +150,48 @@ export const useIsRotating = create()( }); }, })) +); + +interface MainProductState { + mainProduct: { productId: string; productName: string } | null; + setMainProduct: (productId: string, productName: string) => void; + clearMainProduct: () => void; +} + +export const useMainProduct = create()( + immer((set) => ({ + mainProduct: null, + setMainProduct: (productId: string, productName: string) => { + set((state) => { + state.mainProduct = { productId, productName }; + }); + }, + clearMainProduct: () => { + set((state) => { + state.mainProduct = null; + }); + }, + })) +); + +interface ComparisonProductState { + comparisonProduct: { productId: string; productName: string } | null; + setComparisonProduct: (productId: string, productName: string) => void; + clearComparisonProduct: () => void; +} + +export const useComparisonProduct = create()( + immer((set) => ({ + comparisonProduct: null, + setComparisonProduct: (productId: string, productName: string) => { + set((state) => { + state.comparisonProduct = { productId, productName }; + }); + }, + clearComparisonProduct: () => { + set((state) => { + state.comparisonProduct = null; + }); + }, + })) ); \ No newline at end of file diff --git a/app/src/styles/layout/compareLayout.scss b/app/src/styles/layout/compareLayout.scss index e17f227..e7d54c6 100644 --- a/app/src/styles/layout/compareLayout.scss +++ b/app/src/styles/layout/compareLayout.scss @@ -2,585 +2,588 @@ @use "../abstracts/mixins" as *; .initial-selectLayout-wrapper { - position: fixed; - top: 100px; - left: 40px; - z-index: 10; + position: fixed; + top: 100px; + right: 40px; + z-index: 10; - .regularDropdown-container { - background: var(--background-color); - } + .regularDropdown-container { + background: var(--background-color); + } +} + +.selectLayout-wrapper { + position: fixed; + left: 40px; + top: 100px; + z-index: 10; + + .regularDropdown-container { + background: var(--background-color); + } } .compareLayOut-wrapper { - position: fixed; - top: 0; - right: 0; - z-index: 2; - height: 100vh; - background: var(--background-color); - backdrop-filter: blur(20px); - display: flex; - justify-content: center; - align-items: center; - animation: slideInFromRight 0.4s ease-out forwards; - user-select: none; - - .selectLayout-wrapper { - position: absolute; - top: 100px; - right: 40px; - - .regularDropdown-container { - background: var(--background-color); - } - } - - .resizer { - width: 32px; - height: 32px; - @include flex-center; - padding: 6px; - position: absolute; - top: 50%; - left: 0; - transform: translate(-50%, -50%); + position: fixed; + top: 0; + right: 0; + z-index: 2; + height: 100vh; background: var(--background-color); backdrop-filter: blur(20px); - box-shadow: $box-shadow-heavy; - border-radius: 50%; - cursor: ew-resize; - transition: transform 0.1s ease; - z-index: 10; - } - - .chooseLayout-container { - width: 100%; - height: 100%; display: flex; justify-content: center; align-items: center; - position: relative; - overflow: hidden; + animation: slideInFromRight 0.4s ease-out forwards; + user-select: none; - .compare-layout-canvas-container { - position: absolute; - height: 100vh; - width: 100vw; - top: 0; - right: 0; - } - - .chooseLayout-wrapper { - background: var(--background-color); - backdrop-filter: blur(20px); - padding: 20px; - border-radius: 8px; - box-shadow: $box-shadow-medium; - max-width: 80%; - text-align: center; - position: relative; - - .icon { - width: 100%; - margin-bottom: 15px; - text-align: center; - - svg { - width: 100%; - } - } - - .value { - margin-bottom: 15px; - font-size: var(--font-size-small); - font-weight: 500; - color: var(--text-primary); - } - - button { - display: block; - margin: 0 auto; - padding: 8px 16px; - background: var(--background-color-button); - color: var(--icon-default-color-active); - border: none; - border-radius: 4px; - cursor: pointer; - transition: all 0.2s ease; - - &:hover { - transform: translateY(-1px); - } - } - - .displayLayouts-container { - max-width: 170px; - height: auto; + .resizer { + width: 32px; + height: 32px; + @include flex-center; + padding: 6px; + position: absolute; + top: 50%; + left: 0; + transform: translate(-50%, -50%); background: var(--background-color); backdrop-filter: blur(20px); - padding: 6px; - border-radius: 8px; - box-shadow: $box-shadow-medium; - position: absolute; - right: 0; - top: 100%; - transform: translate(50%, -10px); - display: flex; - flex-direction: column; - gap: 6px; - - .header { - text-align: left; - padding-top: 6px; - padding-left: 6px; - } - - .search-wrapper { - padding: 6px 0; - - .search-container { - padding: 0; - border-radius: 6px; - } - } - - .layouts-container { - .layout { - padding: 6px 0; - } - - .layout-wrapper { - display: flex; - align-items: center; - gap: 6px; - cursor: pointer; - padding: 0 10px; - background: none; - width: 100%; - - &:hover { - background-color: var(--highlight-text-color) !important; - border-radius: 4px; - - .layout { - color: var(--text-button-color) !important; - } - - svg { - path { - fill: var(--text-button-color) !important; - } - } - } - } - } - } + box-shadow: $box-shadow-heavy; + border-radius: 50%; + cursor: ew-resize; + transition: transform 0.1s ease; + z-index: 10; + } + + .chooseLayout-container { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + position: relative; + overflow: hidden; + + .compare-layout-canvas-container { + position: absolute; + height: 100vh; + width: 100vw; + top: 0; + right: 0; + } + + .chooseLayout-wrapper { + background: var(--background-color); + backdrop-filter: blur(20px); + padding: 20px; + border-radius: 8px; + box-shadow: $box-shadow-medium; + max-width: 80%; + text-align: center; + position: relative; + + .icon { + width: 100%; + margin-bottom: 15px; + text-align: center; + + svg { + width: 100%; + } + } + + .value { + margin-bottom: 15px; + font-size: var(--font-size-small); + font-weight: 500; + color: var(--text-primary); + } + + button { + display: block; + margin: 0 auto; + padding: 8px 16px; + background: var(--background-color-button); + color: var(--icon-default-color-active); + border: none; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + transform: translateY(-1px); + } + } + + .displayLayouts-container { + max-width: 170px; + height: auto; + background: var(--background-color); + backdrop-filter: blur(20px); + padding: 6px; + border-radius: 8px; + box-shadow: $box-shadow-medium; + position: absolute; + right: 0; + top: 100%; + transform: translate(50%, -10px); + display: flex; + flex-direction: column; + gap: 6px; + + .header { + text-align: left; + padding-top: 6px; + padding-left: 6px; + } + + .search-wrapper { + padding: 6px 0; + + .search-container { + padding: 0; + border-radius: 6px; + } + } + + .layouts-container { + .layout { + padding: 6px 0; + } + + .layout-wrapper { + display: flex; + align-items: center; + gap: 6px; + cursor: pointer; + padding: 0 10px; + background: none; + width: 100%; + + &:hover { + background-color: var( + --highlight-text-color + ) !important; + border-radius: 4px; + + .layout { + color: var(--text-button-color) !important; + } + + svg { + path { + fill: var(--text-button-color) !important; + } + } + } + } + } + } + } } - } } .compare-result-container { - display: flex; - flex-direction: column; - gap: 6px; - position: fixed; - bottom: 40px; - width: 100%; - min-height: 200px; - z-index: 10; - background: var(--background-color-secondary); - backdrop-filter: blur(20px); - padding: 18px 8px; - - .header { - width: fit-content; - background-color: var(--background-color-solid); - color: var(--background-color-accent); - padding: 6px 10px; - border-radius: 6px; - } - - .compare-result-wrapper { display: flex; - gap: 12px; + flex-direction: column; + gap: 6px; + position: fixed; + bottom: 40px; + width: 100%; + min-height: 200px; + z-index: 10; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + padding: 18px 8px; - .comparisionCard { - position: relative; - flex: 1; - width: auto; - max-height: 200px; - background: var(--background-color); - outline: 1px solid var(--border-color); - outline-offset: -1px; - border-radius: 12px; - padding: 8px 12px; - overflow: hidden; + .header { + width: fit-content; + background-color: var(--background-color-solid); + color: var(--background-color-accent); + padding: 6px 10px; + border-radius: 6px; } - .performanceResult-wrapper { - min-width: 328px; - flex: 0; - position: relative; - padding-right: 65px; - - .header { + .compare-result-wrapper { display: flex; gap: 12px; - align-items: center; - } - .metrics-container { - display: flex; - gap: 12px; - height: 100%; + .comparisionCard { + position: relative; + flex: 1; + width: auto; + max-height: 200px; + background: var(--background-color); + outline: 1px solid var(--border-color); + outline-offset: -1px; + border-radius: 12px; + padding: 8px 12px; + overflow: hidden; + } - .metrics-left { - display: flex; - flex-direction: column; - justify-content: space-around; - height: 100%; + .performanceResult-wrapper { + min-width: 328px; + flex: 0; + position: relative; + padding-right: 65px; - .metric { - .metric-label { - display: flex; - align-items: center; - gap: 6px; - - span { + .header { display: flex; - } + gap: 12px; + align-items: center; } - .metric-value { - padding-top: 6px; - font-size: var(--font-size-xlarge); - color: var(--background-color-accent); - font-weight: 600; + + .metrics-container { + display: flex; + gap: 12px; + height: 100%; + + .metrics-left { + display: flex; + flex-direction: column; + justify-content: space-around; + height: 100%; + + .metric { + .metric-label { + display: flex; + align-items: center; + gap: 6px; + + span { + display: flex; + } + } + .metric-value { + padding-top: 6px; + font-size: var(--font-size-xlarge); + color: var(--background-color-accent); + font-weight: 600; + } + } + + .label { + padding-bottom: 68px; + } + } + + .metrics-right { + height: fit-content; + display: grid; + grid-template-columns: repeat(2, 1fr); + grid-template-rows: repeat(2, 1fr); + + gap: 2px; + overflow: visible; + + margin: auto 0; + + .metric-wrapper { + position: relative; + width: 64px; + height: 50px; + overflow: visible; // allow content like labels to overflow + + &:nth-child(1) { + .metric-label { + top: -57%; + left: 220%; + } + &::after { + content: ""; + position: absolute; + + top: -100%; + left: 50%; + width: 100%; // Required for visible shape + height: 40px; + background-color: #b7b7c6; + + // Custom polygon shape (adjust if needed) + clip-path: polygon( + 96% 52%, + 96% 54%, + 45% 53%, + 3% 100%, + 0 100%, + 42% 52% + ); + + z-index: 0; // Behind any inner content + } + } + + // Optional: content above the shape + > * { + position: relative; + z-index: 1; + } + + &:nth-child(2) { + grid-column-start: 1; + grid-row-start: 2; + .metric-label { + white-space: normal; + width: 50px; + left: 230%; + } + } + &:nth-child(3) { + grid-row: span 2 / span 2; + grid-column-start: 2; + grid-row-start: 1; + margin-top: 40%; + left: -16px; + position: relative; + } + } + + .metric-label { + position: absolute; + top: 0px; + left: 0%; + white-space: nowrap; + + transform: translate(-50%, -50%); + + font-size: 10px; + z-index: 1; + } + + .metric { + width: 100%; + height: 100%; + position: relative; + display: flex; + justify-content: center; + align-items: center; + + &::after { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + + background: var(--background-color, wheat); + clip-path: polygon( + 25% 0%, + 75% 0%, + 100% 50%, + 75% 100%, + 25% 100%, + 0% 50% + ); + filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25)); + + z-index: 0; + } + + // Content stays above the shape + > * { + position: relative; + z-index: 1; + } + } + } } - } - .label { - padding-bottom: 68px; - } - } + .simulation-tag { + background: var(--background-color-button); - .metrics-right { - height: fit-content; - display: grid; - grid-template-columns: repeat(2, 1fr); - grid-template-rows: repeat(2, 1fr); - - gap: 2px; - overflow: visible; - - margin: auto 0; - - .metric-wrapper { - position: relative; - width: 64px; - height: 50px; - overflow: visible; // allow content like labels to overflow - - &:nth-child(1) { - .metric-label { - top: -57%; - left: 220%; - } - &::after { - content: ""; + color: var(--icon-default-color-active); position: absolute; - - top: -100%; - left: 50%; - width: 100%; // Required for visible shape - height: 40px; - background-color: #b7b7c6; - - // Custom polygon shape (adjust if needed) - clip-path: polygon( - 96% 52%, - 96% 54%, - 45% 53%, - 3% 100%, - 0 100%, - 42% 52% - ); - - z-index: 0; // Behind any inner content - } + bottom: 0; + right: 0; + padding: 10px 5px; + border-radius: 12px 0 0 0; } - - // Optional: content above the shape - > * { - position: relative; - z-index: 1; - } - - &:nth-child(2) { - grid-column-start: 1; - grid-row-start: 2; - .metric-label { - white-space: normal; - width: 50px; - left: 230%; - } - } - &:nth-child(3) { - grid-row: span 2 / span 2; - grid-column-start: 2; - grid-row-start: 1; - margin-top: 40%; - left: -16px; - position: relative; - } - } - - .metric-label { - position: absolute; - top: 0px; - left: 0%; - white-space: nowrap; - - transform: translate(-50%, -50%); - - font-size: 10px; - z-index: 1; - } - - .metric { - width: 100%; - height: 100%; - position: relative; - display: flex; - justify-content: center; - align-items: center; - - &::after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - - background: var(--background-color, wheat); - clip-path: polygon( - 25% 0%, - 75% 0%, - 100% 50%, - 75% 100%, - 25% 100%, - 0% 50% - ); - filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25)); - - z-index: 0; - } - - // Content stays above the shape - > * { - position: relative; - z-index: 1; - } - } } - } - - .simulation-tag { - background: var(--background-color-button); - - color: var(--icon-default-color-active); - position: absolute; - bottom: 0; - right: 0; - padding: 10px 5px; - border-radius: 12px 0 0 0; - } } - } } @keyframes slideInFromRight { - from { - transform: translateX(100%); - opacity: 0; - } + from { + transform: translateX(100%); + opacity: 0; + } - to { - transform: translateX(0); - opacity: 1; - } + to { + transform: translateX(0); + opacity: 1; + } } .energy-usage { - position: relative; + position: relative; - .energy-usage-wrapper { - h4 { - font-weight: 600; + .energy-usage-wrapper { + h4 { + font-weight: 600; + } + + .value { + padding-top: 25px; + font-size: var(--font-size-xxxlarge); + color: var(--background-color-accent); + } } - .value { - padding-top: 25px; - font-size: var(--font-size-xxxlarge); - color: var(--background-color-accent); + .simulation-details { + position: absolute; + bottom: 12px; + right: 12px; + + .simulation-wrapper { + display: flex; + align-items: center; + gap: 6px; + + .icon { + width: 20px; + height: 20px; + border-radius: 50%; + background-color: var(--background-color-accent); + } + } } - } - .simulation-details { - position: absolute; - bottom: 12px; - right: 12px; - - .simulation-wrapper { - display: flex; - align-items: center; - gap: 6px; - - .icon { - width: 20px; - height: 20px; - border-radius: 50%; - background-color: var(--background-color-accent); - } + .chart { + width: 90%; + position: absolute; + top: 10px; + left: 0; } - } - - .chart { - width: 90%; - position: absolute; - top: 10px; - left: 0; - } } .throughPutCard-container { - .layers-wrapper { - padding: 20px 10px; - height: 100%; - width: 100%; - display: flex; - justify-content: space-between; + .layers-wrapper { + padding: 20px 10px; + height: 100%; + width: 100%; + display: flex; + justify-content: space-between; - .layer-wrapper { - display: flex; - flex-direction: column; + .layer-wrapper { + display: flex; + flex-direction: column; - &:last-child { - justify-content: end; - } + &:last-child { + justify-content: end; + } + } } - } - .chart { - height: 90%; - position: absolute; - bottom: 0; - left: 0; - } + .chart { + height: 90%; + position: absolute; + bottom: 0; + left: 0; + } } .cycle-time-container { - .cycle-main { - display: flex; - justify-content: space-between; - height: 100%; - - .layers-wrapper { - height: 100%; - display: flex; - flex-direction: column; - justify-content: space-between; - - .layers { + .cycle-main { display: flex; - flex-direction: column; - gap: 4px; + justify-content: space-between; + height: 100%; - .layer-name { - color: var(--background-color-accent); + .layers-wrapper { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + + .layers { + display: flex; + flex-direction: column; + gap: 4px; + + .layer-name { + color: var(--background-color-accent); + } + + .layer-time { + font-size: var(--font-size-large); + } + + .layer-profit { + color: #14ca44; + text-align: end; + + span { + color: #14ca44; + } + } + } } - - .layer-time { - font-size: var(--font-size-large); - } - - .layer-profit { - color: #14ca44; - text-align: end; - - span { - color: #14ca44; - } - } - } } - } } .overallDowntime-container { - .totalDownTime-wrapper { - display: flex; - - .totalDownTime { - width: 70%; - background: var(--background-color-secondary); - backdrop-filter: blur(20px); - border-radius: 12px; - - display: flex; - justify-content: space-between; - align-items: center; - gap: 20px; - padding: 8px 10px; - margin: 44px 0; - - .totalDownTime-right { + .totalDownTime-wrapper { display: flex; - flex-direction: column; - gap: 6px; - } - .totalDownTime-left { - display: flex; - align-items: center; - gap: 6px; + .totalDownTime { + width: 70%; + background: var(--background-color-secondary); + backdrop-filter: blur(20px); + border-radius: 12px; - .value { - font-size: var(--font-size-xlarge); - color: var(--background-color-button); + display: flex; + justify-content: space-between; + align-items: center; + gap: 20px; + padding: 8px 10px; + margin: 44px 0; + + .totalDownTime-right { + display: flex; + flex-direction: column; + gap: 6px; + } + + .totalDownTime-left { + display: flex; + align-items: center; + gap: 6px; + + .value { + font-size: var(--font-size-xlarge); + color: var(--background-color-button); + } + } } - } - } - .chart { - width: 30%; - position: relative; + .chart { + width: 30%; + position: relative; + } } - } } .overallScrapRate { - .overallScrapRate-wrapper { - display: flex; + .overallScrapRate-wrapper { + display: flex; - .overallScrapRate-value { - width: 50%; - display: flex; - flex-direction: column; - gap: 6px; - margin: 40px 0; + .overallScrapRate-value { + width: 50%; + display: flex; + flex-direction: column; + gap: 6px; + margin: 40px 0; - .overallScrapRate-key { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } + .overallScrapRate-key { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + .chart { + width: 50%; + position: relative; + } } - - .chart { - width: 50%; - position: relative; - } - } }