feat: Implement duplicate event and product stores using Zustand with immer middleware
- Created `duplicateEventStore` to manage events with actions for adding, removing, updating events, points, actions, and triggers. - Implemented helper functions to retrieve events, points, actions, and triggers by their unique identifiers. - Created `duplicateProductStore` to manage products and their associated events, including actions for adding, removing, updating products, events, points, actions, and triggers. - Added renaming functions for products, actions, and triggers. - Included comprehensive helper functions to retrieve products and their related data by various identifiers.
This commit is contained in:
parent
d0538ccfae
commit
f8bcc5aa1c
|
@ -6,6 +6,7 @@ import ModelDuplicate from "./modelDuplicate";
|
|||
import { useLoadingProgress } from "../../../../store/builder/store";
|
||||
import { getFloorAssets } from "../../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi";
|
||||
import { FloorItems } from "../../../../types/world/worldTypes";
|
||||
import { useDuplicateEventsStore } from "../../duplicateStores/duplicateEventStore";
|
||||
|
||||
const gltfLoaderWorker = new Worker(
|
||||
new URL(
|
||||
|
@ -19,6 +20,7 @@ function AssetsGroupDuplicate({ projectId }: { projectId: string }) {
|
|||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
const [assetsDuplicates, setAssetsDuplicates] = useState<Assets>([]);
|
||||
const { addEvent } = useDuplicateEventsStore();
|
||||
|
||||
const loader = new GLTFLoader();
|
||||
const dracoLoader = new DRACOLoader();
|
||||
|
@ -73,10 +75,11 @@ function AssetsGroupDuplicate({ projectId }: { projectId: string }) {
|
|||
updateLoadingProgress(progress);
|
||||
|
||||
if (loadedAssets === totalAssets) {
|
||||
const assets: Asset[] = [];
|
||||
getFloorAssets(organization, projectId).then((data: FloorItems) => {
|
||||
const newAssets: Assets = data.map((item) => {
|
||||
data.map((item) => {
|
||||
if (item.eventData) {
|
||||
return {
|
||||
assets.push({
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
assetId: item.assetId,
|
||||
|
@ -87,9 +90,136 @@ function AssetsGroupDuplicate({ projectId }: { projectId: string }) {
|
|||
isVisible: item.isVisible,
|
||||
opacity: 1,
|
||||
eventData: item.eventData
|
||||
};
|
||||
})
|
||||
|
||||
if (item.eventData.type === "Vehicle") {
|
||||
const vehicleEvent: VehicleEventSchema = {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "vehicle",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "travel",
|
||||
unLoadDuration: 5,
|
||||
loadCapacity: 1,
|
||||
steeringAngle: 0,
|
||||
pickUpPoint: null,
|
||||
unLoadPoint: null,
|
||||
triggers: []
|
||||
}
|
||||
}
|
||||
};
|
||||
addEvent(vehicleEvent);
|
||||
} else if (item.eventData.type === "Conveyor") {
|
||||
const ConveyorEvent: ConveyorEventSchema = {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "transfer",
|
||||
speed: 1,
|
||||
points: item.eventData.points?.map((point: any, index: number) => ({
|
||||
uuid: point.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [point.position[0], point.position[1], point.position[2]],
|
||||
rotation: [point.rotation[0], point.rotation[1], point.rotation[2]],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: `Action 1`,
|
||||
actionType: 'default',
|
||||
material: 'Default material',
|
||||
delay: 0,
|
||||
spawnInterval: 5,
|
||||
spawnCount: 1,
|
||||
triggers: []
|
||||
}
|
||||
})) || [],
|
||||
};
|
||||
addEvent(ConveyorEvent);
|
||||
} else if (item.eventData.type === "StaticMachine") {
|
||||
const machineEvent: MachineEventSchema = {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "machine",
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "process",
|
||||
processTime: 10,
|
||||
swapMaterial: "Default Material",
|
||||
triggers: []
|
||||
}
|
||||
}
|
||||
};
|
||||
addEvent(machineEvent);
|
||||
} else if (item.eventData.type === "ArmBot") {
|
||||
const roboticArmEvent: RoboticArmEventSchema = {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z],
|
||||
state: "idle",
|
||||
type: "roboticArm",
|
||||
speed: 1,
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
|
||||
actions: [
|
||||
{
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "pickAndPlace",
|
||||
process: {
|
||||
startPoint: null,
|
||||
endPoint: null
|
||||
},
|
||||
triggers: []
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
addEvent(roboticArmEvent);
|
||||
} else if (item.eventData.type === 'Storage') {
|
||||
const storageEvent: StorageEventSchema = {
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
position: item.position,
|
||||
rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle",
|
||||
type: "storageUnit",
|
||||
point: {
|
||||
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
|
||||
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
|
||||
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
|
||||
action: {
|
||||
actionUuid: THREE.MathUtils.generateUUID(),
|
||||
actionName: "Action 1",
|
||||
actionType: "store",
|
||||
storageCapacity: 10,
|
||||
triggers: []
|
||||
}
|
||||
}
|
||||
};
|
||||
addEvent(storageEvent);
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
assets.push({
|
||||
modelUuid: item.modelUuid,
|
||||
modelName: item.modelName,
|
||||
assetId: item.assetId,
|
||||
|
@ -99,10 +229,10 @@ function AssetsGroupDuplicate({ projectId }: { projectId: string }) {
|
|||
isCollidable: false,
|
||||
isVisible: item.isVisible,
|
||||
opacity: 1,
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
setAssetsDuplicates(newAssets);
|
||||
setAssetsDuplicates(assets);
|
||||
});
|
||||
updateLoadingProgress(100);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import * as Types from "../../../../types/world/worldTypes";
|
|||
import * as CONSTANTS from "../../../../types/world/worldConstants";
|
||||
import { Base } from "@react-three/csg";
|
||||
import { MeshDiscardMaterial } from "@react-three/drei";
|
||||
import { useEffect } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import objectLinesToArray from "../../../builder/geomentries/lines/lineConvertions/objectLinesToArray";
|
||||
import loadWalls from "../../../builder/geomentries/walls/loadWalls";
|
||||
import texturePath from "../../../../assets/textures/floor/wall-tex.png";
|
||||
|
@ -24,12 +24,14 @@ const WallsMeshDuplicate = ({ projectId, walls, setWalls, lines }: any) => {
|
|||
});
|
||||
}, []);
|
||||
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
const wallTexture = textureLoader.load(texturePath);
|
||||
|
||||
wallTexture.wrapS = wallTexture.wrapT = THREE.RepeatWrapping;
|
||||
wallTexture.repeat.set(0.1, 0.1);
|
||||
wallTexture.colorSpace = THREE.SRGBColorSpace;
|
||||
const wallTexture = React.useMemo(() => {
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
const texture = textureLoader.load(texturePath);
|
||||
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
|
||||
texture.repeat.set(0.1, 0.1);
|
||||
texture.colorSpace = THREE.SRGBColorSpace;
|
||||
return texture;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,37 +1,20 @@
|
|||
import { CameraControls } from "@react-three/drei";
|
||||
import { useRef, useEffect } from "react";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import { useRef } from "react";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
|
||||
import { useToggleView } from "../../../store/builder/store";
|
||||
import { getCamera } from "../../../services/factoryBuilder/camera/getCameraApi";
|
||||
import { useDuplicatedCamData, useToggleView } from "../../../store/builder/store";
|
||||
|
||||
export default function ControlsDuplicate({ projectId }: { projectId: string }) {
|
||||
export default function ControlsDuplicate() {
|
||||
const controlsRef = useRef<CameraControls>(null);
|
||||
|
||||
const { toggleView } = useToggleView();
|
||||
const state = useThree();
|
||||
const { duplicatedCamData } = useDuplicatedCamData();
|
||||
|
||||
useEffect(() => {
|
||||
if (controlsRef.current) {
|
||||
(controlsRef.current as any).mouseButtons.left = CONSTANTS.thirdPersonControls.leftMouse;
|
||||
(controlsRef.current as any).mouseButtons.right = CONSTANTS.thirdPersonControls.rightMouse;
|
||||
}
|
||||
const email = localStorage.getItem("email");
|
||||
const organization = email!.split("@")[1].split(".")[0];
|
||||
const userId = localStorage.getItem("userId")!;
|
||||
|
||||
getCamera(organization, userId, projectId).then((data) => {
|
||||
if (data && data.position && data.target) {
|
||||
controlsRef.current?.setPosition(data.position.x, data.position.y, data.position.z);
|
||||
controlsRef.current?.setTarget(data.target.x, data.target.y, data.target.z);
|
||||
} else {
|
||||
controlsRef.current?.setPosition(...CONSTANTS.threeDimension.defaultPosition);
|
||||
controlsRef.current?.setTarget(...CONSTANTS.threeDimension.defaultTarget);
|
||||
}
|
||||
})
|
||||
.catch((error) => console.error("Failed to fetch camera data:", error));
|
||||
}, []);
|
||||
useFrame(() => {
|
||||
controlsRef.current?.setPosition(...duplicatedCamData.camPosition, true);
|
||||
controlsRef.current?.setTarget(...duplicatedCamData.camTarget, true);
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
import * as THREE from "three";
|
||||
import { useEventsStore } from "../../../../store/simulation/useEventsStore";
|
||||
import useModuleStore from "../../../../store/useModuleStore";
|
||||
import { usePlayButtonStore } from "../../../../store/usePlayButtonStore";
|
||||
|
||||
function PointsDuplicate() {
|
||||
const { events } = useEventsStore();
|
||||
const { activeModule } = useModuleStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
||||
return (
|
||||
<>
|
||||
{activeModule === "simulation" && (
|
||||
<>
|
||||
<group name="EventPointsGroup" visible={!isPlaying}>
|
||||
{events.map((event, index) => {
|
||||
const usedEvent = event;
|
||||
|
||||
if (usedEvent.type === "transfer") {
|
||||
return (
|
||||
<group
|
||||
key={`${index}-${usedEvent.modelUuid}`}
|
||||
position={usedEvent.position}
|
||||
rotation={usedEvent.rotation}
|
||||
>
|
||||
{usedEvent.points.map((point, j) => (
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={point.uuid}
|
||||
key={`${index}-${point.uuid}`}
|
||||
position={new THREE.Vector3(...point.position)}
|
||||
userData={{
|
||||
modelUuid: usedEvent.modelUuid,
|
||||
pointUuid: point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="orange" />
|
||||
</mesh>
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
} else if (usedEvent.type === "vehicle") {
|
||||
const point = usedEvent.point;
|
||||
return (
|
||||
<group
|
||||
key={`${index}-${usedEvent.modelUuid}`}
|
||||
position={usedEvent.position}
|
||||
rotation={usedEvent.rotation}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={point.uuid}
|
||||
position={new THREE.Vector3(...point.position)}
|
||||
userData={{
|
||||
modelUuid: usedEvent.modelUuid,
|
||||
pointUuid: point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="blue" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else if (usedEvent.type === "roboticArm") {
|
||||
const point = usedEvent.point;
|
||||
return (
|
||||
<group
|
||||
key={`${index}-${usedEvent.modelUuid}`}
|
||||
position={usedEvent.position}
|
||||
rotation={usedEvent.rotation}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={point.uuid}
|
||||
position={new THREE.Vector3(...point.position)}
|
||||
userData={{
|
||||
modelUuid: usedEvent.modelUuid,
|
||||
pointUuid: point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="green" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else if (usedEvent.type === "machine") {
|
||||
const point = usedEvent.point;
|
||||
return (
|
||||
<group
|
||||
key={`${index}-${usedEvent.modelUuid}`}
|
||||
position={usedEvent.position}
|
||||
rotation={usedEvent.rotation}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={point.uuid}
|
||||
position={new THREE.Vector3(...point.position)}
|
||||
userData={{
|
||||
modelUuid: usedEvent.modelUuid,
|
||||
pointUuid: point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="purple" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else if (usedEvent.type === "storageUnit") {
|
||||
const point = usedEvent.point;
|
||||
return (
|
||||
<group
|
||||
key={`${index}-${usedEvent.modelUuid}`}
|
||||
position={usedEvent.position}
|
||||
rotation={usedEvent.rotation}
|
||||
>
|
||||
<mesh
|
||||
name="Event-Sphere"
|
||||
uuid={point.uuid}
|
||||
position={new THREE.Vector3(...point.position)}
|
||||
userData={{
|
||||
modelUuid: usedEvent.modelUuid,
|
||||
pointUuid: point.uuid,
|
||||
}}
|
||||
>
|
||||
<sphereGeometry args={[0.1, 16, 16]} />
|
||||
<meshStandardMaterial color="red" />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
</group>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default PointsDuplicate;
|
|
@ -0,0 +1,149 @@
|
|||
import * as THREE from 'three';
|
||||
import { useEffect } from 'react';
|
||||
import { upsertProductOrEventApi } from '../../../../services/simulation/products/UpsertProductOrEventApi';
|
||||
import { getAllProductsApi } from '../../../../services/simulation/products/getallProductsApi';
|
||||
import { usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore';
|
||||
import { useSceneContext } from '../../../scene/sceneContext';
|
||||
import { useProductContext } from '../../../simulation/products/productContext';
|
||||
import { useComparisonProduct, useMainProduct } from '../../../../store/simulation/useSimulationStore';
|
||||
import { useDuplicateProductStore } from '../../duplicateStores/duplicateProductStore';
|
||||
|
||||
function ProductsDuplicate({ projectId }: { projectId: string }) {
|
||||
const { armBotStore, machineStore, conveyorStore, vehicleStore, storageUnitStore, layout } = useSceneContext();
|
||||
const { products, getProductById, addProduct, setProducts } = useDuplicateProductStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { setMainProduct } = useMainProduct();
|
||||
const { selectedProduct, setSelectedProduct } = selectedProductStore();
|
||||
const { addVehicle, clearvehicles } = vehicleStore();
|
||||
const { addArmBot, clearArmBots } = armBotStore();
|
||||
const { addMachine, clearMachines } = machineStore();
|
||||
const { addConveyor, clearConveyors } = conveyorStore();
|
||||
const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = storageUnitStore();
|
||||
const { isReset } = useResetButtonStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { comparisonProduct } = useComparisonProduct();
|
||||
|
||||
useEffect(() => {
|
||||
if (layout === 'Comparison Layout' && comparisonProduct) {
|
||||
setSelectedProduct(comparisonProduct.productUuid, comparisonProduct.productName);
|
||||
}
|
||||
}, [comparisonProduct])
|
||||
|
||||
useEffect(() => {
|
||||
getAllProductsApi(projectId || '').then((data) => {
|
||||
if (data.length === 0) {
|
||||
const id = THREE.MathUtils.generateUUID();
|
||||
const name = 'Product 1';
|
||||
addProduct(name, id);
|
||||
console.log(name, id, projectId);
|
||||
upsertProductOrEventApi({
|
||||
productName: name,
|
||||
productUuid: id,
|
||||
projectId: projectId || ''
|
||||
})
|
||||
if (layout === 'Main Layout') {
|
||||
setSelectedProduct(id, name);
|
||||
setMainProduct(id, name);
|
||||
}
|
||||
} else {
|
||||
setProducts(data);
|
||||
if (layout === 'Main Layout') {
|
||||
setSelectedProduct(data[0].productUuid, data[0].productName);
|
||||
setMainProduct(data[0].productUuid, data[0].productName);
|
||||
}
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProduct.productUuid) {
|
||||
const product = getProductById(selectedProduct.productUuid);
|
||||
if (product) {
|
||||
clearvehicles();
|
||||
product.eventDatas.forEach(events => {
|
||||
if (events.type === 'vehicle') {
|
||||
addVehicle(selectedProduct.productUuid, events);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, products, isReset, isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProduct.productUuid) {
|
||||
const product = getProductById(selectedProduct.productUuid);
|
||||
if (product) {
|
||||
clearArmBots();
|
||||
product.eventDatas.forEach(events => {
|
||||
if (events.type === 'roboticArm') {
|
||||
addArmBot(selectedProduct.productUuid, events);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, products, isReset, isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProduct.productUuid) {
|
||||
const product = getProductById(selectedProduct.productUuid);
|
||||
if (product) {
|
||||
clearConveyors();
|
||||
product.eventDatas.forEach(events => {
|
||||
if (events.type === 'transfer') {
|
||||
addConveyor(selectedProduct.productUuid, events);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, products, isReset, isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProduct.productUuid) {
|
||||
const product = getProductById(selectedProduct.productUuid);
|
||||
if (product) {
|
||||
clearMachines();
|
||||
product.eventDatas.forEach(events => {
|
||||
if (events.type === 'machine') {
|
||||
addMachine(selectedProduct.productUuid, events);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, products, isReset, isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedProduct.productUuid) {
|
||||
const product = getProductById(selectedProduct.productUuid);
|
||||
if (product) {
|
||||
clearStorageUnits();
|
||||
product.eventDatas.forEach(event => {
|
||||
if (event.type === 'storageUnit') {
|
||||
addStorageUnit(selectedProduct.productUuid, event);
|
||||
|
||||
if (event.point.action.actionType === 'retrieve') {
|
||||
const storageAction = event.point.action;
|
||||
const materials = Array.from({ length: storageAction.storageCapacity }, () => ({
|
||||
materialType: storageAction.materialType || 'Default material',
|
||||
materialId: THREE.MathUtils.generateUUID()
|
||||
}));
|
||||
|
||||
setCurrentMaterials(event.modelUuid, materials);
|
||||
updateCurrentLoad(event.modelUuid, storageAction.storageCapacity);
|
||||
} else {
|
||||
setCurrentMaterials(event.modelUuid, []);
|
||||
updateCurrentLoad(event.modelUuid, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [selectedProduct, products, isReset, isPlaying]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProductsDuplicate
|
|
@ -0,0 +1,20 @@
|
|||
import React from 'react'
|
||||
import ProductsDuplicate from './duplicateProduct/duplicateProduct'
|
||||
import PointsDuplicate from './duplicatePoint/duplicatePoint'
|
||||
import TriggerDuplicate from './duplicateTrigger/duplicateTrigger'
|
||||
|
||||
function SimulationDuplicate({ projectId }: { projectId: string }) {
|
||||
return (
|
||||
<>
|
||||
|
||||
<ProductsDuplicate projectId={projectId} />
|
||||
|
||||
<PointsDuplicate />
|
||||
|
||||
<TriggerDuplicate />
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default SimulationDuplicate
|
|
@ -0,0 +1,165 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import { QuadraticBezierLine } from "@react-three/drei";
|
||||
import { usePlayButtonStore } from "../../../../store/usePlayButtonStore";
|
||||
import { Arrows } from "../../../simulation/events/arrows/arrows";
|
||||
import { useProductContext } from "../../../simulation/products/productContext";
|
||||
import { useDuplicateProductStore } from "../../duplicateStores/duplicateProductStore";
|
||||
|
||||
interface ConnectionLine {
|
||||
id: string;
|
||||
startPointUuid: string;
|
||||
endPointUuid: string;
|
||||
trigger: TriggerSchema;
|
||||
}
|
||||
|
||||
function TriggerDuplicate() {
|
||||
const { scene } = useThree();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { products, getProductById } = useDuplicateProductStore();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
|
||||
const [connections, setConnections] = useState<ConnectionLine[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const newConnections: ConnectionLine[] = [];
|
||||
|
||||
const product = getProductById(selectedProduct.productUuid);
|
||||
if (!product || products.length === 0) return;
|
||||
|
||||
product.eventDatas.forEach(event => {
|
||||
// Handle Conveyor points
|
||||
if (event.type === "transfer" && 'points' in event) {
|
||||
event.points.forEach(point => {
|
||||
if (point.action?.triggers) {
|
||||
point.action.triggers.forEach(trigger => {
|
||||
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
|
||||
newConnections.push({
|
||||
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
|
||||
startPointUuid: point.uuid,
|
||||
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
trigger
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// Handle Vehicle point
|
||||
else if (event.type === "vehicle" && 'point' in event) {
|
||||
const point = event.point;
|
||||
if (point.action?.triggers) {
|
||||
point.action.triggers.forEach(trigger => {
|
||||
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
|
||||
newConnections.push({
|
||||
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
|
||||
startPointUuid: point.uuid,
|
||||
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
trigger
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Handle Robotic Arm points
|
||||
else if (event.type === "roboticArm" && 'point' in event) {
|
||||
const point = event.point;
|
||||
point.actions?.forEach(action => {
|
||||
action.triggers?.forEach(trigger => {
|
||||
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
|
||||
newConnections.push({
|
||||
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
|
||||
startPointUuid: point.uuid,
|
||||
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
trigger
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// Handle Machine point
|
||||
else if (event.type === "machine" && 'point' in event) {
|
||||
const point = event.point;
|
||||
if (point.action?.triggers) {
|
||||
point.action.triggers.forEach(trigger => {
|
||||
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
|
||||
newConnections.push({
|
||||
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
|
||||
startPointUuid: point.uuid,
|
||||
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
trigger
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Handle StorageUnit point
|
||||
else if (event.type === "storageUnit" && 'point' in event) {
|
||||
const point = event.point;
|
||||
if (point.action?.triggers) {
|
||||
point.action.triggers.forEach(trigger => {
|
||||
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
|
||||
newConnections.push({
|
||||
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
|
||||
startPointUuid: point.uuid,
|
||||
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
|
||||
trigger
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setConnections(newConnections);
|
||||
}, [products, selectedProduct.productUuid]);
|
||||
|
||||
const getWorldPositionFromScene = (pointUuid: string): THREE.Vector3 | null => {
|
||||
const pointObj = scene.getObjectByProperty("uuid", pointUuid);
|
||||
if (!pointObj) return null;
|
||||
|
||||
const worldPosition = new THREE.Vector3();
|
||||
pointObj.getWorldPosition(worldPosition);
|
||||
return worldPosition;
|
||||
};
|
||||
|
||||
return (
|
||||
<group name="simulationConnectionGroup" visible={!isPlaying}>
|
||||
{connections.map((connection) => {
|
||||
const startPoint = getWorldPositionFromScene(connection.startPointUuid);
|
||||
const endPoint = getWorldPositionFromScene(connection.endPointUuid);
|
||||
|
||||
if (!startPoint || !endPoint) return null;
|
||||
|
||||
const distance = startPoint.distanceTo(endPoint);
|
||||
const heightFactor = Math.max(0.5, distance * 0.2);
|
||||
const midPoint = new THREE.Vector3(
|
||||
(startPoint.x + endPoint.x) / 2,
|
||||
Math.max(startPoint.y, endPoint.y) + heightFactor,
|
||||
(startPoint.z + endPoint.z) / 2
|
||||
);
|
||||
|
||||
return (
|
||||
<QuadraticBezierLine
|
||||
key={connection.id}
|
||||
start={startPoint.toArray()}
|
||||
end={endPoint.toArray()}
|
||||
mid={midPoint.toArray()}
|
||||
color={"#42a5f5"}
|
||||
lineWidth={4}
|
||||
dashed={true}
|
||||
dashSize={0.75}
|
||||
dashScale={20}
|
||||
userData={connection.trigger}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
<Arrows connections={connections} />
|
||||
</group>
|
||||
);
|
||||
}
|
||||
|
||||
export default TriggerDuplicate;
|
|
@ -0,0 +1,357 @@
|
|||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
type EventsStore = {
|
||||
events: EventsSchema[];
|
||||
|
||||
// Event-level actions
|
||||
addEvent: (event: EventsSchema) => void;
|
||||
removeEvent: (modelUuid: string) => void;
|
||||
clearEvents: () => void;
|
||||
updateEvent: (modelUuid: string, updates: Partial<EventsSchema>) => EventsSchema | undefined;
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
|
||||
removePoint: (modelUuid: string, pointUuid: string) => void;
|
||||
updatePoint: (
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
updates: Partial<ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema>
|
||||
) => EventsSchema | undefined;
|
||||
|
||||
// Action-level actions
|
||||
addAction: (
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
|
||||
) => void;
|
||||
removeAction: (actionUuid: string) => void;
|
||||
updateAction: (
|
||||
actionUuid: string,
|
||||
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
|
||||
) => void;
|
||||
|
||||
// Trigger-level actions
|
||||
addTrigger: (actionUuid: string, trigger: TriggerSchema) => void;
|
||||
removeTrigger: (triggerUuid: string) => void;
|
||||
updateTrigger: (triggerUuid: string, updates: Partial<TriggerSchema>) => void;
|
||||
|
||||
// Helper functions
|
||||
getEventByModelUuid: (modelUuid: string) => EventsSchema | 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;
|
||||
};
|
||||
|
||||
export const useDuplicateEventsStore = create<EventsStore>()(
|
||||
immer((set, get) => ({
|
||||
events: [],
|
||||
|
||||
// Event-level actions
|
||||
addEvent: (event) => {
|
||||
set((state) => {
|
||||
if (!state.events.some(e => 'modelUuid' in e && e.modelUuid === event.modelUuid)) {
|
||||
state.events.push(event);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeEvent: (modelUuid) => {
|
||||
set((state) => {
|
||||
state.events = state.events.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
|
||||
});
|
||||
},
|
||||
|
||||
clearEvents: () => {
|
||||
set((state) => {
|
||||
state.events = [];
|
||||
});
|
||||
},
|
||||
|
||||
updateEvent: (modelUuid, updates) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event) {
|
||||
Object.assign(event, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (modelUuid, point) => {
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const existingPoint = (event as ConveyorEventSchema).points.find(p => p.uuid === point.uuid);
|
||||
if (!existingPoint) {
|
||||
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
|
||||
}
|
||||
} else if (event && 'point' in event) {
|
||||
if (!(event as any).point || (event as any).point.uuid !== point.uuid) {
|
||||
(event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point = point as any;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removePoint: (modelUuid, pointUuid) => {
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
(event as ConveyorEventSchema).points = (event as ConveyorEventSchema).points.filter(p => p.uuid !== pointUuid);
|
||||
}
|
||||
// For single-point events, you might want to handle differently
|
||||
});
|
||||
},
|
||||
|
||||
updatePoint: (modelUuid, pointUuid, updates) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
if (point) {
|
||||
Object.assign(point, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
Object.assign((event as any).point, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
// Action-level actions
|
||||
addAction: (modelUuid, pointUuid, action) => {
|
||||
set((state) => {
|
||||
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
if (point && (!point.action || point.action.actionUuid !== action.actionUuid)) {
|
||||
point.action = action as any;
|
||||
}
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && (!point.action || point.action.actionUuid !== action.actionUuid)) {
|
||||
point.action = action;
|
||||
} else if ('actions' in point && !point.actions.some((a: any) => a.actionUuid === action.actionUuid)) {
|
||||
point.actions.push(action);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeAction: (actionUuid) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
// Handle removal for single action points
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if (event.type === "roboticArm") {
|
||||
if ('actions' in point) {
|
||||
point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid);
|
||||
}
|
||||
} else if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||
// Handle single action
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateAction: (actionUuid, updates) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
Object.assign(point.action, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
Object.assign(point.action, updates);
|
||||
return;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
Object.assign(action, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Trigger-level actions
|
||||
addTrigger: (actionUuid, trigger) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
if (!point.action.triggers.some(t => t.triggerUuid === trigger.triggerUuid)) {
|
||||
point.action.triggers.push(trigger);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point: MachinePointSchema | VehiclePointSchema = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
if (!point.action.triggers.some(t => t.triggerUuid === trigger.triggerUuid)) {
|
||||
point.action.triggers.push(trigger);
|
||||
}
|
||||
return;
|
||||
} else if ('actions' in point) {
|
||||
const action = (point as RoboticArmPointSchema).actions.find((a) => a.actionUuid === actionUuid);
|
||||
if (action && !action.triggers.some(t => t.triggerUuid === trigger.triggerUuid)) {
|
||||
action.triggers.push(trigger);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeTrigger: (triggerUuid) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateTrigger: (triggerUuid, updates) => {
|
||||
set((state) => {
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
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) {
|
||||
Object.assign(trigger, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
return;
|
||||
}
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Helper functions
|
||||
getEventByModelUuid: (modelUuid) => {
|
||||
return get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
},
|
||||
|
||||
getPointByUuid: (modelUuid, pointUuid) => {
|
||||
const event = get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
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;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getActionByUuid: (actionUuid) => {
|
||||
const state = get();
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
return point.action;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
return point.action;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) return action;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getTriggerByUuid: (triggerUuid) => {
|
||||
const state = get();
|
||||
for (const event of state.events) {
|
||||
if ('points' in event) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) return trigger;
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) return trigger;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}))
|
||||
);
|
|
@ -0,0 +1,798 @@
|
|||
import { create } from 'zustand';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
type ProductsStore = {
|
||||
products: productsSchema;
|
||||
|
||||
// Product-level actions
|
||||
addProduct: (productName: string, productUuid: string) => void;
|
||||
setProducts: (products: productsSchema) => void;
|
||||
clearProducts: () => void;
|
||||
removeProduct: (productUuid: string) => void;
|
||||
updateProduct: (productUuid: string, updates: Partial<{ productName: string; eventDatas: EventsSchema[] }>) => void;
|
||||
|
||||
// Event-level actions
|
||||
addEvent: (productUuid: string, event: EventsSchema) => void;
|
||||
removeEvent: (productUuid: string, modelUuid: string) => void;
|
||||
deleteEvent: (modelUuid: string) => void;
|
||||
updateEvent: (productUuid: string, modelUuid: string, updates: Partial<EventsSchema>) => EventsSchema | undefined;
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (productUuid: string, modelUuid: string, point: ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
|
||||
removePoint: (productUuid: string, modelUuid: string, pointUuid: string) => void;
|
||||
updatePoint: (
|
||||
productUuid: string,
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
updates: Partial<ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema>
|
||||
) => EventsSchema | undefined;
|
||||
|
||||
// Action-level actions
|
||||
addAction: (
|
||||
productUuid: string,
|
||||
modelUuid: string,
|
||||
pointUuid: string,
|
||||
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
|
||||
) => EventsSchema | undefined;
|
||||
removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined;
|
||||
updateAction: (
|
||||
productUuid: string,
|
||||
actionUuid: string,
|
||||
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
|
||||
) => EventsSchema | undefined;
|
||||
|
||||
// Trigger-level actionss
|
||||
addTrigger: (
|
||||
productUuid: string,
|
||||
actionUuid: string,
|
||||
trigger: TriggerSchema
|
||||
) => EventsSchema | undefined;
|
||||
removeTrigger: (productUuid: string, triggerUuid: string) => EventsSchema | undefined;
|
||||
updateTrigger: (
|
||||
productUuid: string,
|
||||
triggerUuid: string,
|
||||
updates: Partial<TriggerSchema>
|
||||
) => EventsSchema | undefined;
|
||||
|
||||
// Renaming functions
|
||||
renameProduct: (productUuid: string, newName: string) => void;
|
||||
renameAction: (productUuid: string, actionUuid: string, newName: string) => EventsSchema | undefined;
|
||||
renameTrigger: (productUuid: string, triggerUuid: string, newName: string) => EventsSchema | undefined;
|
||||
|
||||
// Helper functions
|
||||
getProductById: (productUuid: string) => { productName: string; productUuid: string; eventDatas: EventsSchema[] } | undefined;
|
||||
getEventByModelUuid: (productUuid: string, modelUuid: string) => EventsSchema | undefined;
|
||||
getEventByActionUuid: (productUuid: string, actionUuid: string) => EventsSchema | undefined;
|
||||
getEventByTriggerUuid: (productUuid: string, triggerUuid: string) => EventsSchema | undefined;
|
||||
getEventByPointUuid: (productUuid: string, pointUuid: string) => EventsSchema | undefined;
|
||||
getPointByUuid: (productUuid: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
|
||||
getActionByUuid: (productUuid: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
||||
getActionByPointUuid: (productUuid: string, pointUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
||||
getModelUuidByPointUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
||||
getModelUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
||||
getPointUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
|
||||
getTriggerByUuid: (productUuid: string, triggerUuid: string) => TriggerSchema | undefined;
|
||||
getIsEventInProduct: (productUuid: string, modelUuid: string) => boolean;
|
||||
};
|
||||
|
||||
export const useDuplicateProductStore = create<ProductsStore>()(
|
||||
immer((set, get) => ({
|
||||
products: [],
|
||||
|
||||
// Product-level actions
|
||||
addProduct: (productName, productUuid) => {
|
||||
set((state) => {
|
||||
const existingProduct = state.products.find(p => p.productUuid === productUuid);
|
||||
if (!existingProduct) {
|
||||
const newProduct = {
|
||||
productName,
|
||||
productUuid: productUuid,
|
||||
eventDatas: []
|
||||
};
|
||||
state.products.push(newProduct);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setProducts: (products) => {
|
||||
set((state) => {
|
||||
state.products = products;
|
||||
});
|
||||
},
|
||||
|
||||
clearProducts: () => {
|
||||
set((state) => {
|
||||
state.products = [];
|
||||
});
|
||||
},
|
||||
|
||||
removeProduct: (productUuid) => {
|
||||
set((state) => {
|
||||
state.products = state.products.filter(p => p.productUuid !== productUuid);
|
||||
});
|
||||
},
|
||||
|
||||
updateProduct: (productUuid, updates) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
Object.assign(product, updates);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Event-level actions
|
||||
addEvent: (productUuid, event) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
const existingEvent = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === event.modelUuid);
|
||||
if (!existingEvent) {
|
||||
product.eventDatas.push(event);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeEvent: (productUuid, modelUuid) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
deleteEvent: (modelUuid) => {
|
||||
set((state) => {
|
||||
for (const product of state.products) {
|
||||
product.eventDatas = product.eventDatas.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updateEvent: (productUuid, modelUuid, updates) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event) {
|
||||
Object.assign(event, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
// Point-level actions
|
||||
addPoint: (productUuid, modelUuid, point) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const existingPoint = (event as ConveyorEventSchema).points.find(p => p.uuid === point.uuid);
|
||||
if (!existingPoint) {
|
||||
(event as ConveyorEventSchema).points.push(point as ConveyorPointSchema);
|
||||
}
|
||||
} else if (event && 'point' in event) {
|
||||
const existingPoint = (event as any).point?.uuid === point.uuid;
|
||||
if (!existingPoint) {
|
||||
(event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point = point as any;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removePoint: (productUuid, modelUuid, pointUuid) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
(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
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updatePoint: (productUuid, modelUuid, pointUuid, updates) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
if (point) {
|
||||
Object.assign(point, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
Object.assign((event as any).point, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
// Action-level actions
|
||||
addAction: (productUuid, modelUuid, pointUuid, action) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
const event = product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
if (event && 'points' in event) {
|
||||
const point = (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
if (point && (!point.action || point.action.actionUuid !== action.actionUuid)) {
|
||||
point.action = action as any;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
|
||||
if ('action' in (event as any).point) {
|
||||
if (!(event as any).point.action || (event as any).point.action.actionUuid !== action.actionUuid) {
|
||||
(event as any).point.action = action;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
} else if ('actions' in (event as any).point) {
|
||||
const existingAction = (event as any).point.actions.find((a: any) => a.actionUuid === action.actionUuid);
|
||||
if (!existingAction) {
|
||||
(event as any).point.actions.push(action);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
removeAction: (productUuid, actionUuid) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
// Handle ConveyorEventSchema
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if (event.type === "roboticArm") {
|
||||
if ('actions' in point) {
|
||||
const index = point.actions.findIndex((a: any) => a.actionUuid === actionUuid);
|
||||
if (index !== -1) {
|
||||
point.actions.splice(index, 1);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||
point.action = undefined;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
updateAction: (productUuid, actionUuid, updates) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
Object.assign(point.action, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
Object.assign(point.action, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
Object.assign(action, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
// Trigger-level actions
|
||||
addTrigger: (productUuid, actionUuid, trigger) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
const existingTrigger = point.action.triggers.find(t => t.triggerUuid === trigger.triggerUuid);
|
||||
if (!existingTrigger) {
|
||||
point.action.triggers.push(trigger);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
const existingTrigger = point.action.triggers.find((t: any) => t.triggerUuid === trigger.triggerUuid);
|
||||
if (!existingTrigger) {
|
||||
point.action.triggers.push(trigger);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
return;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
const existingTrigger = action.triggers.find((t: any) => t.triggerUuid === trigger.triggerUuid);
|
||||
if (!existingTrigger) {
|
||||
action.triggers.push(trigger);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
removeTrigger: (productUuid, triggerUuid) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
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) {
|
||||
point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
const Trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (Trigger) {
|
||||
point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
const Trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (Trigger) {
|
||||
action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
updateTrigger: (productUuid, triggerUuid, updates) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
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) {
|
||||
Object.assign(trigger, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
Object.assign(trigger, updates);
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
// Renaming functions
|
||||
renameProduct: (productUuid, newName) => {
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
product.productName = newName;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
renameAction: (productUuid, actionUuid, newName) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action && point.action.actionUuid === actionUuid) {
|
||||
point.action.actionName = newName;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action.actionUuid === actionUuid) {
|
||||
point.action.actionName = newName;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
action.actionName = newName;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
renameTrigger: (productUuid, triggerUuid, newName) => {
|
||||
let updatedEvent: EventsSchema | undefined;
|
||||
set((state) => {
|
||||
const product = state.products.find(p => p.productUuid === productUuid);
|
||||
if (product) {
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
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) {
|
||||
trigger.triggerName = newName;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && 'triggers' in point.action) {
|
||||
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
trigger.triggerName = newName;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if ('triggers' in action) {
|
||||
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
|
||||
if (trigger) {
|
||||
trigger.triggerName = newName;
|
||||
updatedEvent = JSON.parse(JSON.stringify(event));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return updatedEvent;
|
||||
},
|
||||
|
||||
// Helper functions
|
||||
getProductById: (productUuid) => {
|
||||
return get().products.find(p => p.productUuid === productUuid);
|
||||
},
|
||||
|
||||
getEventByModelUuid: (productUuid, modelUuid) => {
|
||||
const product = get().getProductById(productUuid);
|
||||
if (!product) return undefined;
|
||||
return product.eventDatas.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
},
|
||||
|
||||
getEventByActionUuid: (productUuid, actionUuid) => {
|
||||
const product = get().getProductById(productUuid);
|
||||
if (!product) return undefined;
|
||||
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action?.actionUuid === actionUuid) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||
return event;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getEventByTriggerUuid: (productUuid, triggerUuid) => {
|
||||
const product = get().getProductById(productUuid);
|
||||
if (!product) return undefined;
|
||||
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action?.triggers?.some(t => t.triggerUuid === triggerUuid)) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point) {
|
||||
if (point.action?.triggers?.some((t: any) => t.triggerUuid === triggerUuid)) {
|
||||
return event;
|
||||
}
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
if (action.triggers?.some((t: any) => t.triggerUuid === triggerUuid)) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getEventByPointUuid: (productUuid, pointUuid) => {
|
||||
const product = get().getProductById(productUuid);
|
||||
if (!product) return undefined;
|
||||
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
if ((event as ConveyorEventSchema).points.some(p => p.uuid === pointUuid)) {
|
||||
return event;
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
if ((event as any).point?.uuid === pointUuid) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getPointByUuid: (productUuid, modelUuid, pointUuid) => {
|
||||
const event = get().getEventByModelUuid(productUuid, modelUuid);
|
||||
if (!event) return undefined;
|
||||
|
||||
if ('points' in event) {
|
||||
return (event as ConveyorEventSchema).points.find(p => p.uuid === pointUuid);
|
||||
} else if ('point' in event && (event as any).point.uuid === pointUuid) {
|
||||
return (event as VehicleEventSchema | RoboticArmEventSchema | MachineEventSchema | StorageEventSchema).point;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getActionByUuid: (productUuid, actionUuid) => {
|
||||
const product = get().products.find(p => p.productUuid === productUuid);
|
||||
if (!product) return undefined;
|
||||
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action?.actionUuid === actionUuid) {
|
||||
return point.action;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||
return point.action;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) return action;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getActionByPointUuid: (productUuid, pointUuid) => {
|
||||
const product = get().products.find(p => p.productUuid === productUuid);
|
||||
if (!product) return undefined;
|
||||
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.uuid === pointUuid) {
|
||||
return point.action;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if (point.uuid === pointUuid) {
|
||||
return point.action;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getModelUuidByPointUuid: (productUuid, pointUuid) => {
|
||||
const product = get().products.find(p => p.productUuid === productUuid);
|
||||
if (!product) return undefined;
|
||||
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.uuid === pointUuid) {
|
||||
return event.modelUuid;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if (point.uuid === pointUuid) {
|
||||
return event.modelUuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getModelUuidByActionUuid: (productUuid, actionUuid) => {
|
||||
const product = get().products.find(p => p.productUuid === productUuid);
|
||||
if (!product) return undefined;
|
||||
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action?.actionUuid === actionUuid) {
|
||||
return event.modelUuid;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||
return event.modelUuid;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) return event.modelUuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getPointUuidByActionUuid: (productUuid, actionUuid) => {
|
||||
const product = get().products.find(p => p.productUuid === productUuid);
|
||||
if (!product) return undefined;
|
||||
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
if (point.action?.actionUuid === actionUuid) {
|
||||
return point.uuid;
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||
return point.uuid;
|
||||
} else if ('actions' in point) {
|
||||
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||
if (action) return point.uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getTriggerByUuid: (productUuid, triggerUuid) => {
|
||||
const product = get().products.find(p => p.productUuid === productUuid);
|
||||
if (!product) return undefined;
|
||||
|
||||
for (const event of product.eventDatas) {
|
||||
if ('points' in event) {
|
||||
for (const point of (event as ConveyorEventSchema).points) {
|
||||
for (const trigger of point.action?.triggers || []) {
|
||||
if (trigger.triggerUuid === triggerUuid) {
|
||||
return trigger;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ('point' in event) {
|
||||
const point = (event as any).point;
|
||||
if ('action' in point) {
|
||||
for (const trigger of point.action?.triggers || []) {
|
||||
if (trigger.triggerUuid === triggerUuid) {
|
||||
return trigger;
|
||||
}
|
||||
}
|
||||
} else if ('actions' in point) {
|
||||
for (const action of point.actions) {
|
||||
for (const trigger of action.triggers || []) {
|
||||
if (trigger.triggerUuid === triggerUuid) {
|
||||
return trigger;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getIsEventInProduct: (productUuid, modelUuid) => {
|
||||
const product = get().getProductById(productUuid);
|
||||
if (!product) return false;
|
||||
return product.eventDatas.some(e => 'modelUuid' in e && e.modelUuid === modelUuid);
|
||||
}
|
||||
}))
|
||||
);
|
|
@ -9,36 +9,45 @@ import background from "../../assets/textures/hdr/mudroadpuresky2k.hdr";
|
|||
import ControlsDuplicate from "./duplicateSetup/controlsDuplicate";
|
||||
import PostProcessingDuplicate from "./duplicateSetup/postProcessingDuplicate";
|
||||
import { Color } from "three";
|
||||
import { SceneProvider } from "../scene/sceneContext";
|
||||
import SimulationDuplicate from "./duplicateSimulation/duplicateSimulation";
|
||||
|
||||
export default function DuplicateScene() {
|
||||
const projectId = "684bcd620a64bc2a815a88d6";
|
||||
|
||||
return (
|
||||
<Canvas
|
||||
id="sceneCanvas"
|
||||
shadows
|
||||
color="#aaaa"
|
||||
eventPrefix="client"
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
onCreated={(e) => {
|
||||
e.scene.background = new Color(0x19191d);
|
||||
}}
|
||||
gl={{ powerPreference: "high-performance", antialias: true, preserveDrawingBuffer: true }}
|
||||
>
|
||||
<SceneProvider layout='Comparison Layout'>
|
||||
<Canvas
|
||||
id="sceneCanvas"
|
||||
shadows
|
||||
color="#aaaa"
|
||||
eventPrefix="client"
|
||||
style={{
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
onCreated={(e) => {
|
||||
e.scene.background = new Color(0x19191d);
|
||||
}}
|
||||
gl={{ powerPreference: "high-performance", antialias: true, preserveDrawingBuffer: true }}
|
||||
>
|
||||
|
||||
<Sun />
|
||||
<Sun />
|
||||
|
||||
<Shadows />
|
||||
<Shadows />
|
||||
|
||||
<ControlsDuplicate projectId={projectId} />
|
||||
<ControlsDuplicate />
|
||||
|
||||
<PostProcessingDuplicate />
|
||||
<PostProcessingDuplicate />
|
||||
|
||||
<Environment files={background} environmentIntensity={1.5} />
|
||||
<Environment files={background} environmentIntensity={1.5} />
|
||||
|
||||
<BuilderDuplicate projectId={projectId} />
|
||||
</Canvas>
|
||||
<BuilderDuplicate projectId={projectId} />
|
||||
|
||||
<SimulationDuplicate projectId={projectId} />
|
||||
</Canvas>
|
||||
</SceneProvider>
|
||||
);
|
||||
}
|
|
@ -4,7 +4,7 @@ import { useThree } from "@react-three/fiber";
|
|||
import * as THREE from "three";
|
||||
import * as CONSTANTS from '../../../types/world/worldConstants';
|
||||
|
||||
import { useSocketStore, useToggleView, useResetCamera } from "../../../store/builder/store";
|
||||
import { useSocketStore, useToggleView, useResetCamera, useDuplicatedCamData } from "../../../store/builder/store";
|
||||
import { getCamera } from "../../../services/factoryBuilder/camera/getCameraApi";
|
||||
import updateCamPosition from "../camera/updateCameraPosition";
|
||||
import CamMode from "../camera/camMode";
|
||||
|
@ -21,6 +21,7 @@ export default function Controls() {
|
|||
const { socket } = useSocketStore();
|
||||
const state = useThree();
|
||||
const { projectId } = useParams();
|
||||
const { setDuplicatedCamData } = useDuplicatedCamData();
|
||||
|
||||
useEffect(() => {
|
||||
if (controlsRef.current) {
|
||||
|
@ -106,10 +107,23 @@ export default function Controls() {
|
|||
}
|
||||
};
|
||||
|
||||
const camUpdate = () => {
|
||||
if (!controlsRef.current) return;
|
||||
const position = controlsRef.current.getPosition(new THREE.Vector3(0, 0, 0));
|
||||
const target = controlsRef.current.getTarget(new THREE.Vector3(0, 0, 0));
|
||||
const rotation = state.camera.rotation;
|
||||
setDuplicatedCamData(
|
||||
[position.x, position.y, position.z],
|
||||
[target.x, target.y, target.z],
|
||||
[rotation.x, rotation.y, rotation.z]
|
||||
)
|
||||
};
|
||||
|
||||
const controls = controlsRef.current;
|
||||
if (controls) {
|
||||
controls.addEventListener("sleep", handleRest);
|
||||
controls.addEventListener("control", startInterval);
|
||||
controls.addEventListener("control", camUpdate);
|
||||
controls.addEventListener("controlend", stopInterval);
|
||||
}
|
||||
|
||||
|
@ -117,6 +131,7 @@ export default function Controls() {
|
|||
if (controls) {
|
||||
controls.removeEventListener("sleep", handleRest);
|
||||
controls.removeEventListener("control", startInterval);
|
||||
controls.removeEventListener("control", camUpdate);
|
||||
controls.removeEventListener("controlend", stopInterval);
|
||||
}
|
||||
stopInterval();
|
||||
|
|
|
@ -742,3 +742,35 @@ export const useCompareProductDataStore = create<{
|
|||
compareProductsData: [],
|
||||
setCompareProductsData: (x) => set({ compareProductsData: x }),
|
||||
}));
|
||||
|
||||
export const useDuplicatedCamData = create<{
|
||||
duplicatedCamData: {
|
||||
camPosition: [number, number, number];
|
||||
camTarget: [number, number, number];
|
||||
camRotation: [number, number, number];
|
||||
};
|
||||
setDuplicatedCamData: (
|
||||
camPosition: [number, number, number],
|
||||
camTarget: [number, number, number],
|
||||
camRotation: [number, number, number],
|
||||
) =>
|
||||
void;
|
||||
}>((set) => ({
|
||||
duplicatedCamData: {
|
||||
camPosition: [0, 0, 0],
|
||||
camTarget: [0, 0, 0],
|
||||
camRotation: [0, 0, 0],
|
||||
},
|
||||
setDuplicatedCamData: (
|
||||
camPosition: [number, number, number],
|
||||
camTarget: [number, number, number],
|
||||
camRotation: [number, number, number],
|
||||
) => set({
|
||||
duplicatedCamData: {
|
||||
camPosition: camPosition,
|
||||
camTarget: camTarget,
|
||||
camRotation: camRotation,
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
animation: slideInFromRight 0.4s ease-out forwards;
|
||||
user-select: none;
|
||||
border-left: 2px solid var(--border-color);
|
||||
pointer-events: none;
|
||||
|
||||
.resizer {
|
||||
width: 32px;
|
||||
|
@ -54,6 +55,7 @@
|
|||
cursor: ew-resize;
|
||||
transition: transform 0.1s ease;
|
||||
z-index: 100;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.chooseLayout-container {
|
||||
|
@ -82,6 +84,7 @@
|
|||
max-width: 80%;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
pointer-events: all;
|
||||
|
||||
.icon {
|
||||
width: 100%;
|
||||
|
@ -162,7 +165,9 @@
|
|||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--highlight-text-color) !important;
|
||||
background-color: var(
|
||||
--highlight-text-color
|
||||
) !important;
|
||||
border-radius: 4px;
|
||||
|
||||
.layout {
|
||||
|
@ -301,19 +306,21 @@
|
|||
background-color: #b7b7c6;
|
||||
|
||||
// Custom polygon shape (adjust if needed)
|
||||
clip-path: polygon(96% 52%,
|
||||
96% 54%,
|
||||
45% 53%,
|
||||
3% 100%,
|
||||
0 100%,
|
||||
42% 52%);
|
||||
clip-path: polygon(
|
||||
96% 52%,
|
||||
96% 54%,
|
||||
45% 53%,
|
||||
3% 100%,
|
||||
0 100%,
|
||||
42% 52%
|
||||
);
|
||||
|
||||
z-index: 0; // Behind any inner content
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: content above the shape
|
||||
>* {
|
||||
> * {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
@ -368,19 +375,21 @@
|
|||
height: 100%;
|
||||
|
||||
background: var(--background-color, wheat);
|
||||
clip-path: polygon(25% 0%,
|
||||
75% 0%,
|
||||
100% 50%,
|
||||
75% 100%,
|
||||
25% 100%,
|
||||
0% 50%);
|
||||
clip-path: polygon(
|
||||
25% 0%,
|
||||
75% 0%,
|
||||
100% 50%,
|
||||
75% 100%,
|
||||
25% 100%,
|
||||
0% 50%
|
||||
);
|
||||
filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.25));
|
||||
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
// Content stays above the shape
|
||||
>* {
|
||||
> * {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue