From 6363d5b9af9038b33b5501f8510ebeb25f388422 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 22 Apr 2025 14:28:29 +0530 Subject: [PATCH] feat: Implement Zustand stores for machine, simulation, storage unit, vehicle, and visualization management - Added `useMachineStore` for managing machine statuses, including actions for adding, removing, and updating machines. - Introduced `useSimulationStore` to handle product and event management with actions for adding, removing, and updating products and events. - Created `useStorageUnitStore` for managing storage unit statuses, including load tracking and state updates. - Developed `useVehicleStore` for vehicle management, including load and state updates. - Implemented `useChartStore` for managing measurement data and visualization settings. - Added `useDroppedObjectsStore` for handling dropped objects in visualization zones, including object manipulation actions. - Created `useZone3DWidgetStore` for managing 3D widget data in zones, including position and rotation updates. - Introduced `useZoneStore` for managing selected zone states and widget configurations. --- .../components/layout/sidebarLeft/Assets.tsx | 5 +- .../properties/ZoneProperties.tsx | 2 +- .../IotInputCards/BarChartInput.tsx | 4 +- .../FleetEfficiencyInputComponent.tsx | 4 +- .../IotInputCards/FlotingWidgetInput.tsx | 4 +- .../IotInputCards/LineGrapInput.tsx | 4 +- .../IotInputCards/PieChartInput.tsx | 4 +- .../IotInputCards/Progress1Input.tsx | 4 +- .../IotInputCards/Progress2Input.tsx | 4 +- .../WarehouseThroughputInputComponent.tsx | 4 +- .../IotInputCards/Widget2InputCard3D.tsx | 4 +- .../IotInputCards/Widget3InputCard3D.tsx | 4 +- .../IotInputCards/Widget4InputCard3D.tsx | 4 +- app/src/components/ui/Tools.tsx | 4 +- app/src/components/ui/list/DropDownList.tsx | 2 +- app/src/components/ui/list/List.tsx | 2 +- .../components/ui/menu/EditWidgetOption.tsx | 2 +- app/src/modules/builder/builder.tsx | 3 + .../geomentries/assets/addAssetModel.ts | 61 ++++++- .../builder/groups/floorItemsGroup.tsx | 19 +- .../events/points/pointsCalculator.ts | 47 +++++ app/src/modules/simulation/simulation.tsx | 23 ++- .../simulation/{events/points => ui}/temp.md | 0 .../instances/animator/vehicleAnimator.tsx | 9 + .../instances/instance/vehicleInstance.tsx | 14 ++ .../vehicle/instances/vehicleInstances.tsx | 14 ++ .../simulation/vehicle/navMesh/navMesh.tsx | 31 ++++ .../vehicle/navMesh/navMeshDetails.tsx | 64 +++++++ .../vehicle/navMesh/polygonGenerator.tsx | 119 ++++++++++++ .../modules/simulation/vehicle/vehicle.tsx | 14 ++ .../visualization/RealTimeVisulization.tsx | 6 +- .../socket/realTimeVizSocket.dev.tsx | 6 +- .../visualization/template/Templates.tsx | 4 +- .../widgets/2d/DraggableWidget.tsx | 2 +- .../widgets/2d/charts/BarGraphComponent.tsx | 2 +- .../2d/charts/DoughnutGraphComponent.tsx | 2 +- .../widgets/2d/charts/LineGraphComponent.tsx | 2 +- .../widgets/2d/charts/PieGraphComponent.tsx | 2 +- .../2d/charts/PolarAreaGraphComponent.tsx | 2 +- .../widgets/2d/charts/ProgressCard1.tsx | 2 +- .../widgets/2d/charts/ProgressCard2.tsx | 2 +- .../widgets/3d/Dropped3dWidget.tsx | 8 +- .../widgets/3d/cards/ProductionCapacity.tsx | 2 +- .../widgets/3d/cards/ReturnOfInvestment.tsx | 2 +- .../widgets/3d/cards/StateWorking.tsx | 2 +- .../widgets/3d/cards/Throughput.tsx | 2 +- .../floating/DroppedFloatingWidgets.tsx | 4 +- .../cards/FleetEfficiencyComponent.tsx | 2 +- .../floating/cards/TotalCardComponent.tsx | 2 +- .../cards/WarehouseThroughputComponent.tsx | 2 +- .../visualization/zone/DisplayZone.tsx | 2 +- .../visualization/zone/zoneCameraTarget.tsx | 2 +- app/src/store/simulation/useArmBotStore.ts | 172 ++++++++++++++++++ app/src/store/simulation/useConveyorStore.ts | 129 +++++++++++++ .../store/{ => simulation}/useEventsStore.ts | 54 ++---- app/src/store/simulation/useMachineStore.ts | 129 +++++++++++++ .../{ => simulation}/useSimulationStore.ts | 34 ++-- .../store/simulation/useStorageUnitStore.ts | 158 ++++++++++++++++ app/src/store/simulation/useVehicleStore.ts | 149 +++++++++++++++ app/src/store/store.ts | 7 +- .../{ => visualization}/useChartStore.ts | 0 .../useDroppedObjectsStore.ts | 4 +- .../useZone3DWidgetStore.ts | 0 .../store/{ => visualization}/useZoneStore.ts | 106 +++++------ app/src/types/simulationTypes.d.ts | 17 +- 65 files changed, 1306 insertions(+), 194 deletions(-) create mode 100644 app/src/modules/simulation/events/points/pointsCalculator.ts rename app/src/modules/simulation/{events/points => ui}/temp.md (100%) create mode 100644 app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx create mode 100644 app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx create mode 100644 app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx create mode 100644 app/src/modules/simulation/vehicle/navMesh/navMesh.tsx create mode 100644 app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx create mode 100644 app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx create mode 100644 app/src/modules/simulation/vehicle/vehicle.tsx create mode 100644 app/src/store/simulation/useArmBotStore.ts create mode 100644 app/src/store/simulation/useConveyorStore.ts rename app/src/store/{ => simulation}/useEventsStore.ts (88%) create mode 100644 app/src/store/simulation/useMachineStore.ts rename app/src/store/{ => simulation}/useSimulationStore.ts (91%) create mode 100644 app/src/store/simulation/useStorageUnitStore.ts create mode 100644 app/src/store/simulation/useVehicleStore.ts rename app/src/store/{ => visualization}/useChartStore.ts (100%) rename app/src/store/{ => visualization}/useDroppedObjectsStore.ts (97%) rename app/src/store/{ => visualization}/useZone3DWidgetStore.ts (100%) rename app/src/store/{ => visualization}/useZoneStore.ts (95%) diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index 5477790..17a4df3 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -192,12 +192,13 @@ const Assets: React.FC = () => { src={asset?.thumbnail} alt={asset.filename} className="asset-image" - onPointerDown={() => + onPointerDown={() => { setSelectedItem({ name: asset.filename, id: asset.AssetID, + type: asset.type === "undefined" ? undefined : asset.type }) - } + }} />
diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index 9cd9a7c..a9f8cc0 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import RenameInput from "../../../ui/inputs/RenameInput"; import Vector3Input from "../customInput/Vector3Input"; -import { useSelectedZoneStore } from "../../../../store/useZoneStore"; +import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore"; import { useEditPosition, usezonePosition, useZones, usezoneTarget } from "../../../../store/store"; import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCameraUpdation"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx index 9fb7b78..a729a9e 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx index 78b82c8..9c6c831 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx index 271b4fc..0165257 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx index 50330d1..cb51491 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx @@ -121,8 +121,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx index e7486f2..9dff7d6 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx index 797f63a..ed84458 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx index a7d2934..c97a380 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx index 764be54..d48f2ee 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx index 345de09..62edae4 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx index c41447a..7481622 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx index 20369bd..f8cdef6 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx @@ -2,8 +2,8 @@ import React, { useEffect, useState } from "react"; import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; import { AddIcon } from "../../../../icons/ExportCommonIcons"; import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; -import useChartStore from "../../../../../store/useChartStore"; -import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/visualization/useZoneStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import RenameInput from "../../../../ui/inputs/RenameInput"; diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index cf5bb17..70b1461 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -18,7 +18,7 @@ import useModuleStore, { useThreeDStore } from "../../store/useModuleStore"; import { handleSaveTemplate } from "../../modules//visualization/functions/handleSaveTemplate"; import { usePlayButtonStore } from "../../store/usePlayButtonStore"; import useTemplateStore from "../../store/useTemplateStore"; -import { useSelectedZoneStore } from "../../store/useZoneStore"; +import { useSelectedZoneStore } from "../../store/visualization/useZoneStore"; import { useActiveTool, useAddAction, @@ -38,7 +38,7 @@ import { use3DWidget, useDroppedObjectsStore, useFloatingWidget, -} from "../../store/useDroppedObjectsStore"; +} from "../../store/visualization/useDroppedObjectsStore"; const Tools: React.FC = () => { const { templates } = useTemplateStore(); diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index f29475e..0416a9e 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -3,7 +3,7 @@ import List from "./List"; import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons"; import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect"; import { useFloorItems, useZones } from "../../../store/store"; -import { useSelectedZoneStore } from "../../../store/useZoneStore"; +import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; interface DropDownListProps { value?: string; // Value to display in the DropDownList diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index efcf328..cac0b43 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import RenameInput from "../inputs/RenameInput"; -import { useSelectedZoneStore } from "../../../store/useZoneStore"; +import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; import { getZoneData } from "../../../services/visulization/zone/getZones"; import useModuleStore, { useSubModuleStore, diff --git a/app/src/components/ui/menu/EditWidgetOption.tsx b/app/src/components/ui/menu/EditWidgetOption.tsx index 1c1fa2e..6fd1e94 100644 --- a/app/src/components/ui/menu/EditWidgetOption.tsx +++ b/app/src/components/ui/menu/EditWidgetOption.tsx @@ -5,7 +5,7 @@ import { useRightClickSelected, useRightSelected, useTopData, -} from "../../../store/useZone3DWidgetStore"; +} from "../../../store/visualization/useZone3DWidgetStore"; interface EditWidgetOptionProps { options: string[]; diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index d924d9d..e7f83e2 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -55,6 +55,7 @@ import DrieHtmlTemp from "..//visualization/mqttTemp/drieHtmlTemp"; import ZoneGroup from "./groups/zoneGroup"; import useModuleStore from "../../store/useModuleStore"; import MeasurementTool from "../scene/tools/measurementTool"; +import NavMesh from "../simulation/vehicle/navMesh/navMesh"; export default function Builder() { const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. @@ -347,6 +348,8 @@ export default function Builder() { + + ); } diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index 5a42404..5837958 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -10,6 +10,7 @@ import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils'; import { Socket } from 'socket.io-client'; import * as CONSTANTS from '../../../../types/world/worldConstants'; import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; +import PointsCalculator from '../../../simulation/events/points/pointsCalculator'; async function addAssetModel( raycaster: THREE.Raycaster, @@ -23,6 +24,7 @@ async function addAssetModel( socket: Socket, selectedItem: any, setSelectedItem: any, + addEvent: (event: EventsSchema) => void, plane: Types.RefMesh, ): Promise { @@ -63,7 +65,7 @@ async function addAssetModel( const cachedModel = THREE.Cache.get(selectedItem.id); if (cachedModel) { // console.log(`[Cache] Fetching ${selectedItem.name}`); - handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket); + handleModelLoad(cachedModel, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, addEvent, socket); return; } else { const cachedModelBlob = await retrieveGLTF(selectedItem.id); @@ -76,7 +78,7 @@ async function addAssetModel( URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); THREE.Cache.add(selectedItem.id, gltf); - handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket); + handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, addEvent, socket); }, () => { TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); @@ -88,7 +90,7 @@ async function addAssetModel( const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`).then((res) => res.blob()); await storeGLTF(selectedItem.id, modelBlob); THREE.Cache.add(selectedItem.id, gltf); - await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, socket); + await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, addEvent, socket); }, () => { TempLoader(intersectPoint!, isTempLoader, tempLoader, itemsGroup); @@ -111,6 +113,7 @@ async function handleModelLoad( tempLoader: Types.RefMesh, isTempLoader: Types.RefBoolean, setFloorItems: Types.setFloorItemSetState, + addEvent: (event: EventsSchema) => void, socket: Socket ) { const model = gltf.scene.clone(); @@ -173,6 +176,58 @@ async function handleModelLoad( socketId: socket.id }; + if (selectedItem.type) { + const data = PointsCalculator( + selectedItem.type, + gltf.scene.clone(), + new THREE.Vector3(...model.rotation) + ); + + if (!data || !data.points) return; + console.log('data: ', data); + + const createMarker = (point: THREE.Vector3) => { + const sphere = new THREE.SphereGeometry(0.1, 15); + const material = new THREE.MeshStandardMaterial(); + const mesh = new THREE.Mesh(sphere, material); + mesh.position.copy(point); + return mesh; + }; + + if (data.points && data.points.length > 0) { + data.points.forEach((Point) => { + model.add(createMarker(Point)); + }); + } + + if (selectedItem.type === "Conveyor") { + const event: ConveyorEventSchema = { + modelUuid: newFloorItem.modeluuid, + modelName: newFloorItem.modelname, + position: newFloorItem.position, + rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], + state: "idle", + type: 'transfer', + speed: 1, + points: data.points.map((point: THREE.Vector3, index: number) => ({ + uuid: THREE.MathUtils.generateUUID(), + position: [point.x, point.y, point.z], + rotation: [0, 0, 0], + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: `Action ${index}`, + actionType: 'default', + material: 'inherit', + delay: 0, + spawnInterval: 5, + spawnCount: 1, + triggers: [] + } + })) + } + addEvent(event); + } + } setFloorItems((prevItems) => { const updatedItems = [...(prevItems || []), newFloorItem]; diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 99d3291..23fa80d 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -19,6 +19,8 @@ import useModuleStore from "../../../store/useModuleStore"; const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url)); const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); +import { useEventsStore } from "../../../store/simulation/useEventsStore"; + const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => { const state: Types.ThreeState = useThree(); const { raycaster, controls }: any = state; @@ -37,6 +39,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject const { socket } = useSocketStore(); const loader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); + const { addEvent } = useEventsStore(); dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"); loader.setDRACOLoader(dracoLoader); @@ -275,7 +278,7 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject if (!event.dataTransfer?.files[0]) return; if (selectedItem.id !== "" && event.dataTransfer?.files[0]) { - addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, plane); + addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, addEvent, plane); } }; @@ -311,14 +314,14 @@ const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject useFrame(() => { if (controls) // assetVisibility(itemsGroup, state.camera.position, renderDistance); - if (deleteTool && activeModule === "builder") { - DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem); - } else if (!deleteTool) { - if (hoveredDeletableFloorItem.current) { - hoveredDeletableFloorItem.current = undefined; - setDeletableFloorItem(null); + if (deleteTool && activeModule === "builder") { + DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem); + } else if (!deleteTool) { + if (hoveredDeletableFloorItem.current) { + hoveredDeletableFloorItem.current = undefined; + setDeletableFloorItem(null); + } } - } }); return ; diff --git a/app/src/modules/simulation/events/points/pointsCalculator.ts b/app/src/modules/simulation/events/points/pointsCalculator.ts new file mode 100644 index 0000000..86d368e --- /dev/null +++ b/app/src/modules/simulation/events/points/pointsCalculator.ts @@ -0,0 +1,47 @@ +import * as THREE from 'three'; +import { Group } from '../../../../types/world/worldTypes'; + +function PointsCalculator( + type: string, + model: Group, + rotation: THREE.Vector3 = new THREE.Vector3() +): { points?: THREE.Vector3[] } | null { + if (!model) return null; + + const box = new THREE.Box3().setFromObject(model); + + const size = new THREE.Vector3(); + box.getSize(size); + const center = new THREE.Vector3(); + box.getCenter(center); + + const rotationMatrix = new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(rotation.x, rotation.y, rotation.z)); + + const localTopMiddle = new THREE.Vector3(0, size.y / 2, 0); + const worldTopMiddle = localTopMiddle.clone().applyMatrix4(rotationMatrix).add(center); + + if (type === 'Conveyor') { + const isWidthLonger = size.x > size.z; + const longerSize = isWidthLonger ? size.x : size.z; + const shorterSize = isWidthLonger ? size.z : size.x; + const halfLongerSize = longerSize / 2; + const halfShorterSize = shorterSize / 2; + + const localEndPoint1 = new THREE.Vector3(isWidthLonger ? -halfLongerSize + halfShorterSize : 0, size.y / 2, isWidthLonger ? 0 : -halfLongerSize + halfShorterSize); + + const localEndPoint2 = new THREE.Vector3(isWidthLonger ? halfLongerSize - halfShorterSize : 0, size.y / 2, isWidthLonger ? 0 : halfLongerSize - halfShorterSize); + + const worldEndPoint1 = localEndPoint1.applyMatrix4(rotationMatrix).add(center); + const worldEndPoint2 = localEndPoint2.applyMatrix4(rotationMatrix).add(center); + + return { + points: [worldEndPoint1, worldTopMiddle, worldEndPoint2] + }; + } + + return { + points: [worldTopMiddle] + }; +} + +export default PointsCalculator; diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index bde8106..387bfa8 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -1,10 +1,23 @@ -import React from 'react' +import React, { useEffect } from 'react'; +import { useEventsStore } from '../../store/simulation/useEventsStore'; +import { useProductStore } from '../../store/simulation/useSimulationStore'; function Simulation() { - return ( - <> - - ) + const { events } = useEventsStore(); + const { products } = useProductStore(); + + useEffect(() => { + console.log('events: ', events); + }, [events]) + + useEffect(() => { + console.log('products: ', products); + }, [products]) + + return ( + <> + + ) } export default Simulation \ No newline at end of file diff --git a/app/src/modules/simulation/events/points/temp.md b/app/src/modules/simulation/ui/temp.md similarity index 100% rename from app/src/modules/simulation/events/points/temp.md rename to app/src/modules/simulation/ui/temp.md diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx new file mode 100644 index 0000000..92c1d44 --- /dev/null +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -0,0 +1,9 @@ +import React from 'react' + +function VehicleAnimator() { + return ( +
VehicleAnimator
+ ) +} + +export default VehicleAnimator \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx new file mode 100644 index 0000000..0996b3c --- /dev/null +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import VehicleAnimator from '../animator/vehicleAnimator' + +function VehicleInstance() { + return ( + <> + + + + + ) +} + +export default VehicleInstance \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx new file mode 100644 index 0000000..13e15b7 --- /dev/null +++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import VehicleInstance from './instance/vehicleInstance' + +function VehicleInstances() { + return ( + <> + + + + + ) +} + +export default VehicleInstances \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx b/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx new file mode 100644 index 0000000..8652172 --- /dev/null +++ b/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx @@ -0,0 +1,31 @@ +import { useRef } from "react"; +import { useNavMesh } from "../../../../store/store"; +import PolygonGenerator from "./polygonGenerator"; +import NavMeshDetails from "./navMeshDetails"; +import * as CONSTANTS from "../../../../types/world/worldConstants"; +import * as Types from "../../../../types/world/worldTypes"; + +type NavMeshProps = { + lines: Types.RefLines +}; + +function NavMesh({ lines }: NavMeshProps) { + let groupRef = useRef() as Types.RefGroup; + const { setNavMesh } = useNavMesh(); + + return ( + <> + + + + + + + + + + + ) +} + +export default NavMesh \ No newline at end of file diff --git a/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx b/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx new file mode 100644 index 0000000..aee91e0 --- /dev/null +++ b/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx @@ -0,0 +1,64 @@ +import React, { useEffect } from "react"; +import { init as initRecastNavigation } from "@recast-navigation/core"; +import { generateSoloNavMesh } from "@recast-navigation/generators"; +import { DebugDrawer, getPositionsAndIndices } from "@recast-navigation/three"; +import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; +import * as Types from "../../../../types/world/worldTypes"; + +interface NavMeshDetailsProps { + setNavMesh: (navMesh: any) => void; + groupRef: React.MutableRefObject; + lines: Types.RefLines; +} + +export default function NavMeshDetails({ + lines, + setNavMesh, + groupRef, +}: NavMeshDetailsProps) { + const { scene } = useThree(); + + useEffect(() => { + const initializeNavigation = async () => { + try { + await initRecastNavigation(); + + if (!groupRef.current || groupRef.current.children.length === 0) { + return; + } + + const meshes = groupRef?.current?.children as THREE.Mesh[]; + + const [positions, indices] = getPositionsAndIndices(meshes); + + const cellSize = 0.2; + const cellHeight = 0.7; + const walkableRadius = 0.5; + const { success, navMesh } = generateSoloNavMesh(positions, indices, { + cs: cellSize, + ch: cellHeight, + walkableRadius: Math.round(walkableRadius / cellHeight), + }); + + if (!success || !navMesh) { + return; + } + + setNavMesh(navMesh); + + scene.children + .filter((child) => child instanceof DebugDrawer) + .forEach((child) => scene.remove(child)); + + const debugDrawer = new DebugDrawer(); + debugDrawer.drawNavMesh(navMesh); + // scene.add(debugDrawer); + } catch (error) { } + }; + + initializeNavigation(); + }, [scene, groupRef, lines.current]); + + return null; +} diff --git a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx new file mode 100644 index 0000000..fa0d9dd --- /dev/null +++ b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx @@ -0,0 +1,119 @@ +import * as THREE from "three"; +import { useEffect } from "react"; +import * as turf from "@turf/turf"; +import * as Types from "../../../../types/world/worldTypes"; +import arrayLinesToObject from "../../../builder/geomentries/lines/lineConvertions/arrayLinesToObject"; + +interface PolygonGeneratorProps { + groupRef: React.MutableRefObject; + lines: Types.RefLines; +} + +export default function PolygonGenerator({ + groupRef, + lines, +}: PolygonGeneratorProps) { + + useEffect(() => { + let allLines = arrayLinesToObject(lines.current); + const wallLines = allLines?.filter((line) => line?.type === "WallLine"); + const aisleLines = allLines?.filter((line) => line?.type === "AisleLine"); + + const wallPoints = wallLines + .map((pair) => pair?.line.map((vals) => vals.position)) + .filter((wall): wall is THREE.Vector3[] => !!wall); + + const result = aisleLines.map((pair) => + pair?.line.map((point) => ({ + position: [point.position.x, point.position.z], + uuid: point.uuid, + })) + ); + + if (!result || result.some((line) => !line)) { + return; + } + + const lineFeatures = result?.map((line: any) => + turf.lineString(line.map((p: any) => p?.position)) + ); + + const polygons = turf.polygonize(turf.featureCollection(lineFeatures)); + renderWallGeometry(wallPoints); + + if (polygons.features.length > 1) { + polygons.features.forEach((feature) => { + if (feature.geometry.type === "Polygon") { + + const shape = new THREE.Shape(); + const coords = feature.geometry.coordinates[0]; + + shape.moveTo(coords[0][0], coords[0][1]); + + for (let i = 1; i < coords.length; i++) { + shape.lineTo(coords[i][0], coords[i][1]); + } + shape.lineTo(coords[0][0], coords[0][1]); + + const extrudeSettings = { + depth: 5, + bevelEnabled: false, + }; + + const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings); + + const material = new THREE.MeshBasicMaterial({ color: "blue", transparent: true, opacity: 0.5 }); + const mesh = new THREE.Mesh(geometry, material); + mesh.rotateX(Math.PI / 2); + mesh.name = "agv-collider"; + mesh.position.y = 5; + + mesh.receiveShadow = true; + groupRef.current?.add(mesh); + } + }); + } + + }, [lines.current]); + + const renderWallGeometry = (walls: THREE.Vector3[][]) => { + walls.forEach((wall) => { + if (wall.length < 2) return; + + for (let i = 0; i < wall.length - 1; i++) { + const start = new THREE.Vector3(wall[i].x, wall[i].y, wall[i].z); + const end = new THREE.Vector3( + wall[i + 1].x, + wall[i + 1].y, + wall[i + 1].z + ); + + const wallHeight = 10; + const direction = new THREE.Vector3().subVectors(end, start); + const length = direction.length(); + direction.normalize(); + + const wallGeometry = new THREE.BoxGeometry(length, wallHeight); + const wallMaterial = new THREE.MeshBasicMaterial({ + color: "#aaa", + transparent: true, + opacity: 0.5, + }); + + const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial); + const midPoint = new THREE.Vector3() + .addVectors(start, end) + .multiplyScalar(0.5); + wallMesh.position.set(midPoint.x, wallHeight / 2, midPoint.z); + + const quaternion = new THREE.Quaternion(); + quaternion.setFromUnitVectors(new THREE.Vector3(1, 0, 0), direction); + wallMesh.quaternion.copy(quaternion); + + groupRef.current?.add(wallMesh); + } + }); + }; + + return null; +} diff --git a/app/src/modules/simulation/vehicle/vehicle.tsx b/app/src/modules/simulation/vehicle/vehicle.tsx new file mode 100644 index 0000000..e51effc --- /dev/null +++ b/app/src/modules/simulation/vehicle/vehicle.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import VehicleInstances from './instances/vehicleInstances'; + +function Vehicle() { + return ( + <> + + + + + ) +} + +export default Vehicle \ No newline at end of file diff --git a/app/src/modules/visualization/RealTimeVisulization.tsx b/app/src/modules/visualization/RealTimeVisulization.tsx index e341fcd..cd2c57c 100644 --- a/app/src/modules/visualization/RealTimeVisulization.tsx +++ b/app/src/modules/visualization/RealTimeVisulization.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState, useRef } from "react"; import { usePlayButtonStore } from "../../store/usePlayButtonStore"; import Panel from "./widgets/panel/Panel"; import AddButtons from "./widgets/panel/AddButtons"; -import { useSelectedZoneStore } from "../../store/useZoneStore"; +import { useSelectedZoneStore } from "../../store/visualization/useZoneStore"; import DisplayZone from "./zone/DisplayZone"; import Scene from "../scene/scene"; import useModuleStore from "../../store/useModuleStore"; @@ -10,7 +10,7 @@ import useModuleStore from "../../store/useModuleStore"; import { useDroppedObjectsStore, useFloatingWidget, -} from "../../store/useDroppedObjectsStore"; +} from "../../store/visualization/useDroppedObjectsStore"; import { useAsset3dWidget, useSocketStore, @@ -30,7 +30,7 @@ import { useEditWidgetOptionsStore, useRightClickSelected, useRightSelected, -} from "../../store/useZone3DWidgetStore"; +} from "../../store/visualization/useZone3DWidgetStore"; import OuterClick from "../../utils/outerClick"; import { useWidgetStore } from "../../store/useWidgetStore"; import { getActiveProperties } from "./functions/getActiveProperties"; diff --git a/app/src/modules/visualization/socket/realTimeVizSocket.dev.tsx b/app/src/modules/visualization/socket/realTimeVizSocket.dev.tsx index b5291a3..1dbc175 100644 --- a/app/src/modules/visualization/socket/realTimeVizSocket.dev.tsx +++ b/app/src/modules/visualization/socket/realTimeVizSocket.dev.tsx @@ -1,8 +1,8 @@ import { useEffect } from "react"; import { useSocketStore } from "../../../store/store"; -import { useSelectedZoneStore } from "../../../store/useZoneStore"; -import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; -import { useZoneWidgetStore } from "../../../store/useZone3DWidgetStore"; +import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; +import { useDroppedObjectsStore } from "../../../store/visualization/useDroppedObjectsStore"; +import { useZoneWidgetStore } from "../../../store/visualization/useZone3DWidgetStore"; import useTemplateStore from "../../../store/useTemplateStore"; type WidgetData = { diff --git a/app/src/modules/visualization/template/Templates.tsx b/app/src/modules/visualization/template/Templates.tsx index 59a38ce..e0ece1c 100644 --- a/app/src/modules/visualization/template/Templates.tsx +++ b/app/src/modules/visualization/template/Templates.tsx @@ -1,9 +1,9 @@ import { useEffect } from "react"; import useTemplateStore from "../../../store/useTemplateStore"; -import { useSelectedZoneStore } from "../../../store/useZoneStore"; +import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; import { useSocketStore } from "../../../store/store"; import { getTemplateData } from "../../../services/visulization/zone/getTemplate"; -import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; +import { useDroppedObjectsStore } from "../../../store/visualization/useDroppedObjectsStore"; import RenameInput from "../../../components/ui/inputs/RenameInput"; diff --git a/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx b/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx index ca70d45..0c8fe6f 100644 --- a/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx +++ b/app/src/modules/visualization/widgets/2d/DraggableWidget.tsx @@ -17,7 +17,7 @@ import { useClickOutside } from "../../functions/handleWidgetsOuterClick"; import { useSocketStore } from "../../../../store/store"; import { usePlayButtonStore } from "../../../../store/usePlayButtonStore"; import OuterClick from "../../../../utils/outerClick"; -import useChartStore from "../../../../store/useChartStore"; +import useChartStore from "../../../../store/visualization/useChartStore"; type Side = "top" | "bottom" | "left" | "right"; diff --git a/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx index 4f3cfd9..e68e1d3 100644 --- a/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx +++ b/app/src/modules/visualization/widgets/2d/charts/BarGraphComponent.tsx @@ -192,7 +192,7 @@ import io from "socket.io-client"; import axios from "axios"; import { useThemeStore } from "../../../../../store/useThemeStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; interface ChartComponentProps { id: string; diff --git a/app/src/modules/visualization/widgets/2d/charts/DoughnutGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/DoughnutGraphComponent.tsx index 3108d09..74d3fec 100644 --- a/app/src/modules/visualization/widgets/2d/charts/DoughnutGraphComponent.tsx +++ b/app/src/modules/visualization/widgets/2d/charts/DoughnutGraphComponent.tsx @@ -5,7 +5,7 @@ import io from "socket.io-client"; import axios from "axios"; import { useThemeStore } from "../../../../../store/useThemeStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; interface ChartComponentProps { id: string; diff --git a/app/src/modules/visualization/widgets/2d/charts/LineGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/LineGraphComponent.tsx index 4a6906a..9e5d616 100644 --- a/app/src/modules/visualization/widgets/2d/charts/LineGraphComponent.tsx +++ b/app/src/modules/visualization/widgets/2d/charts/LineGraphComponent.tsx @@ -4,7 +4,7 @@ import io from "socket.io-client"; import axios from "axios"; import { useThemeStore } from "../../../../../store/useThemeStore"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; interface ChartComponentProps { diff --git a/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx index b77e964..931d567 100644 --- a/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx +++ b/app/src/modules/visualization/widgets/2d/charts/PieGraphComponent.tsx @@ -189,7 +189,7 @@ import io from "socket.io-client"; import axios from "axios"; import { useThemeStore } from "../../../../../store/useThemeStore"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; interface ChartComponentProps { diff --git a/app/src/modules/visualization/widgets/2d/charts/PolarAreaGraphComponent.tsx b/app/src/modules/visualization/widgets/2d/charts/PolarAreaGraphComponent.tsx index e4056dc..d5024d6 100644 --- a/app/src/modules/visualization/widgets/2d/charts/PolarAreaGraphComponent.tsx +++ b/app/src/modules/visualization/widgets/2d/charts/PolarAreaGraphComponent.tsx @@ -4,7 +4,7 @@ import io from "socket.io-client"; import axios from "axios"; import { useThemeStore } from "../../../../../store/useThemeStore"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; interface ChartComponentProps { diff --git a/app/src/modules/visualization/widgets/2d/charts/ProgressCard1.tsx b/app/src/modules/visualization/widgets/2d/charts/ProgressCard1.tsx index 70f09a2..5d1f59e 100644 --- a/app/src/modules/visualization/widgets/2d/charts/ProgressCard1.tsx +++ b/app/src/modules/visualization/widgets/2d/charts/ProgressCard1.tsx @@ -3,7 +3,7 @@ import { Line } from "react-chartjs-2"; import io from "socket.io-client"; import axios from "axios"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import { StockIncreseIcon } from "../../../../../components/icons/RealTimeVisulationIcons"; diff --git a/app/src/modules/visualization/widgets/2d/charts/ProgressCard2.tsx b/app/src/modules/visualization/widgets/2d/charts/ProgressCard2.tsx index 67ae415..325445c 100644 --- a/app/src/modules/visualization/widgets/2d/charts/ProgressCard2.tsx +++ b/app/src/modules/visualization/widgets/2d/charts/ProgressCard2.tsx @@ -3,7 +3,7 @@ import { Line } from "react-chartjs-2"; import io from "socket.io-client"; import axios from "axios"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import { StockIncreseIcon } from "../../../../../components/icons/RealTimeVisulationIcons"; diff --git a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx index c094109..d09a88f 100644 --- a/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx +++ b/app/src/modules/visualization/widgets/3d/Dropped3dWidget.tsx @@ -4,9 +4,9 @@ import React, { useEffect, useRef, useState } from "react"; import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../../store/store"; import useModuleStore from "../../../../store/useModuleStore"; import { ThreeState } from "../../../../types/world/worldTypes"; -import { useSelectedZoneStore } from "../../../../store/useZoneStore"; -import { useEditWidgetOptionsStore, useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../../store/useZone3DWidgetStore"; -import { use3DWidget } from "../../../../store/useDroppedObjectsStore"; +import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore"; +import { useEditWidgetOptionsStore, useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../../store/visualization/useZone3DWidgetStore"; +import { use3DWidget } from "../../../../store/visualization/useDroppedObjectsStore"; import { get3dWidgetZoneData } from "../../../../services/visulization/zone/get3dWidgetData"; import { generateUniqueId } from "../../../../functions/generateUniqueId"; import ProductionCapacity from "./cards/ProductionCapacity"; @@ -14,7 +14,7 @@ import ReturnOfInvestment from "./cards/ReturnOfInvestment"; import StateWorking from "./cards/StateWorking"; import Throughput from "./cards/Throughput"; import { useWidgetStore } from "../../../../store/useWidgetStore"; -import useChartStore from "../../../../store/useChartStore"; +import useChartStore from "../../../../store/visualization/useChartStore"; type WidgetData = { id: string; diff --git a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx index 274d6dd..6666452 100644 --- a/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/ProductionCapacity.tsx @@ -15,7 +15,7 @@ import { import axios from "axios"; import io from "socket.io-client"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; // Register ChartJS components ChartJS.register( diff --git a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx index 5a975f1..6aeafa6 100644 --- a/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/ReturnOfInvestment.tsx @@ -16,7 +16,7 @@ import { import axios from "axios"; import io from "socket.io-client"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; import { WavyIcon } from "../../../../../components/icons/3dChartIcons"; // Register Chart.js components diff --git a/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx b/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx index 4d10955..048dd7d 100644 --- a/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/StateWorking.tsx @@ -4,7 +4,7 @@ import React, { useEffect, useMemo, useState } from "react"; import axios from "axios"; import io from "socket.io-client"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; // import image from "../../../../assets/image/temp/image.png"; interface StateWorkingProps { diff --git a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx index 67397bd..857813c 100644 --- a/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx +++ b/app/src/modules/visualization/widgets/3d/cards/Throughput.tsx @@ -18,7 +18,7 @@ import { import axios from "axios"; import io from "socket.io-client"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; import { ThroughputIcon } from "../../../../../components/icons/3dChartIcons"; // Register Chart.js components diff --git a/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx b/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx index 1121e27..b4a328e 100644 --- a/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx +++ b/app/src/modules/visualization/widgets/floating/DroppedFloatingWidgets.tsx @@ -3,7 +3,7 @@ import { useEffect, useRef, useState } from "react"; import { useDroppedObjectsStore, Zones, -} from "../../../../store/useDroppedObjectsStore"; +} from "../../../../store/visualization/useDroppedObjectsStore"; import useModuleStore from "../../../../store/useModuleStore"; import { determinePosition } from "../../functions/determinePosition"; import { getActiveProperties } from "../../functions/getActiveProperties"; @@ -23,7 +23,7 @@ import { useWidgetStore } from "../../../../store/useWidgetStore"; import { useSocketStore } from "../../../../store/store"; import { useClickOutside } from "../../functions/handleWidgetsOuterClick"; import { usePlayButtonStore } from "../../../../store/usePlayButtonStore"; -import { useSelectedZoneStore } from "../../../../store/useZoneStore"; +import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore"; interface DraggingState { zone: string; index: number; diff --git a/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx b/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx index f50bec9..bdaf648 100644 --- a/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx +++ b/app/src/modules/visualization/widgets/floating/cards/FleetEfficiencyComponent.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import { Line } from "react-chartjs-2"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import io from "socket.io-client"; diff --git a/app/src/modules/visualization/widgets/floating/cards/TotalCardComponent.tsx b/app/src/modules/visualization/widgets/floating/cards/TotalCardComponent.tsx index 6e8d692..61096c5 100644 --- a/app/src/modules/visualization/widgets/floating/cards/TotalCardComponent.tsx +++ b/app/src/modules/visualization/widgets/floating/cards/TotalCardComponent.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from "react"; import { Line } from "react-chartjs-2"; -import useChartStore from "../../../../../store/useChartStore"; +import useChartStore from "../../../../../store/visualization/useChartStore"; import { useWidgetStore } from "../../../../../store/useWidgetStore"; import axios from "axios"; import io from "socket.io-client"; diff --git a/app/src/modules/visualization/widgets/floating/cards/WarehouseThroughputComponent.tsx b/app/src/modules/visualization/widgets/floating/cards/WarehouseThroughputComponent.tsx index 012c2e7..67793f9 100644 --- a/app/src/modules/visualization/widgets/floating/cards/WarehouseThroughputComponent.tsx +++ b/app/src/modules/visualization/widgets/floating/cards/WarehouseThroughputComponent.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect } from 'react' import { Line } from 'react-chartjs-2' -import useChartStore from '../../../../../store/useChartStore'; +import useChartStore from '../../../../../store/visualization/useChartStore'; import { useWidgetStore } from '../../../../../store/useWidgetStore'; import axios from 'axios'; import io from "socket.io-client"; diff --git a/app/src/modules/visualization/zone/DisplayZone.tsx b/app/src/modules/visualization/zone/DisplayZone.tsx index 66fdba2..578bdab 100644 --- a/app/src/modules/visualization/zone/DisplayZone.tsx +++ b/app/src/modules/visualization/zone/DisplayZone.tsx @@ -4,7 +4,7 @@ import { useWidgetStore, Widget } from "../../../store/useWidgetStore"; import { useDroppedObjectsStore, useFloatingWidget, -} from "../../../store/useDroppedObjectsStore"; +} from "../../../store/visualization/useDroppedObjectsStore"; import { getSelect2dZoneData } from "../../../services/visulization/zone/getSelect2dZoneData"; import { getFloatingZoneData } from "../../../services/visulization/zone/getFloatingData"; import { get3dWidgetZoneData } from "../../../services/visulization/zone/get3dWidgetData"; diff --git a/app/src/modules/visualization/zone/zoneCameraTarget.tsx b/app/src/modules/visualization/zone/zoneCameraTarget.tsx index f022b32..d1587de 100644 --- a/app/src/modules/visualization/zone/zoneCameraTarget.tsx +++ b/app/src/modules/visualization/zone/zoneCameraTarget.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import * as THREE from "three"; -import { useSelectedZoneStore } from "../../../store/useZoneStore"; +import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; import { useEditPosition, usezonePosition, usezoneTarget } from "../../../store/store"; export default function ZoneCentreTarget() { diff --git a/app/src/store/simulation/useArmBotStore.ts b/app/src/store/simulation/useArmBotStore.ts new file mode 100644 index 0000000..4733161 --- /dev/null +++ b/app/src/store/simulation/useArmBotStore.ts @@ -0,0 +1,172 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface ArmBotStatus extends RoboticArmSchemaEvent { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; + currentAction?: { + actionUuid: string; + actionName: string; + }; +} + +interface ArmBotStore { + armBots: Record; + + // ArmBot actions + addArmBot: (productId: string, event: RoboticArmSchemaEvent) => void; + removeArmBot: (modelUuid: string) => void; + updateArmBot: ( + modelUuid: string, + updates: Partial> + ) => void; + + // Action management + startAction: (modelUuid: string, actionUuid: string) => void; + completeAction: (modelUuid: string) => void; + cancelAction: (modelUuid: string) => void; + + // Status updates + setArmBotActive: (modelUuid: string, isActive: boolean) => void; + + // Time tracking + incrementActiveTime: (modelUuid: string, incrementBy: number) => void; + incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + + // Helper functions + getArmBotById: (modelUuid: string) => ArmBotStatus | undefined; + getArmBotsByProduct: (productId: string) => ArmBotStatus[]; + getActiveArmBots: () => ArmBotStatus[]; + getIdleArmBots: () => ArmBotStatus[]; + getArmBotsByCurrentAction: (actionUuid: string) => ArmBotStatus[]; +} + +export const useArmBotStore = create()( + immer((set, get) => ({ + armBots: {}, + + // ArmBot actions + addArmBot: (productId, event) => { + set((state) => { + state.armBots[event.modelUuid] = { + ...event, + productId, + isActive: false, + idleTime: 0, + activeTime: 0, + state: 'idle' + }; + }); + }, + + removeArmBot: (modelUuid) => { + set((state) => { + delete state.armBots[modelUuid]; + }); + }, + + updateArmBot: (modelUuid, updates) => { + set((state) => { + const armBot = state.armBots[modelUuid]; + if (armBot) { + Object.assign(armBot, updates); + } + }); + }, + + // Action management + startAction: (modelUuid, actionUuid) => { + set((state) => { + const armBot = state.armBots[modelUuid]; + if (armBot) { + const action = armBot.point.actions.find(a => a.actionUuid === actionUuid); + if (action) { + armBot.currentAction = { + actionUuid: action.actionUuid, + actionName: action.actionName + }; + armBot.isActive = true; + } + } + }); + }, + + completeAction: (modelUuid) => { + set((state) => { + const armBot = state.armBots[modelUuid]; + if (armBot && armBot.currentAction) { + armBot.currentAction = undefined; + armBot.isActive = false; + } + }); + }, + + cancelAction: (modelUuid) => { + set((state) => { + const armBot = state.armBots[modelUuid]; + if (armBot) { + armBot.currentAction = undefined; + armBot.isActive = false; + } + }); + }, + + // Status updates + setArmBotActive: (modelUuid, isActive) => { + set((state) => { + const armBot = state.armBots[modelUuid]; + if (armBot) { + armBot.isActive = isActive; + } + }); + }, + + // Time tracking + incrementActiveTime: (modelUuid, incrementBy) => { + set((state) => { + const armBot = state.armBots[modelUuid]; + if (armBot) { + armBot.activeTime += incrementBy; + } + }); + }, + + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const armBot = state.armBots[modelUuid]; + if (armBot) { + armBot.idleTime += incrementBy; + } + }); + }, + + // Helper functions + getArmBotById: (modelUuid) => { + return get().armBots[modelUuid]; + }, + + getArmBotsByProduct: (productId) => { + return Object.values(get().armBots).filter( + a => a.productId === productId + ); + }, + + getActiveArmBots: () => { + return Object.values(get().armBots).filter(a => a.isActive); + }, + + getIdleArmBots: () => { + return Object.values(get().armBots).filter( + a => !a.isActive && a.state === 'idle' + ); + }, + + getArmBotsByCurrentAction: (actionUuid) => { + return Object.values(get().armBots).filter( + a => a.currentAction?.actionUuid === actionUuid + ); + } + })) +); \ No newline at end of file diff --git a/app/src/store/simulation/useConveyorStore.ts b/app/src/store/simulation/useConveyorStore.ts new file mode 100644 index 0000000..f49d5e0 --- /dev/null +++ b/app/src/store/simulation/useConveyorStore.ts @@ -0,0 +1,129 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface ConveyorStatus extends ConveyorEventSchema { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; +} + +interface ConveyorStore { + conveyors: Record; + + // Actions + addConveyor: (productId: string, event: ConveyorEventSchema) => void; + removeConveyor: (modelUuid: string) => void; + updateConveyor: ( + modelUuid: string, + updates: Partial> + ) => void; + + // Status updates + setConveyorActive: (modelUuid: string, isActive: boolean) => void; + setConveyorState: (modelUuid: string, newState: ConveyorStatus['state']) => void; + + // Time tracking + incrementActiveTime: (modelUuid: string, incrementBy: number) => void; + incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + + // Helper functions + getConveyorById: (modelUuid: string) => ConveyorStatus | undefined; + getConveyorsByProduct: (productId: string) => ConveyorStatus[]; + getActiveConveyors: () => ConveyorStatus[]; + getIdleConveyors: () => ConveyorStatus[]; +} + +export const useConveyorStore = create()( + immer((set, get) => ({ + conveyors: {}, + + // Actions + addConveyor: (productId, event) => { + set((state) => { + state.conveyors[event.modelUuid] = { + ...event, + productId, + isActive: false, + idleTime: 0, + activeTime: 0, + state: 'idle', + }; + }); + }, + + removeConveyor: (modelUuid) => { + set((state) => { + delete state.conveyors[modelUuid]; + }); + }, + + updateConveyor: (modelUuid, updates) => { + set((state) => { + const conveyor = state.conveyors[modelUuid]; + if (conveyor) { + Object.assign(conveyor, updates); + } + }); + }, + + // Status updates + setConveyorActive: (modelUuid, isActive) => { + set((state) => { + const conveyor = state.conveyors[modelUuid]; + if (conveyor) { + conveyor.isActive = isActive; + } + }); + }, + + setConveyorState: (modelUuid, newState) => { + set((state) => { + const conveyor = state.conveyors[modelUuid]; + if (conveyor) { + conveyor.state = newState; + } + }); + }, + + // Time tracking + incrementActiveTime: (modelUuid, incrementBy) => { + set((state) => { + const conveyor = state.conveyors[modelUuid]; + if (conveyor) { + conveyor.activeTime += incrementBy; + } + }); + }, + + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const conveyor = state.conveyors[modelUuid]; + if (conveyor) { + conveyor.idleTime += incrementBy; + } + }); + }, + + // Helper functions + getConveyorById: (modelUuid) => { + return get().conveyors[modelUuid]; + }, + + getConveyorsByProduct: (productId) => { + return Object.values(get().conveyors).filter( + c => c.productId === productId + ); + }, + + getActiveConveyors: () => { + return Object.values(get().conveyors).filter(c => c.isActive); + }, + + getIdleConveyors: () => { + return Object.values(get().conveyors).filter( + c => !c.isActive && c.state === 'idle' + ); + }, + })) +); \ No newline at end of file diff --git a/app/src/store/useEventsStore.ts b/app/src/store/simulation/useEventsStore.ts similarity index 88% rename from app/src/store/useEventsStore.ts rename to app/src/store/simulation/useEventsStore.ts index 2fc0317..f13ac5b 100644 --- a/app/src/store/useEventsStore.ts +++ b/app/src/store/simulation/useEventsStore.ts @@ -1,37 +1,33 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -import { useProductStore } from './useSimulationStore'; type EventsStore = { events: EventsSchema[]; - // Sync with product store - syncFromProducts: (products: productsSchema) => void; - // Event-level actions addEvent: (event: EventsSchema) => void; removeEvent: (modelUuid: string) => void; updateEvent: (modelUuid: string, updates: Partial) => void; // Point-level actions - addPoint: (modelUuid: string, point: TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; + addPoint: (modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; removePoint: (modelUuid: string, pointUuid: string) => void; updatePoint: ( modelUuid: string, pointUuid: string, - updates: Partial + updates: Partial ) => void; // Action-level actions addAction: ( modelUuid: string, pointUuid: string, - action: TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] + action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] ) => void; removeAction: (actionUuid: string) => void; updateAction: ( actionUuid: string, - updates: Partial + updates: Partial ) => void; // Trigger-level actions @@ -41,8 +37,8 @@ type EventsStore = { // Helper functions getEventByModelUuid: (modelUuid: string) => EventsSchema | undefined; - getPointByUuid: (modelUuid: string, pointUuid: string) => TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined; - getActionByUuid: (actionUuid: string) => (TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined; + getPointByUuid: (modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined; + getActionByUuid: (actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined; getTriggerByUuid: (triggerUuid: string) => TriggerSchema | undefined; }; @@ -50,13 +46,6 @@ export const useEventsStore = create()( immer((set, get) => ({ events: [], - // Sync events from products store - syncFromProducts: (products) => { - set((state) => { - state.events = products.flatMap(product => product.eventsData); - }); - }, - // Event-level actions addEvent: (event) => { set((state) => { @@ -84,7 +73,7 @@ export const useEventsStore = create()( set((state) => { const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { - (event as TransferEventSchema).points.push(point as TransferPointSchema); + (event as ConveyorEventSchema).points.push(point as ConveyorPointSchema); } else if (event && 'point' in event) { (event as VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent).point = point as any; } @@ -95,7 +84,7 @@ export const useEventsStore = create()( set((state) => { const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { - (event as TransferEventSchema).points = (event as TransferEventSchema).points.filter(p => p.uuid !== pointUuid); + (event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid); } // For single-point events, you might want to handle differently }); @@ -105,7 +94,7 @@ export const useEventsStore = create()( set((state) => { const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { - const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); + const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); if (point) { Object.assign(point, updates); } @@ -120,7 +109,7 @@ export const useEventsStore = create()( set((state) => { const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { - const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); + const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); if (point) { point.action = action as any; } @@ -138,7 +127,7 @@ export const useEventsStore = create()( set((state) => { for (const event of state.events) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { // Handle removal for single action points } @@ -161,7 +150,7 @@ export const useEventsStore = create()( set((state) => { for (const event of state.events) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { Object.assign(point.action, updates); return; @@ -189,7 +178,7 @@ export const useEventsStore = create()( set((state) => { for (const event of state.events) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { point.action.triggers.push(trigger); return; @@ -216,7 +205,7 @@ export const useEventsStore = create()( set((state) => { for (const event of state.events) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && 'triggers' in point.action) { point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid); } @@ -241,7 +230,7 @@ export const useEventsStore = create()( set((state) => { for (const event of state.events) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && 'triggers' in point.action) { const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid); if (trigger) { @@ -282,7 +271,7 @@ export const useEventsStore = create()( getPointByUuid: (modelUuid, pointUuid) => { const event = get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { - return (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); + return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { return (event as any).point; } @@ -293,7 +282,7 @@ export const useEventsStore = create()( const state = get(); for (const event of state.events) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { return point.action; } @@ -315,7 +304,7 @@ export const useEventsStore = create()( const state = get(); for (const event of state.events) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && 'triggers' in point.action) { const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid); if (trigger) return trigger; @@ -340,10 +329,3 @@ export const useEventsStore = create()( } })) ); - -// Set up automatic syncing between stores -useProductStore.subscribe( - (state) => { - useEventsStore.getState().syncFromProducts(state.products); - } -); \ No newline at end of file diff --git a/app/src/store/simulation/useMachineStore.ts b/app/src/store/simulation/useMachineStore.ts new file mode 100644 index 0000000..64f2dcc --- /dev/null +++ b/app/src/store/simulation/useMachineStore.ts @@ -0,0 +1,129 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface MachineStatus extends MachineSchemaEvent { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; +} + +interface MachineStore { + machines: Record; + + // Actions + addMachine: (productId: string, machine: MachineSchemaEvent) => void; + removeMachine: (modelUuid: string) => void; + updateMachine: ( + modelUuid: string, + updates: Partial> + ) => void; + + // Status updates + setMachineActive: (modelUuid: string, isActive: boolean) => void; + setMachineState: (modelUuid: string, newState: MachineStatus['state']) => void; + + // Time tracking + incrementActiveTime: (modelUuid: string, incrementBy: number) => void; + incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + + // Helpers + getMachineById: (modelUuid: string) => MachineStatus | undefined; + getMachinesByProduct: (productId: string) => MachineStatus[]; + getActiveMachines: () => MachineStatus[]; + getIdleMachines: () => MachineStatus[]; +} + +export const useMachineStore = create()( + immer((set, get) => ({ + machines: {}, + + // Actions + addMachine: (productId, machine) => { + set((state) => { + state.machines[machine.modelUuid] = { + ...machine, + productId, + isActive: false, + idleTime: 0, + activeTime: 0, + state: 'idle', + }; + }); + }, + + removeMachine: (modelUuid) => { + set((state) => { + delete state.machines[modelUuid]; + }); + }, + + updateMachine: (modelUuid, updates) => { + set((state) => { + const machine = state.machines[modelUuid]; + if (machine) { + Object.assign(machine, updates); + } + }); + }, + + // Status updates + setMachineActive: (modelUuid, isActive) => { + set((state) => { + const machine = state.machines[modelUuid]; + if (machine) { + machine.isActive = isActive; + } + }); + }, + + setMachineState: (modelUuid, newState) => { + set((state) => { + const machine = state.machines[modelUuid]; + if (machine) { + machine.state = newState; + } + }); + }, + + // Time tracking + incrementActiveTime: (modelUuid, incrementBy) => { + set((state) => { + const machine = state.machines[modelUuid]; + if (machine) { + machine.activeTime += incrementBy; + } + }); + }, + + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const machine = state.machines[modelUuid]; + if (machine) { + machine.idleTime += incrementBy; + } + }); + }, + + // Helpers + getMachineById: (modelUuid) => { + return get().machines[modelUuid]; + }, + + getMachinesByProduct: (productId) => { + return Object.values(get().machines).filter( + m => m.productId === productId + ); + }, + + getActiveMachines: () => { + return Object.values(get().machines).filter(m => m.isActive); + }, + + getIdleMachines: () => { + return Object.values(get().machines).filter( + m => !m.isActive && m.state === 'idle' + ); + }, + })) +); \ No newline at end of file diff --git a/app/src/store/useSimulationStore.ts b/app/src/store/simulation/useSimulationStore.ts similarity index 91% rename from app/src/store/useSimulationStore.ts rename to app/src/store/simulation/useSimulationStore.ts index f0c3a56..dfd8991 100644 --- a/app/src/store/useSimulationStore.ts +++ b/app/src/store/simulation/useSimulationStore.ts @@ -1,7 +1,7 @@ import { create } from 'zustand'; import { immer } from 'zustand/middleware/immer'; -type Store = { +type ProductsStore = { products: productsSchema; // Product-level actions @@ -15,13 +15,13 @@ type Store = { updateEvent: (productId: string, modelUuid: string, updates: Partial) => void; // Point-level actions - addPoint: (productId: string, modelUuid: string, point: TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; + addPoint: (productId: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; removePoint: (productId: string, modelUuid: string, pointUuid: string) => void; updatePoint: ( productId: string, modelUuid: string, pointUuid: string, - updates: Partial + updates: Partial ) => void; // Action-level actions @@ -29,12 +29,12 @@ type Store = { productId: string, modelUuid: string, pointUuid: string, - action: TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] + action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] ) => void; removeAction: (actionUuid: string) => void; updateAction: ( actionUuid: string, - updates: Partial + updates: Partial ) => void; // Trigger-level actions @@ -52,7 +52,7 @@ type Store = { getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined; }; -export const useProductStore = create()( +export const useProductStore = create()( immer((set, get) => ({ products: [], @@ -121,7 +121,7 @@ export const useProductStore = create()( if (product) { const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { - (event as TransferEventSchema).points.push(point as TransferPointSchema); + (event as ConveyorEventSchema).points.push(point as ConveyorPointSchema); } else if (event && 'point' in event) { (event as VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent).point = point as any; } @@ -135,7 +135,7 @@ export const useProductStore = create()( if (product) { const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { - (event as TransferEventSchema).points = (event as TransferEventSchema).points.filter(p => p.uuid !== pointUuid); + (event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid); } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { // For events with single point, we can't remove it, only reset to empty } @@ -149,7 +149,7 @@ export const useProductStore = create()( if (product) { const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { - const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); + const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); if (point) { Object.assign(point, updates); } @@ -167,7 +167,7 @@ export const useProductStore = create()( if (product) { const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid); if (event && 'points' in event) { - const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); + const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid); if (point) { point.action = action as any; } @@ -187,8 +187,8 @@ export const useProductStore = create()( for (const product of state.products) { for (const event of product.eventsData) { if ('points' in event) { - // Handle TransferEventSchema - for (const point of (event as TransferEventSchema).points) { + // Handle ConveyorEventSchema + for (const point of (event as ConveyorEventSchema).points) { } } else if ('point' in event) { const point = (event as any).point; @@ -211,7 +211,7 @@ export const useProductStore = create()( for (const product of state.products) { for (const event of product.eventsData) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { Object.assign(point.action, updates); return; @@ -241,7 +241,7 @@ export const useProductStore = create()( for (const product of state.products) { for (const event of product.eventsData) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && point.action.actionUuid === actionUuid) { point.action.triggers.push(trigger); return; @@ -270,7 +270,7 @@ export const useProductStore = create()( for (const product of state.products) { for (const event of product.eventsData) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && 'triggers' in point.action) { point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid); } @@ -297,7 +297,7 @@ export const useProductStore = create()( for (const product of state.products) { for (const event of product.eventsData) { if ('points' in event) { - for (const point of (event as TransferEventSchema).points) { + for (const point of (event as ConveyorEventSchema).points) { if (point.action && 'triggers' in point.action) { const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid); if (trigger) { @@ -336,4 +336,4 @@ export const useProductStore = create()( return get().products.find(p => p.productId === productId); } })) -); \ No newline at end of file +); diff --git a/app/src/store/simulation/useStorageUnitStore.ts b/app/src/store/simulation/useStorageUnitStore.ts new file mode 100644 index 0000000..db9d3c2 --- /dev/null +++ b/app/src/store/simulation/useStorageUnitStore.ts @@ -0,0 +1,158 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface StorageUnitStatus extends StorageSchemaEvent { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; + currentLoad: number; +} + +interface StorageUnitStore { + storageUnits: Record; + + // Actions + addStorageUnit: (productId: string, storageUnit: StorageSchemaEvent) => void; + removeStorageUnit: (modelUuid: string) => void; + updateStorageUnit: ( + modelUuid: string, + updates: Partial> + ) => void; + + // Status updates + setStorageUnitActive: (modelUuid: string, isActive: boolean) => void; + setStorageUnitState: (modelUuid: string, newState: StorageUnitStatus['state']) => void; + + // Load updates + updateStorageUnitLoad: (modelUuid: string, load: number) => void; + + // Time tracking + incrementActiveTime: (modelUuid: string, incrementBy: number) => void; + incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + + // Helpers + getStorageUnitById: (modelUuid: string) => StorageUnitStatus | undefined; + getStorageUnitsByProduct: (productId: string) => StorageUnitStatus[]; + getActiveStorageUnits: () => StorageUnitStatus[]; + getIdleStorageUnits: () => StorageUnitStatus[]; + getFullStorageUnits: () => StorageUnitStatus[]; + getEmptyStorageUnits: () => StorageUnitStatus[]; +} + +export const useStorageUnitStore = create()( + immer((set, get) => ({ + storageUnits: {}, + + // Actions + addStorageUnit: (productId, storageUnit) => { + set((state) => { + state.storageUnits[storageUnit.modelUuid] = { + ...storageUnit, + productId, + isActive: false, + idleTime: 0, + activeTime: 0, + currentLoad: 0, // Initialize currentLoad to 0 + state: 'idle', + }; + }); + }, + + removeStorageUnit: (modelUuid) => { + set((state) => { + delete state.storageUnits[modelUuid]; + }); + }, + + updateStorageUnit: (modelUuid, updates) => { + set((state) => { + const storageUnit = state.storageUnits[modelUuid]; + if (storageUnit) { + Object.assign(storageUnit, updates); + } + }); + }, + + // Status updates + setStorageUnitActive: (modelUuid, isActive) => { + set((state) => { + const storageUnit = state.storageUnits[modelUuid]; + if (storageUnit) { + storageUnit.isActive = isActive; + } + }); + }, + + setStorageUnitState: (modelUuid, newState) => { + set((state) => { + const storageUnit = state.storageUnits[modelUuid]; + if (storageUnit) { + storageUnit.state = newState; + } + }); + }, + + // Load updates + updateStorageUnitLoad: (modelUuid, load) => { + set((state) => { + const storageUnit = state.storageUnits[modelUuid]; + if (storageUnit) { + storageUnit.currentLoad = load; + } + }); + }, + + // Time tracking + incrementActiveTime: (modelUuid, incrementBy) => { + set((state) => { + const storageUnit = state.storageUnits[modelUuid]; + if (storageUnit) { + storageUnit.activeTime += incrementBy; + } + }); + }, + + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const storageUnit = state.storageUnits[modelUuid]; + if (storageUnit) { + storageUnit.idleTime += incrementBy; + } + }); + }, + + // Helpers + getStorageUnitById: (modelUuid) => { + return get().storageUnits[modelUuid]; + }, + + getStorageUnitsByProduct: (productId) => { + return Object.values(get().storageUnits).filter( + s => s.productId === productId + ); + }, + + getActiveStorageUnits: () => { + return Object.values(get().storageUnits).filter(s => s.isActive); + }, + + getIdleStorageUnits: () => { + return Object.values(get().storageUnits).filter( + s => !s.isActive && s.state === 'idle' + ); + }, + + getFullStorageUnits: () => { + return Object.values(get().storageUnits).filter( + s => s.currentLoad >= s.point.action.storageCapacity + ); + }, + + getEmptyStorageUnits: () => { + return Object.values(get().storageUnits).filter( + s => s.currentLoad === 0 + ); + }, + })) +); \ No newline at end of file diff --git a/app/src/store/simulation/useVehicleStore.ts b/app/src/store/simulation/useVehicleStore.ts new file mode 100644 index 0000000..da093ca --- /dev/null +++ b/app/src/store/simulation/useVehicleStore.ts @@ -0,0 +1,149 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; + +interface VehicleStatus extends VehicleSchemaEvent { + productId: string; + isActive: boolean; + idleTime: number; + activeTime: number; + currentLoad: number; + distanceTraveled: number; +} + +interface VehiclesStore { + vehicles: Record; + + // Vehicle actions + addVehicle: (productId: string, event: VehicleSchemaEvent) => void; + removeVehicle: (modelUuid: string) => void; + updateVehicle: ( + modelUuid: string, + updates: Partial> + ) => void; + + // Status updates + setVehicleActive: (modelUuid: string, isActive: boolean) => void; + updateVehicleLoad: (modelUuid: string, load: number) => void; + + // State management + setVehicleState: (modelUuid: string, newState: VehicleStatus['state']) => void; + + // Time tracking + incrementActiveTime: (modelUuid: string, incrementBy: number) => void; + incrementIdleTime: (modelUuid: string, incrementBy: number) => void; + + // Helper functions + getVehicleById: (modelUuid: string) => VehicleStatus | undefined; + getVehiclesByProduct: (productId: string) => VehicleStatus[]; + getActiveVehicles: () => VehicleStatus[]; + getIdleVehicles: () => VehicleStatus[]; +} + +export const useVehicleStore = create()( + immer((set, get) => ({ + vehicles: {}, + + addVehicle: (productId, event) => { + set((state) => { + state.vehicles[event.modelUuid] = { + ...event, + isActive: false, + productId, + idleTime: 0, + activeTime: 0, + currentLoad: 0, + distanceTraveled: 0, + }; + }); + }, + + removeVehicle: (modelUuid) => { + set((state) => { + delete state.vehicles[modelUuid]; + }); + }, + + updateVehicle: (modelUuid, updates) => { + set((state) => { + const vehicle = state.vehicles[modelUuid]; + if (vehicle) { + Object.assign(vehicle, updates); + } + }); + }, + + // Status updates + setVehicleActive: (modelUuid, isActive) => { + set((state) => { + const vehicle = state.vehicles[modelUuid]; + if (vehicle) { + vehicle.isActive = isActive; + if (isActive) { + vehicle.state = 'running'; + } else { + vehicle.state = vehicle.currentLoad > 0 ? 'idle' : 'stopped'; + } + } + }); + }, + + updateVehicleLoad: (modelUuid, load) => { + set((state) => { + const vehicle = state.vehicles[modelUuid]; + if (vehicle) { + vehicle.currentLoad = load; + } + }); + }, + + // State management + setVehicleState: (modelUuid, newState) => { + set((state) => { + const vehicle = state.vehicles[modelUuid]; + if (vehicle) { + vehicle.state = newState; + } + }); + }, + + // Time tracking + incrementActiveTime: (modelUuid, incrementBy) => { + set((state) => { + const vehicle = state.vehicles[modelUuid]; + if (vehicle) { + vehicle.activeTime += incrementBy; + } + }); + }, + + incrementIdleTime: (modelUuid, incrementBy) => { + set((state) => { + const vehicle = state.vehicles[modelUuid]; + if (vehicle) { + vehicle.idleTime += incrementBy; + } + }); + }, + + // Getters + getVehicleById: (modelUuid) => { + return get().vehicles[modelUuid]; + }, + + getVehiclesByProduct: (productId) => { + return Object.values(get().vehicles).filter( + v => v.productId === productId + ); + }, + + getActiveVehicles: () => { + return Object.values(get().vehicles).filter(v => v.isActive); + }, + + getIdleVehicles: () => { + return Object.values(get().vehicles).filter( + v => !v.isActive && v.currentLoad > 0 + ); + } + })) +); \ No newline at end of file diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 2165b82..b16e1ff 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -85,10 +85,15 @@ export const useZonePoints = create((set) => ({ })); export const useSelectedItem = create((set: any) => ({ - selectedItem: { name: "", id: "" }, + selectedItem: { name: "", id: "", type: undefined }, setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), })); +export const useNavMesh = create((set: any) => ({ + navMesh: null, + setNavMesh: (x: any) => set({ navMesh: x }), +})); + export const useSelectedAssets = create((set: any) => ({ selectedAssets: [], setSelectedAssets: (x: any) => set(() => ({ selectedAssets: x })), diff --git a/app/src/store/useChartStore.ts b/app/src/store/visualization/useChartStore.ts similarity index 100% rename from app/src/store/useChartStore.ts rename to app/src/store/visualization/useChartStore.ts diff --git a/app/src/store/useDroppedObjectsStore.ts b/app/src/store/visualization/useDroppedObjectsStore.ts similarity index 97% rename from app/src/store/useDroppedObjectsStore.ts rename to app/src/store/visualization/useDroppedObjectsStore.ts index ded9f0a..5c4527b 100644 --- a/app/src/store/useDroppedObjectsStore.ts +++ b/app/src/store/visualization/useDroppedObjectsStore.ts @@ -1,6 +1,6 @@ import { create } from "zustand"; -import { addingFloatingWidgets } from "../services/visulization/zone/addFloatingWidgets"; -import { useSocketStore } from "./store"; +import { addingFloatingWidgets } from "../../services/visulization/zone/addFloatingWidgets"; +import { useSocketStore } from "../store"; import useChartStore from "./useChartStore"; type DroppedObject = { diff --git a/app/src/store/useZone3DWidgetStore.ts b/app/src/store/visualization/useZone3DWidgetStore.ts similarity index 100% rename from app/src/store/useZone3DWidgetStore.ts rename to app/src/store/visualization/useZone3DWidgetStore.ts diff --git a/app/src/store/useZoneStore.ts b/app/src/store/visualization/useZoneStore.ts similarity index 95% rename from app/src/store/useZoneStore.ts rename to app/src/store/visualization/useZoneStore.ts index b06824b..eb05790 100644 --- a/app/src/store/useZoneStore.ts +++ b/app/src/store/visualization/useZoneStore.ts @@ -1,53 +1,53 @@ -import { create } from "zustand"; - -type Side = "top" | "bottom" | "left" | "right"; - -interface Widget { - id: string; - type: string; - title: string; - panel: Side; - data: any; -} - -interface SelectedZoneState { - zoneName: string; - activeSides: Side[]; - panelOrder: Side[]; - points: [] - lockedPanels: Side[]; - zoneId: string; - zoneViewPortTarget: number[]; - zoneViewPortPosition: number[]; - widgets: Widget[]; -} - -interface SelectedZoneStore { - selectedZone: SelectedZoneState; - setSelectedZone: ( - zone: - | Partial - | ((prev: SelectedZoneState) => SelectedZoneState) - ) => void; -} - -export const useSelectedZoneStore = create((set) => ({ - selectedZone: { - zoneName: "", // Empty string initially - activeSides: [], // Empty array - panelOrder: [], // Empty array - lockedPanels: [], // Empty array - points: [], - zoneId: "", - zoneViewPortTarget: [], - zoneViewPortPosition: [], - widgets: [], // Empty array - }, - setSelectedZone: (zone) => - set((state) => ({ - selectedZone: - typeof zone === "function" - ? zone(state.selectedZone) // Handle functional updates - : { ...state.selectedZone, ...zone }, // Handle partial updates - })), -})); +import { create } from "zustand"; + +type Side = "top" | "bottom" | "left" | "right"; + +interface Widget { + id: string; + type: string; + title: string; + panel: Side; + data: any; +} + +interface SelectedZoneState { + zoneName: string; + activeSides: Side[]; + panelOrder: Side[]; + points: [] + lockedPanels: Side[]; + zoneId: string; + zoneViewPortTarget: number[]; + zoneViewPortPosition: number[]; + widgets: Widget[]; +} + +interface SelectedZoneStore { + selectedZone: SelectedZoneState; + setSelectedZone: ( + zone: + | Partial + | ((prev: SelectedZoneState) => SelectedZoneState) + ) => void; +} + +export const useSelectedZoneStore = create((set) => ({ + selectedZone: { + zoneName: "", // Empty string initially + activeSides: [], // Empty array + panelOrder: [], // Empty array + lockedPanels: [], // Empty array + points: [], + zoneId: "", + zoneViewPortTarget: [], + zoneViewPortPosition: [], + widgets: [], // Empty array + }, + setSelectedZone: (zone) => + set((state) => ({ + selectedZone: + typeof zone === "function" + ? zone(state.selectedZone) // Handle functional updates + : { ...state.selectedZone, ...zone }, // Handle partial updates + })), +})); diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 07298ca..07a04fa 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -13,11 +13,12 @@ interface TriggerSchema { delay: number; triggeredAsset: { triggeredModel: { modelName: string, modelUuid: string }; + triggeredPoint: { pointName: string, pointUuid: string }; triggeredAction: { actionName: string, actionUuid: string }; } | null; } -interface TransferPointSchema { +interface ConveyorPointSchema { uuid: string; position: [number, number, number]; rotation: [number, number, number]; @@ -25,7 +26,7 @@ interface TransferPointSchema { actionUuid: string; actionName: string; actionType: "default" | "spawn" | "swap" | "despawn"; - material: string | "inherit"; + material: string; delay: number | "inherit"; spawnInterval: number | "inherit"; spawnCount: number | "inherit"; @@ -44,8 +45,8 @@ interface VehiclePointSchema { material: string; unLoadDuration: number; loadCapacity: number; - pickUpPoint: { x: number; y: number, z: number } | {}; - unLoadPoint: { x: number; y: number, z: number } | {}; + pickUpPoint: { x: number; y: number, z: number } | null; + unLoadPoint: { x: number; y: number, z: number } | null; triggers: TriggerSchema[]; }; } @@ -85,15 +86,15 @@ interface StoragePointSchema { actionUuid: string; actionName: string; actionType: "storage"; - materials: { materialName: string; materialId: string; quantity: number }[]; + materials: { materialName: string; materialId: string; }[]; storageCapacity: number; }; } -interface TransferEventSchema extends AssetEventSchema { +interface ConveyorEventSchema extends AssetEventSchema { type: "transfer"; speed: number; - points: TransferPointSchema[]; + points: ConveyorPointSchema[]; } interface VehicleSchemaEvent extends AssetEventSchema { @@ -118,7 +119,7 @@ interface StorageSchemaEvent extends AssetEventSchema { point: StoragePointSchema; } -type EventsSchema = TransferEventSchema | VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent | []; +type EventsSchema = ConveyorEventSchema | VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent | []; type productsSchema = { productName: string;