From f6a63c20d7feb8f77447c756ef06efd2a2599909 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Thu, 4 Sep 2025 17:26:18 +0530 Subject: [PATCH] add simulations data --- .../scenes/functions/simulationStorage.ts | 13 + .../sidebarRight/simulation/Simulations.tsx | 8 + .../ui/simulation/simulationPlayer.tsx | 13 +- .../scene/postProcessing/postProcessing.tsx | 1 + .../simulation/analysis/ROI/roiData.tsx | 21 +- .../productionCapacityData.tsx | 11 +- .../analysis/throughPut/throughPutData.tsx | 10 +- .../simulator/SimulationHandler.tsx | 181 +++++ .../simulation/simulator/simulator.tsx | 4 + app/src/store/builder/store.ts | 684 +++++++++--------- .../store/rough/useSimulationManagerStore.ts | 136 ++++ 11 files changed, 736 insertions(+), 346 deletions(-) create mode 100644 app/src/components/layout/scenes/functions/simulationStorage.ts create mode 100644 app/src/modules/simulation/simulator/SimulationHandler.tsx create mode 100644 app/src/store/rough/useSimulationManagerStore.ts diff --git a/app/src/components/layout/scenes/functions/simulationStorage.ts b/app/src/components/layout/scenes/functions/simulationStorage.ts new file mode 100644 index 0000000..7eafe7c --- /dev/null +++ b/app/src/components/layout/scenes/functions/simulationStorage.ts @@ -0,0 +1,13 @@ +interface SimulationData { + key: string; + data?: object | any; +} +export const saveSimulationData = ({ key, data }: SimulationData) => { + console.log("key: ", key); + localStorage.setItem(key, JSON.stringify(data)); +}; +export const getSimulationData = ({ key }: SimulationData) => { + const data = localStorage.getItem(key); + console.log("data: ", JSON.parse(data || "{}")); +}; +export const clearSimulationData = ({ key, data }: SimulationData) => {}; diff --git a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx index 0858e5d..d4755b8 100644 --- a/app/src/components/layout/sidebarRight/simulation/Simulations.tsx +++ b/app/src/components/layout/sidebarRight/simulation/Simulations.tsx @@ -19,6 +19,7 @@ import { useProductContext } from "../../../../modules/simulation/products/produ import { useParams } from "react-router-dom"; import { useVersionContext } from "../../../../modules/builder/version/versionContext"; import { useSceneContext } from "../../../../modules/scene/sceneContext"; +import { getSimulationData } from "../../scenes/functions/simulationStorage"; interface Event { modelName: string; @@ -137,6 +138,7 @@ const Simulations: React.FC = () => { if (selectedProductData) { determineExecutionMachineSequences([selectedProductData]).then( (sequences) => { + console.log('selectedProductData: ', selectedProductData); sequences.forEach((sequence) => { const events: Event[] = sequence.map((event) => ({ @@ -151,6 +153,12 @@ const Simulations: React.FC = () => { } }, [selectedProduct.productUuid, products]); + //call when comparePopup is true + useEffect(() => { + if (comparePopUp || selectedProduct.productUuid) { + getSimulationData({ key: selectedProduct.productUuid }); + } + }, [comparePopUp]) return (
diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index e2ec99f..f6ff314 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -1,6 +1,7 @@ import React, { useState, useRef, useEffect } from "react"; import { ExitIcon, PlayStopIcon, ResetIcon } from "../../icons/SimulationIcons"; import { + comparsionMaterialData, useActiveTool, useProcessBar, useViewSceneStore, @@ -32,6 +33,8 @@ import ROISummary from "../analysis/ROISummary"; import { usePlayerStore } from "../../../store/useUIToggleStore"; import { useComparisonProduct } from "../../../store/simulation/useSimulationStore"; import InputToggle from "../inputs/InputToggle"; +import { saveSimulationData } from "../../layout/scenes/functions/simulationStorage"; +import { useProductContext } from "../../../modules/simulation/products/productContext"; const SimulationPlayer: React.FC = () => { const MAX_SPEED = 8; // Maximum speed @@ -49,9 +52,11 @@ const SimulationPlayer: React.FC = () => { const { subModule } = useSubModuleStore(); const { clearComparisonProduct } = useComparisonProduct(); const { viewSceneLabels, setViewSceneLabels } = useViewSceneStore(); - + const { materialData, setMaterialData } = comparsionMaterialData() const { isPlaying } = usePlayButtonStore(); const { activeModule } = useModuleStore(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct, setSelectedProduct } = selectedProductStore(); useEffect(() => { if (isReset) { setTimeout(() => { @@ -60,6 +65,12 @@ const SimulationPlayer: React.FC = () => { } }, [isReset, setReset]); + useEffect(() => { + if (materialData.length === 0) return; + console.log('materialData: ', materialData); + saveSimulationData({ key: selectedProduct.productUuid, data: materialData }); + }, [materialData]) + // Button functions const handleReset = () => { setReset(true); diff --git a/app/src/modules/scene/postProcessing/postProcessing.tsx b/app/src/modules/scene/postProcessing/postProcessing.tsx index be05893..3916b56 100644 --- a/app/src/modules/scene/postProcessing/postProcessing.tsx +++ b/app/src/modules/scene/postProcessing/postProcessing.tsx @@ -1,4 +1,5 @@ import { DepthOfField, Bloom, EffectComposer, N8AO } from "@react-three/postprocessing"; +// import OutlineInstances from "./outlineInstances/outlineInstances"; import OutlineInstances from "./outlineInstances/outlineInstances"; import { useDeletableEventSphere, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore"; diff --git a/app/src/modules/simulation/analysis/ROI/roiData.tsx b/app/src/modules/simulation/analysis/ROI/roiData.tsx index b8bdf0f..9753d0e 100644 --- a/app/src/modules/simulation/analysis/ROI/roiData.tsx +++ b/app/src/modules/simulation/analysis/ROI/roiData.tsx @@ -1,8 +1,10 @@ import React, { useEffect } from 'react' -import { CompareProduct, useCompareProductDataStore, useInputValues, useMachineDowntime, useMachineUptime, useProductionCapacityData, useROISummaryData, useThroughPutData } from '../../../../store/builder/store'; +import { CompareProduct, comparsionMaterialData, useCompareProductDataStore, useInputValues, useMachineDowntime, useMachineUptime, useProductionCapacityData, useROISummaryData, useThroughPutData } from '../../../../store/builder/store'; import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; import { useProductContext } from '../../products/productContext'; import { useSceneContext } from '../../../scene/sceneContext'; +import { saveSimulationData } from '../../../../components/layout/scenes/functions/simulationStorage'; +import { set } from 'immer/dist/internal'; export default function ROIData() { const { selectedProductStore } = useProductContext(); @@ -17,6 +19,7 @@ export default function ROIData() { const { machineActiveTime } = useMachineUptime(); const { machineIdleTime } = useMachineDowntime(); const { throughputData } = useThroughPutData() + const { materialData, setMaterialData } = comparsionMaterialData() useEffect(() => { if (isPlaying) return; @@ -136,6 +139,22 @@ export default function ROIData() { const Annual_net_profit = (Annual_units * (sellingPrice - materialCost - laborCost)) - (maintenanceCost + electricityCost + fixedCost) * workingDaysPerYear + (salvageValue * workingDaysPerYear) const Payback_period_years = initialInvestment / Annual_net_profit; + const data = { + productName: selectedProduct.productName, + roiPercentage: ROI, + paybackPeriod: Payback_period_years, + totalCost: Total_cost, + revenueGenerated: Total_revenue, + netProfit: Net_profit > 0 ? Net_profit : 0, + netLoss: Net_profit < 0 ? -Net_profit : 0 + } + console.log('selectedProduct.productUuid: ', selectedProduct.productUuid); + + saveSimulationData({ key: selectedProduct.productUuid, data: data }); + const datas = { + roi: data + } + setMaterialData(datas); setRoiSummaryData({ productName: selectedProduct.productName, diff --git a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx index f7891e7..f17ba57 100644 --- a/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx +++ b/app/src/modules/simulation/analysis/productionCapacity/productionCapacityData.tsx @@ -1,12 +1,15 @@ import { useEffect } from 'react' -import { useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store' +import { comparsionMaterialData, useInputValues, useProductionCapacityData, useThroughPutData } from '../../../../store/builder/store' import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; +import { saveSimulationData } from '../../../../components/layout/scenes/functions/simulationStorage'; export default function ProductionCapacityData() { const { throughputData } = useThroughPutData() const { setProductionCapacityData } = useProductionCapacityData() const { inputValues } = useInputValues(); const { isPlaying } = usePlayButtonStore(); + const { materialData, setMaterialData } = comparsionMaterialData() + useEffect(() => { if (!isPlaying) { @@ -21,10 +24,12 @@ export default function ProductionCapacityData() { if (!isNaN(workingDaysPerYear) && throughputData > 0) { const Monthly_working_days = workingDaysPerYear / 12; const Production_capacity_per_month = throughputData * Monthly_working_days; - + const data = Number(Production_capacity_per_month.toFixed(2)); + saveSimulationData({ key: 'productionCapacity', data: data }); + setMaterialData({ ...materialData, productionCapacity: data }); setProductionCapacityData(Number(Production_capacity_per_month.toFixed(2))); } - }, [throughputData, inputValues, isPlaying]); + }, [throughputData, inputValues, isPlaying, materialData]); return ( <> diff --git a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx index f6ea5c1..38f8aae 100644 --- a/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx +++ b/app/src/modules/simulation/analysis/throughPut/throughPutData.tsx @@ -1,9 +1,10 @@ import { useEffect } from 'react'; import { determineExecutionMachineSequences } from '../../simulator/functions/determineExecutionMachineSequences'; -import { useInputValues, useMachineCount, useMachineDowntime, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store'; +import { comparsionMaterialData, useInputValues, useMachineCount, useMachineDowntime, useMachineUptime, useMaterialCycle, useProcessBar, useThroughPutData } from '../../../../store/builder/store'; import { usePlayButtonStore } from '../../../../store/usePlayButtonStore'; import { useSceneContext } from '../../../scene/sceneContext'; import { useProductContext } from '../../products/productContext'; +import { saveSimulationData } from '../../../../components/layout/scenes/functions/simulationStorage'; export default function ThroughPutData() { const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, productStore } = useSceneContext(); @@ -24,6 +25,7 @@ export default function ThroughPutData() { const { setThroughputData } = useThroughPutData() const { isPlaying } = usePlayButtonStore(); const { inputValues } = useInputValues(); + const { materialData, setMaterialData } = comparsionMaterialData() // Setting machine count let totalItems = 0; @@ -219,9 +221,13 @@ export default function ThroughPutData() { const Units_per_shift = (shiftLength * 60) / (materialCycleTime / 60); const Throughput_per_day = Units_per_shift * shiftsPerDay * (yieldRate / 100); + const data = Number(Throughput_per_day.toFixed(2)) + saveSimulationData({ key: selectedProduct.productUuid, data: data }); + + setMaterialData({ ...materialData, throughput: data }); setThroughputData(Number(Throughput_per_day.toFixed(2))); // Keep as number } - }, [materialCycleTime, machineCount, isPlaying, inputValues]); + }, [materialCycleTime, machineCount, isPlaying, inputValues, materialData]); return ( <> diff --git a/app/src/modules/simulation/simulator/SimulationHandler.tsx b/app/src/modules/simulation/simulator/SimulationHandler.tsx new file mode 100644 index 0000000..5da5bc0 --- /dev/null +++ b/app/src/modules/simulation/simulator/SimulationHandler.tsx @@ -0,0 +1,181 @@ +import React, { useEffect } from 'react'; +import { useSceneContext } from '../../scene/sceneContext'; +import { useProductContext } from '../products/productContext'; +import { determineExecutionMachineSequences } from './functions/determineExecutionMachineSequences'; +import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; +import { useSimulationManager } from '../../../store/rough/useSimulationManagerStore'; +import { useParams } from 'react-router-dom'; +import { useVersionContext } from '../../builder/version/versionContext'; +interface SimulationUsageRecord { + activeTime: number; + isActive: boolean; + idleTime: number; + type: + | "roboticArm" + | "vehicle" + | "transfer" + | "storageUnit" + | "crane" + | "human" + | "machine"; +} + +// Product → holds multiple usage records +interface ProductSimulation { + productId: string; + data: SimulationUsageRecord[]; +} + +// Version → holds multiple products +interface VersionSimulation { + versionId: string; + products: ProductSimulation[]; +} + +// Project → holds multiple versions +interface ProjectSimulation { + projectId: string | undefined; + versions: VersionSimulation[]; +} +const SimulationHandler = () => { + const { materialStore, armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, productStore, craneStore, humanStore } = useSceneContext(); + const { armBots, getArmBotById } = armBotStore(); + const { vehicles, getVehicleById } = vehicleStore(); + const { getConveyorById } = conveyorStore(); + const { materialHistory, materials } = materialStore(); + const { getProductById } = productStore(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); + const { machines, getMachineById } = machineStore(); + const { getHumanById } = humanStore(); + const { getCraneById, } = craneStore(); + const { getStorageUnitById } = storageUnitStore(); + const { isPlaying, setIsPlaying } = usePlayButtonStore(); + const { simulationData, addData } = useSimulationManager(); + const { projectId } = useParams(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + + + + + useEffect(() => { + let checkTimer: ReturnType; + if (!projectId) return; + async function checkActiveMachines() { + const currentProduct = getProductById(selectedProduct.productUuid); + let hasActiveEntity = false; + + if (currentProduct) { + const executionSequences = await determineExecutionMachineSequences([currentProduct]); + if (executionSequences?.length > 0) { + executionSequences.forEach(sequence => { + sequence.forEach(entity => { + if (entity.type === 'roboticArm') { + const roboticArm = getArmBotById(entity.modelUuid); + if (roboticArm?.isActive) { + hasActiveEntity = true; + } + } + if (entity.type === 'vehicle') { + const vehicle = getVehicleById(entity.modelUuid); + if (vehicle?.isActive) { + hasActiveEntity = true; + } + } + if (entity.type === 'machine') { + const machine = getMachineById(entity.modelUuid); + if (machine?.isActive) { + hasActiveEntity = true; + } + } + if (entity.type === 'human') { + const human = getHumanById(entity.modelUuid); + if (human?.isActive) { + hasActiveEntity = true; + } + } + if (entity.type === 'crane') { + const crane = getCraneById(entity.modelUuid); + if (crane?.isActive) { + hasActiveEntity = true; + } + } + if (entity.type === 'storageUnit') { + const storageUnit = getStorageUnitById(entity.modelUuid); + if (storageUnit?.isActive) { + hasActiveEntity = true; + } + } + if (entity.type === "transfer") { + const storageUnit = getConveyorById(entity.modelUuid); + if (storageUnit?.isActive) { + hasActiveEntity = true; + } + } + }); + }); + } + + if (materials.length === 0 && materialHistory.length >= 0 && !hasActiveEntity) { + + if (executionSequences?.length > 0) { + executionSequences.forEach((sequence) => { + sequence.forEach((entity) => { + const typeToGetter: Record any> = { + roboticArm: getArmBotById, + vehicle: getVehicleById, + machine: getMachineById, + human: getHumanById, + crane: getCraneById, + storageUnit: getStorageUnitById, + transfer: getConveyorById, + }; + + const getter = typeToGetter[entity.type]; + if (!getter) return; // skip unknown entity types + + const obj = getter(entity.modelUuid); + if (!obj) return; // skip if not found + + addData( + projectId, + selectedVersion?.versionId || "", + selectedProduct?.productUuid, + { + activeTime: obj.activeTime ?? 0, + isActive: obj.isActive ?? false, + idleTime: obj.idleTime ?? 0, + type: entity.type as + | "roboticArm" + | "vehicle" + | "machine" + | "human" + | "crane" + | "storageUnit" + | "transfer", + } + ); + }); + }); + } + setIsPlaying(false); + } + } + } + + if (isPlaying) { + checkTimer = setTimeout(() => { + checkActiveMachines(); + }, 1500); + } + + return () => { + if (checkTimer) clearTimeout(checkTimer); + }; + }, [materials, materialHistory, selectedVersion, selectedProduct?.productUuid, isPlaying, armBots, vehicles, machines]); + + return null; +} + +export default SimulationHandler; diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx index 21bf97a..ddfd5b6 100644 --- a/app/src/modules/simulation/simulator/simulator.tsx +++ b/app/src/modules/simulation/simulator/simulator.tsx @@ -4,6 +4,7 @@ import { usePlayButtonStore, useResetButtonStore } from '../../../store/usePlayB import { determineExecutionOrder } from './functions/determineExecutionOrder'; import { useProductContext } from '../products/productContext'; import { useSceneContext } from '../../scene/sceneContext'; +import SimulationHandler from './SimulationHandler'; function Simulator() { const { selectedProductStore } = useProductContext(); @@ -32,6 +33,9 @@ function Simulator() { <> + {/* */} + + ); diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index d35ae36..b2ceae5 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -4,601 +4,607 @@ import { io } from "socket.io-client"; import * as CONSTANTS from "../../types/world/worldConstants"; export const useSocketStore = create((set: any, get: any) => ({ - socket: null, - initializeSocket: ( - email?: string, - organization?: string, - token?: string, - refreshToken?: string - ) => { - const existingSocket = get().socket; - if (existingSocket) { - return; - } + socket: null, + initializeSocket: ( + email?: string, + organization?: string, + token?: string, + refreshToken?: string + ) => { + const existingSocket = get().socket; + if (existingSocket) { + return; + } - const socket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); + const socket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); - const visualizationSocket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); + const visualizationSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); - const dashBoardSocket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); - const projectSocket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); - const threadSocket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`, - { - reconnection: true, - auth: { token, refreshToken }, - } - ); + const dashBoardSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); + const projectSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); + const threadSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`, + { + reconnection: true, + auth: { token, refreshToken }, + } + ); - set({ - socket, - visualizationSocket, - dashBoardSocket, - projectSocket, - threadSocket, - }); - }, - disconnectSocket: () => { - set((state: any) => { - state.socket?.disconnect(); - state.visualizationSocket?.disconnect(); - state.dashBoardSocket?.disconnect(); - state.projectSocket?.disconnect(); - state.threadSocket?.disconnect(); - return { socket: null }; - }); - }, + set({ + socket, + visualizationSocket, + dashBoardSocket, + projectSocket, + threadSocket, + }); + }, + disconnectSocket: () => { + set((state: any) => { + state.socket?.disconnect(); + state.visualizationSocket?.disconnect(); + state.dashBoardSocket?.disconnect(); + state.projectSocket?.disconnect(); + state.threadSocket?.disconnect(); + return { socket: null }; + }); + }, })); export const useLoadingProgress = create<{ - loadingProgress: number; - setLoadingProgress: (x: number) => void; + loadingProgress: number; + setLoadingProgress: (x: number) => void; }>((set) => ({ - loadingProgress: 1, - setLoadingProgress: (x: number) => set({ loadingProgress: x }), + loadingProgress: 1, + setLoadingProgress: (x: number) => set({ loadingProgress: x }), })); export const useOrganization = create((set: any) => ({ - organization: "", - setOrganization: (x: any) => set(() => ({ organization: x })), + organization: "", + setOrganization: (x: any) => set(() => ({ organization: x })), })); export const useToggleView = create((set: any) => ({ - toggleView: false, - setToggleView: (x: any) => set(() => ({ toggleView: x })), + toggleView: false, + setToggleView: (x: any) => set(() => ({ toggleView: x })), })); export const useRoomsState = create((set: any) => ({ - roomsState: [], - setRoomsState: (x: any) => set(() => ({ roomsState: x })), + roomsState: [], + setRoomsState: (x: any) => set(() => ({ roomsState: x })), })); export const useSelectedItem = create((set: any) => ({ - selectedItem: { - name: "", - id: "", - type: undefined, - category: "", - subType: "", - }, - setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), + selectedItem: { + name: "", + id: "", + type: undefined, + category: "", + subType: "", + }, + setSelectedItem: (x: any) => set(() => ({ selectedItem: x })), })); type DroppedDecalType = { - category: string; - decalName: string; - decalImage: string; - decalId: string; + category: string; + decalName: string; + decalImage: string; + decalId: string; }; export const useDroppedDecal = create<{ - droppedDecal: DroppedDecalType | null; - setDroppedDecal: (x: DroppedDecalType | null) => void; + droppedDecal: DroppedDecalType | null; + setDroppedDecal: (x: DroppedDecalType | null) => void; }>((set) => ({ - droppedDecal: null, - setDroppedDecal: (x) => set({ droppedDecal: x }), + droppedDecal: null, + setDroppedDecal: (x) => set({ droppedDecal: x }), })); export const useNavMesh = create((set: any) => ({ - navMesh: null, - setNavMesh: (x: any) => set({ navMesh: x }), + navMesh: null, + setNavMesh: (x: any) => set({ navMesh: x }), })); export const useLayers = create((set: any) => ({ - Layers: 1, - setLayers: (x: any) => set(() => ({ Layers: x })), + Layers: 1, + setLayers: (x: any) => set(() => ({ Layers: x })), })); export const useCamPosition = create((set: any) => ({ - camPosition: { x: undefined, y: undefined, z: undefined }, - setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }), + camPosition: { x: undefined, y: undefined, z: undefined }, + setCamPosition: (newCamPosition: any) => set({ camPosition: newCamPosition }), })); export const useMenuVisible = create((set: any) => ({ - menuVisible: false, - setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), + menuVisible: false, + setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), })); export const useToolMode = create((set: any) => ({ - toolMode: null, - setToolMode: (x: any) => set(() => ({ toolMode: x })), + toolMode: null, + setToolMode: (x: any) => set(() => ({ toolMode: x })), })); export const useSetScale = create((set: any) => ({ - scale: null, - setScale: (x: any) => set(() => ({ scale: x })), + scale: null, + setScale: (x: any) => set(() => ({ scale: x })), })); export const useRoofVisibility = create((set: any) => ({ - roofVisibility: false, - setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })), + roofVisibility: false, + setRoofVisibility: (x: any) => set(() => ({ roofVisibility: x })), })); export const useWallVisibility = create((set: any) => ({ - wallVisibility: false, - setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })), + wallVisibility: false, + setWallVisibility: (x: any) => set(() => ({ wallVisibility: x })), })); export const useShadows = create((set: any) => ({ - shadows: false, - setShadows: (x: any) => set(() => ({ shadows: x })), + shadows: false, + setShadows: (x: any) => set(() => ({ shadows: x })), })); export const useSunPosition = create((set: any) => ({ - sunPosition: { x: undefined, y: undefined, z: undefined }, - setSunPosition: (newSuntPosition: any) => - set({ sunPosition: newSuntPosition }), + sunPosition: { x: undefined, y: undefined, z: undefined }, + setSunPosition: (newSuntPosition: any) => + set({ sunPosition: newSuntPosition }), })); export const useRemoveLayer = create((set: any) => ({ - removeLayer: false, - setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })), + removeLayer: false, + setRemoveLayer: (x: any) => set(() => ({ removeLayer: x })), })); export const useRemovedLayer = create((set: any) => ({ - removedLayer: null, - setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })), + removedLayer: null, + setRemovedLayer: (x: any) => set(() => ({ removedLayer: x })), })); export const useProjectName = create((set: any) => ({ - projectName: "Creating Your Project", - setProjectName: (x: any) => set({ projectName: x }), + projectName: "Creating Your Project", + setProjectName: (x: any) => set({ projectName: x }), })); export const useActiveLayer = create((set: any) => ({ - activeLayer: 1, - setActiveLayer: (x: any) => set({ activeLayer: x }), + activeLayer: 1, + setActiveLayer: (x: any) => set({ activeLayer: x }), })); export const useResetCamera = create((set: any) => ({ - resetCamera: false, - setResetCamera: (x: any) => set({ resetCamera: x }), + resetCamera: false, + setResetCamera: (x: any) => set({ resetCamera: x }), })); export const useAddAction = create((set: any) => ({ - addAction: null, - setAddAction: (x: any) => set({ addAction: x }), + addAction: null, + setAddAction: (x: any) => set({ addAction: x }), })); export const useActiveTool = create((set: any) => ({ - activeTool: "cursor", - setActiveTool: (x: any) => set({ activeTool: x }), + activeTool: "cursor", + setActiveTool: (x: any) => set({ activeTool: x }), })); export const useActiveSubTool = create((set: any) => ({ - activeSubTool: "cursor", - setActiveSubTool: (x: any) => set({ activeSubTool: x }), + activeSubTool: "cursor", + setActiveSubTool: (x: any) => set({ activeSubTool: x }), })); export const useElevation = create((set: any) => ({ - elevation: 45, - setElevation: (x: any) => set({ elevation: x }), + elevation: 45, + setElevation: (x: any) => set({ elevation: x }), })); export const useAzimuth = create((set: any) => ({ - azimuth: -160, - setAzimuth: (x: any) => set({ azimuth: x }), + azimuth: -160, + setAzimuth: (x: any) => set({ azimuth: x }), })); export const useRenderDistance = create((set: any) => ({ - renderDistance: 40, - setRenderDistance: (x: any) => set({ renderDistance: x }), + renderDistance: 40, + setRenderDistance: (x: any) => set({ renderDistance: x }), })); export const useCamMode = create((set: any) => ({ - camMode: "ThirdPerson", - setCamMode: (x: any) => set({ camMode: x }), + camMode: "ThirdPerson", + setCamMode: (x: any) => set({ camMode: x }), })); export const useUserName = create((set: any) => ({ - userName: "", - setUserName: (x: any) => set({ userName: x }), + userName: "", + setUserName: (x: any) => set({ userName: x }), })); export const useRenameModeStore = create((set: any) => ({ - isRenameMode: false, - setIsRenameMode: (state: boolean) => set({ isRenameMode: state }), + isRenameMode: false, + setIsRenameMode: (state: boolean) => set({ isRenameMode: state }), })); export const useObjectPosition = create((set: any) => ({ - objectPosition: { x: undefined, y: undefined, z: undefined }, - setObjectPosition: (newObjectPosition: any) => - set({ objectPosition: newObjectPosition }), + objectPosition: { x: undefined, y: undefined, z: undefined }, + setObjectPosition: (newObjectPosition: any) => + set({ objectPosition: newObjectPosition }), })); export const useObjectRotation = create((set: any) => ({ - objectRotation: { x: undefined, y: undefined, z: undefined }, - setObjectRotation: (newObjectRotation: any) => - set({ objectRotation: newObjectRotation }), + objectRotation: { x: undefined, y: undefined, z: undefined }, + setObjectRotation: (newObjectRotation: any) => + set({ objectRotation: newObjectRotation }), })); export const useDrieTemp = create((set: any) => ({ - drieTemp: undefined, - setDrieTemp: (x: any) => set({ drieTemp: x }), + drieTemp: undefined, + setDrieTemp: (x: any) => set({ drieTemp: x }), })); export const useActiveUsers = create((set: any) => ({ - activeUsers: [], - setActiveUsers: (callback: (prev: any[]) => any[] | any[]) => - set((state: { activeUsers: any[] }) => ({ - activeUsers: - typeof callback === "function" ? callback(state.activeUsers) : callback, - })), + activeUsers: [], + setActiveUsers: (callback: (prev: any[]) => any[] | any[]) => + set((state: { activeUsers: any[] }) => ({ + activeUsers: + typeof callback === "function" ? callback(state.activeUsers) : callback, + })), })); export const useDrieUIValue = create((set: any) => ({ - drieUIValue: { touch: null, temperature: null, humidity: null }, + drieUIValue: { touch: null, temperature: null, humidity: null }, - setDrieUIValue: (x: any) => - set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), + setDrieUIValue: (x: any) => + set((state: any) => ({ drieUIValue: { ...state.drieUIValue, ...x } })), - setTouch: (value: any) => - set((state: any) => ({ - drieUIValue: { ...state.drieUIValue, touch: value }, - })), - setTemperature: (value: any) => - set((state: any) => ({ - drieUIValue: { ...state.drieUIValue, temperature: value }, - })), - setHumidity: (value: any) => - set((state: any) => ({ - drieUIValue: { ...state.drieUIValue, humidity: value }, - })), + setTouch: (value: any) => + set((state: any) => ({ + drieUIValue: { ...state.drieUIValue, touch: value }, + })), + setTemperature: (value: any) => + set((state: any) => ({ + drieUIValue: { ...state.drieUIValue, temperature: value }, + })), + setHumidity: (value: any) => + set((state: any) => ({ + drieUIValue: { ...state.drieUIValue, humidity: value }, + })), })); export const usezoneTarget = create((set: any) => ({ - zoneTarget: [], - setZoneTarget: (x: any) => set({ zoneTarget: x }), + zoneTarget: [], + setZoneTarget: (x: any) => set({ zoneTarget: x }), })); export const usezonePosition = create((set: any) => ({ - zonePosition: [], - setZonePosition: (x: any) => set({ zonePosition: x }), + zonePosition: [], + setZonePosition: (x: any) => set({ zonePosition: x }), })); interface EditPositionState { - Edit: boolean; - setEdit: (value: boolean) => void; + Edit: boolean; + setEdit: (value: boolean) => void; } export const useEditPosition = create((set) => ({ - Edit: false, - setEdit: (value) => set({ Edit: value }), + Edit: false, + setEdit: (value) => set({ Edit: value }), })); export const useAsset3dWidget = create((set: any) => ({ - widgetSelect: "", - setWidgetSelect: (x: any) => set({ widgetSelect: x }), + widgetSelect: "", + setWidgetSelect: (x: any) => set({ widgetSelect: x }), })); export const useWidgetSubOption = create((set: any) => ({ - widgetSubOption: "2D", - setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), + widgetSubOption: "2D", + setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), })); export const useLimitDistance = create((set: any) => ({ - limitDistance: true, - setLimitDistance: (x: any) => set({ limitDistance: x }), + limitDistance: true, + setLimitDistance: (x: any) => set({ limitDistance: x }), })); export const useTileDistance = create((set: any) => ({ - gridValue: { - size: CONSTANTS.gridConfig.size, - divisions: CONSTANTS.gridConfig.divisions, - }, - planeValue: { - height: CONSTANTS.planeConfig.height, - width: CONSTANTS.planeConfig.width, - }, + gridValue: { + size: CONSTANTS.gridConfig.size, + divisions: CONSTANTS.gridConfig.divisions, + }, + planeValue: { + height: CONSTANTS.planeConfig.height, + width: CONSTANTS.planeConfig.width, + }, - setGridValue: (value: any) => - set((state: any) => ({ - gridValue: { ...state.gridValue, ...value }, - })), + setGridValue: (value: any) => + set((state: any) => ({ + gridValue: { ...state.gridValue, ...value }, + })), - setPlaneValue: (value: any) => - set((state: any) => ({ - planeValue: { ...state.planeValue, ...value }, - })), + setPlaneValue: (value: any) => + set((state: any) => ({ + planeValue: { ...state.planeValue, ...value }, + })), })); export const usePlayAgv = create((set, get) => ({ - PlayAgv: [], - setPlayAgv: (updateFn: (prev: any[]) => any[]) => - set({ PlayAgv: updateFn(get().PlayAgv) }), + PlayAgv: [], + setPlayAgv: (updateFn: (prev: any[]) => any[]) => + set({ PlayAgv: updateFn(get().PlayAgv) }), })); // Define the Asset type type Asset = { - id: string; - name: string; - position?: [number, number, number]; // Optional: 3D position - rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation + id: string; + name: string; + position?: [number, number, number]; // Optional: 3D position + rotation?: { x: number; y: number; z: number }; // Optional: Euler rotation }; // Zustand store type type ZoneAssetState = { - zoneAssetId: Asset | null; - setZoneAssetId: (asset: Asset | null) => void; + zoneAssetId: Asset | null; + setZoneAssetId: (asset: Asset | null) => void; }; // Zustand store export const useZoneAssetId = create((set) => ({ - zoneAssetId: null, - setZoneAssetId: (asset) => set({ zoneAssetId: asset }), + zoneAssetId: null, + setZoneAssetId: (asset) => set({ zoneAssetId: asset }), })); interface ResourceManagementState { - resourceManagementId: string; - setResourceManagementId: (id: string) => void; + resourceManagementId: string; + setResourceManagementId: (id: string) => void; } -export const useResourceManagementId = create((set) => ({ +export const useResourceManagementId = create( + (set) => ({ resourceManagementId: "", // default value setResourceManagementId: (id: string) => set({ resourceManagementId: id }), -})); + }) +); // version visible hidden interface VersionHistoryState { - viewVersionHistory: boolean; - setVersionHistoryVisible: (value: boolean) => void; + viewVersionHistory: boolean; + setVersionHistoryVisible: (value: boolean) => void; } const useVersionHistoryVisibleStore = create((set) => ({ - viewVersionHistory: false, - setVersionHistoryVisible: (value) => set({ viewVersionHistory: value }), + viewVersionHistory: false, + setVersionHistoryVisible: (value) => set({ viewVersionHistory: value }), })); export default useVersionHistoryVisibleStore; interface ShortcutStore { - showShortcuts: boolean; - setShowShortcuts: (value: boolean) => void; - toggleShortcuts: () => void; + showShortcuts: boolean; + setShowShortcuts: (value: boolean) => void; + toggleShortcuts: () => void; } export const useShortcutStore = create((set) => ({ - showShortcuts: false, - setShowShortcuts: (value) => set({ showShortcuts: value }), - toggleShortcuts: () => - set((state) => ({ showShortcuts: !state.showShortcuts })), + showShortcuts: false, + setShowShortcuts: (value) => set({ showShortcuts: value }), + toggleShortcuts: () => + set((state) => ({ showShortcuts: !state.showShortcuts })), })); export const useMachineCount = create((set: any) => ({ - machineCount: 0, - setMachineCount: (x: any) => set({ machineCount: x }), + machineCount: 0, + setMachineCount: (x: any) => set({ machineCount: x }), })); export const useMachineUptime = create((set: any) => ({ - machineActiveTime: 0, - setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), + machineActiveTime: 0, + setMachineActiveTime: (x: any) => set({ machineActiveTime: x }), })); export const useMachineDowntime = create((set: any) => ({ - machineIdleTime: 0, - setMachineIdleTime: (x: any) => set({ machineIdleTime: x }), + machineIdleTime: 0, + setMachineIdleTime: (x: any) => set({ machineIdleTime: x }), })); export const useMaterialCycle = create((set: any) => ({ - materialCycleTime: 0, - setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), + materialCycleTime: 0, + setMaterialCycleTime: (x: any) => set({ materialCycleTime: x }), })); export const useThroughPutData = create((set: any) => ({ - throughputData: 0, - setThroughputData: (x: any) => set({ throughputData: x }), + throughputData: 0, + setThroughputData: (x: any) => set({ throughputData: x }), })); export const useProductionCapacityData = create((set: any) => ({ - productionCapacityData: 0, - setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), + productionCapacityData: 0, + setProductionCapacityData: (x: any) => set({ productionCapacityData: x }), })); export const useProcessBar = create((set: any) => ({ - processBar: [], - setProcessBar: (x: any) => set({ processBar: x }), + processBar: [], + setProcessBar: (x: any) => set({ processBar: x }), })); export const useDfxUpload = create((set: any) => ({ - dfxuploaded: [], - dfxWallGenerate: [], - objValue: { x: 0, y: 0, z: 0 }, - setDfxUploaded: (x: any) => set({ dfxuploaded: x }), - setDxfWallGenerate: (x: any) => set({ dfxWallGenerate: x }), - setObjValue: (x: any) => set({ objValue: x }), + dfxuploaded: [], + dfxWallGenerate: [], + objValue: { x: 0, y: 0, z: 0 }, + setDfxUploaded: (x: any) => set({ dfxuploaded: x }), + setDxfWallGenerate: (x: any) => set({ dfxWallGenerate: x }), + setObjValue: (x: any) => set({ objValue: x }), })); type InputValuesStore = { - inputValues: Record; - setInputValues: (values: Record) => void; - updateInputValue: (label: string, value: string) => void; // <- New + inputValues: Record; + setInputValues: (values: Record) => void; + updateInputValue: (label: string, value: string) => void; // <- New }; export const useInputValues = create((set) => ({ - inputValues: {}, - setInputValues: (values) => set({ inputValues: values }), - updateInputValue: (label, value) => - set((state) => ({ - inputValues: { - ...state.inputValues, - [label]: value, - }, - })), + inputValues: {}, + setInputValues: (values) => set({ inputValues: values }), + updateInputValue: (label, value) => + set((state) => ({ + inputValues: { + ...state.inputValues, + [label]: value, + }, + })), })); export interface ROISummaryData { - productName: string; - roiPercentage: number; - paybackPeriod: number; - totalCost: number; - revenueGenerated: number; - netProfit: number; - netLoss: number; + productName: string; + roiPercentage: number; + paybackPeriod: number; + totalCost: number; + revenueGenerated: number; + netProfit: number; + netLoss: number; } interface ROISummaryStore { - roiSummary: ROISummaryData; - setRoiSummaryData: (values: ROISummaryData) => void; + roiSummary: ROISummaryData; + setRoiSummaryData: (values: ROISummaryData) => void; } export const useROISummaryData = create((set) => ({ - roiSummary: { - productName: "", - roiPercentage: 0, - paybackPeriod: 0, - totalCost: 0, - revenueGenerated: 0, - netProfit: 0, - netLoss: 0, - }, - setRoiSummaryData: (values) => set({ roiSummary: values }), + roiSummary: { + productName: "", + roiPercentage: 0, + paybackPeriod: 0, + totalCost: 0, + revenueGenerated: 0, + netProfit: 0, + netLoss: 0, + }, + setRoiSummaryData: (values) => set({ roiSummary: values }), })); interface CompareStore { - comparePopUp: boolean; - setComparePopUp: (value: boolean) => void; - toggleComparePopUp: () => void; + comparePopUp: boolean; + setComparePopUp: (value: boolean) => void; + toggleComparePopUp: () => void; } export const useCompareStore = create((set) => ({ - comparePopUp: false, - setComparePopUp: (value) => set({ comparePopUp: value }), - toggleComparePopUp: () => - set((state) => ({ comparePopUp: !state.comparePopUp })), + comparePopUp: false, + setComparePopUp: (value) => set({ comparePopUp: value }), + toggleComparePopUp: () => + set((state) => ({ comparePopUp: !state.comparePopUp })), })); // Save state store interface SaveVersionStore { - isVersionSaved: boolean; - setIsVersionSaved: (value: boolean) => void; + isVersionSaved: boolean; + setIsVersionSaved: (value: boolean) => void; } export const useSaveVersion = create((set) => ({ - isVersionSaved: false, - setIsVersionSaved: (value: boolean) => set({ isVersionSaved: value }), + isVersionSaved: false, + setIsVersionSaved: (value: boolean) => set({ isVersionSaved: value }), })); interface ViewSceneState { - viewSceneLabels: boolean; - setViewSceneLabels: (value: boolean | ((prev: boolean) => boolean)) => void; + viewSceneLabels: boolean; + setViewSceneLabels: (value: boolean | ((prev: boolean) => boolean)) => void; } export const useViewSceneStore = create((set) => ({ - viewSceneLabels: getInitialViewSceneLabels(), - setViewSceneLabels: (value) => { - set((state) => { - const newValue = - typeof value === "function" ? value(state.viewSceneLabels) : value; + viewSceneLabels: getInitialViewSceneLabels(), + setViewSceneLabels: (value) => { + set((state) => { + const newValue = + typeof value === "function" ? value(state.viewSceneLabels) : value; - // Store in localStorage manually - localStorage.setItem("viewSceneLabels", JSON.stringify(newValue)); + // Store in localStorage manually + localStorage.setItem("viewSceneLabels", JSON.stringify(newValue)); - return { viewSceneLabels: newValue }; - }); - }, + return { viewSceneLabels: newValue }; + }); + }, })); function getInitialViewSceneLabels(): boolean { - if (typeof window === "undefined") return false; // SSR safety - const saved = localStorage.getItem("viewSceneLabels"); - return saved ? JSON.parse(saved) : false; + if (typeof window === "undefined") return false; // SSR safety + const saved = localStorage.getItem("viewSceneLabels"); + return saved ? JSON.parse(saved) : false; } export interface CompareProduct { - productUuid: string; - productName: string; - simulationData: { - // costPerUnit: number; - // workingDaysPerYear: number; - // shiftLength: number; - // shiftsPerDay: number; - roiPercentage: number; - // paybackPeriod: number; - // totalCost: number; - // revenueGenerated: number; - netProfit: number; - productionCapacity: number; - paybackPeriod: number; - // netLoss: number; - machineIdleTime: number; - machineActiveTime: number; - throughputData: number; - }; + productUuid: string; + productName: string; + simulationData: { + // costPerUnit: number; + // workingDaysPerYear: number; + // shiftLength: number; + // shiftsPerDay: number; + roiPercentage: number; + // paybackPeriod: number; + // totalCost: number; + // revenueGenerated: number; + netProfit: number; + productionCapacity: number; + paybackPeriod: number; + // netLoss: number; + machineIdleTime: number; + machineActiveTime: number; + throughputData: number; + }; } export const useCompareProductDataStore = create<{ - compareProductsData: CompareProduct[]; - setCompareProductsData: (x: CompareProduct[]) => void; + compareProductsData: CompareProduct[]; + setCompareProductsData: (x: CompareProduct[]) => void; }>((set) => ({ - compareProductsData: [], - setCompareProductsData: (x) => set({ compareProductsData: x }), + compareProductsData: [], + setCompareProductsData: (x) => set({ compareProductsData: x }), })); export const useSelectedComment = create((set: any) => ({ - selectedComment: null, - setSelectedComment: (x: any) => set({ selectedComment: x }), - position2Dstate: {}, - setPosition2Dstate: (x: any) => set({ position2Dstate: x }), - commentPositionState: null, - setCommentPositionState: (x: any) => set({ commentPositionState: x }), + selectedComment: null, + setSelectedComment: (x: any) => set({ selectedComment: x }), + position2Dstate: {}, + setPosition2Dstate: (x: any) => set({ position2Dstate: x }), + commentPositionState: null, + setCommentPositionState: (x: any) => set({ commentPositionState: x }), })); export const useSelectedPath = create((set: any) => ({ - selectedPath: "auto", - setSelectedPath: (x: any) => set({ selectedPath: x }), + selectedPath: "auto", + setSelectedPath: (x: any) => set({ selectedPath: x }), })); export const useContextActionStore = create((set: any) => ({ - contextAction: null, - setContextAction: (x: any) => set({ contextAction: x }), + contextAction: null, + setContextAction: (x: any) => set({ contextAction: x }), })); - // Define the store's state and actions type interface DecalStore { - selectedSubCategory: string | null; - setSelectedSubCategory: (subCategory: string | null) => void; + selectedSubCategory: string | null; + setSelectedSubCategory: (subCategory: string | null) => void; } // Create the Zustand store with types export const useDecalStore = create((set) => ({ - selectedSubCategory: 'Safety', - setSelectedSubCategory: (subCategory: string | null) => set({ selectedSubCategory: subCategory }), + selectedSubCategory: "Safety", + setSelectedSubCategory: (subCategory: string | null) => + set({ selectedSubCategory: subCategory }), +})); +export const comparsionMaterialData = create((set: any) => ({ + materialData: [], + setMaterialData: (x: any) => set({ materialData: x }), })); diff --git a/app/src/store/rough/useSimulationManagerStore.ts b/app/src/store/rough/useSimulationManagerStore.ts new file mode 100644 index 0000000..c86a38a --- /dev/null +++ b/app/src/store/rough/useSimulationManagerStore.ts @@ -0,0 +1,136 @@ + +import { create } from "zustand"; + + +interface SimulationUsageRecord { + activeTime: number; + isActive: boolean; + idleTime: number; + type: + | "roboticArm" + | "vehicle" + | "transfer" + | "storageUnit" + | "crane" + | "human" + | "machine"; +} + +// Product → holds multiple usage records +interface ProductSimulation { + productId: string; + data: SimulationUsageRecord[]; +} + +// Version → holds multiple products +interface VersionSimulation { + versionId: string; + products: ProductSimulation[]; +} + +// Project → holds multiple versions +interface ProjectSimulation { + projectId: string | undefined; + versions: VersionSimulation[]; +} +// or same file + +interface SimulationManagerStore { + simulationData: ProjectSimulation[]; + + addData: ( + projectId: string | undefined, + versionId: string, + productId: string, + record: SimulationUsageRecord + ) => void; + + resetProductData: ( + projectId: string, + versionId: string, + productId: string + ) => void; +} + +export const useSimulationManager = create((set) => ({ + simulationData: [], + + addData: (projectId, versionId, productId, record) => + set((state) => { + const projects = state.simulationData.map((project) => { + if (project.projectId !== projectId) return project; + + return { + ...project, + versions: project.versions.map((version) => { + if (version.versionId !== versionId) return version; + + return { + ...version, + products: version.products.map((product) => + product.productId === productId + ? { ...product, data: [...product.data, record] } + : product + ), + }; + }), + }; + }); + + // If project doesn't exist, create it + if (!state.simulationData.find((p) => p.projectId === projectId)) { + projects.push({ + projectId, + versions: [ + { + versionId, + products: [{ productId, data: [record] }], + }, + ], + }); + } else { + const project = projects.find((p) => p.projectId === projectId)!; + if (!project.versions.find((v) => v.versionId === versionId)) { + project.versions.push({ + versionId, + products: [{ productId, data: [record] }], + }); + } else { + const version = project.versions.find( + (v) => v.versionId === versionId + )!; + if (!version.products.find((p) => p.productId === productId)) { + version.products.push({ productId, data: [record] }); + } + } + } + + return { simulationData: projects }; + }), + + resetProductData: (projectId, versionId, productId) => + set((state) => { + const projects = state.simulationData.map((project) => { + if (project.projectId !== projectId) return project; + + return { + ...project, + versions: project.versions.map((version) => { + if (version.versionId !== versionId) return version; + + return { + ...version, + products: version.products.map((product) => + product.productId === productId + ? { ...product, data: [] } + : product + ), + }; + }), + }; + }); + + return { simulationData: projects }; + }), +})); +///////////////////////////