diff --git a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx index b99b297..5eb8d4e 100644 --- a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx @@ -3,13 +3,10 @@ import { useDroppedObjectsStore } from "../../../../store/useDroppedObjectsStore import useTemplateStore from "../../../../store/useTemplateStore"; import { useSelectedZoneStore } from "../../../../store/useZoneStore"; import { getTemplateData } from "../../../../services/realTimeVisulization/zoneData/getTemplate"; -import { deleteTemplateApi } from "../../../../services/realTimeVisulization/zoneData/deleteTemplate"; -import { loadTempleteApi } from "../../../../services/realTimeVisulization/zoneData/loadTemplate"; import { useSocketStore } from "../../../../store/store"; const Templates = () => { - const { templates, removeTemplate } = useTemplateStore(); - const { setTemplates } = useTemplateStore(); + const { templates, removeTemplate, setTemplates } = useTemplateStore(); const { setSelectedZone, selectedZone } = useSelectedZoneStore(); const { visualizationSocket } = useSocketStore(); @@ -35,15 +32,11 @@ const Templates = () => { let deleteTemplate = { organization: organization, templateID: id, - } + }; if (visualizationSocket) { - visualizationSocket.emit("v2:viz-template:deleteTemplate", deleteTemplate) + visualizationSocket.emit("v2:viz-template:deleteTemplate", deleteTemplate); } removeTemplate(id); - // let response = await deleteTemplateApi(id, organization); - - // if (response.message === "Template deleted successfully") { - // } } catch (error) { console.error("Error deleting template:", error); } @@ -60,114 +53,54 @@ const Templates = () => { organization: organization, zoneId: selectedZone.zoneId, templateID: template.id, - } - console.log('template: ', template); - console.log('loadingTemplate: ', loadingTemplate); + }; if (visualizationSocket) { - visualizationSocket.emit("v2:viz-template:addToZone", loadingTemplate) + visualizationSocket.emit("v2:viz-template:addToZone", loadingTemplate); } - // let response = await loadTempleteApi(template.id, selectedZone.zoneId, organization); - // if (response.message === "Template placed in Zone") { - setSelectedZone({ - panelOrder: template.panelOrder, - activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides` - widgets: template.widgets, + setSelectedZone({ + panelOrder: template.panelOrder, + activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides` + widgets: template.widgets, + }); + + useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId); + + if (Array.isArray(template.floatingWidget)) { + template.floatingWidget.forEach((val: any) => { + useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val); }); - - useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId); - - if (Array.isArray(template.floatingWidget)) { - template.floatingWidget.forEach((val: any) => { - useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val); - }); - } - // } + } } catch (error) { console.error("Error loading template:", error); } }; - return ( -
+
{templates.map((template) => ( -
+
{template?.snapshot && ( -
- {" "} - {/* 16:9 aspect ratio */} +
{`${template.name} handleLoadTemplate(template)} />
)} -
+
handleLoadTemplate(template)} - style={{ - cursor: "pointer", - fontWeight: "500", - // ':hover': { - // textDecoration: 'underline' - // } - }} + className="template-name" > {template.name}
))} {templates.length === 0 && ( -
+
No saved templates yet. Create one in the visualization view!
)} @@ -192,4 +118,3 @@ const Templates = () => { }; export default Templates; - diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx index 8c3df32..09c481a 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/WidgetsFloating.tsx @@ -46,7 +46,7 @@ const WidgetsFloating = () => { ))} */} {/* Floating 1 */} { const { activeModule } = useModuleStore(); @@ -42,9 +44,8 @@ const SideBarRight: React.FC = () => {
{/* {activeModule === "builder" && ( */}
setSubModule("properties")} > @@ -53,25 +54,22 @@ const SideBarRight: React.FC = () => { {activeModule === "simulation" && ( <>
setSubModule("mechanics")} >
setSubModule("simulations")} >
setSubModule("analysis")} > @@ -132,10 +130,28 @@ const SideBarRight: React.FC = () => {
)} + {subModule === "mechanics" && + selectedActionSphere && + selectedActionSphere.path.type === "StaticMachine" && ( +
+
+ +
+
+ )} + {subModule === "mechanics" && + selectedActionSphere && + selectedActionSphere.path.type === "ArmBot" && ( +
+
+ +
+
+ )} {subModule === "mechanics" && !selectedActionSphere && (
- + {/* default */}
)} diff --git a/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx new file mode 100644 index 0000000..744d555 --- /dev/null +++ b/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx @@ -0,0 +1,90 @@ +import React, { useRef, useMemo } from "react"; +import { InfoIcon } from "../../../icons/ExportCommonIcons"; +import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; +import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store"; +import * as Types from '../../../../types/world/worldTypes'; +import PositionInput from "../customInput/PositionInputs"; +import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt"; + +const ArmBotMechanics: React.FC = () => { + const { selectedActionSphere } = useSelectedActionSphere(); + const { simulationStates, setSimulationStates } = useSimulationStates(); + const { socket } = useSocketStore(); + + const propertiesContainerRef = useRef(null); + + const { selectedPoint, connectedPointUuids } = useMemo(() => { + if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] }; + + const vehiclePaths = simulationStates.filter( + (path): path is Types.ArmBotEventsSchema => path.type === "ArmBot" + ); + + const points = vehiclePaths.find( + (path) => path.points.uuid === selectedActionSphere.points.uuid + )?.points; + + if (!points) return { selectedPoint: null, connectedPointUuids: [] }; + + const connectedUuids: string[] = []; + if (points.connections?.targets) { + points.connections.targets.forEach(target => { + connectedUuids.push(target.pointUUID); + }); + } + + return { + selectedPoint: points, + connectedPointUuids: connectedUuids + }; + }, [selectedActionSphere, simulationStates]); + + const updateBackend = async (updatedPath: Types.ArmBotEventsSchema | undefined) => { + if (!updatedPath) return; + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : ""; + + // await setEventApi( + // organization, + // updatedPath.modeluuid, + // { type: "ArmBot", points: updatedPath.points } + // ); + + const data = { + organization: organization, + modeluuid: updatedPath.modeluuid, + eventData: { type: "ArmBot", points: updatedPath.points } + } + + socket.emit('v2:model-asset:updateEventData', data); + + } + + + return ( +
+
+ {selectedActionSphere?.path?.modelName || "ArmBot point not found"} +
+ +
+
+
ArmBot Properties
+ + {selectedPoint && ( + <> + + + )} +
+ +
+ + Configure armbot properties. +
+
+
+ ); +}; + +export default React.memo(ArmBotMechanics); \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx index fd64db9..6c7487e 100644 --- a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx @@ -1,20 +1,20 @@ import React, { useRef, useState, useMemo, useEffect } from "react"; import { - AddIcon, - InfoIcon, - RemoveIcon, - ResizeHeightIcon, + AddIcon, + InfoIcon, + RemoveIcon, + ResizeHeightIcon, } from "../../../icons/ExportCommonIcons"; import RenameInput from "../../../ui/inputs/RenameInput"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; import LabledDropdown from "../../../ui/inputs/LabledDropdown"; import { handleResize } from "../../../../functions/handleResizePannel"; import { - useFloorItems, - useSelectedActionSphere, - useSelectedPath, - useSimulationStates, - useSocketStore, + useFloorItems, + useSelectedActionSphere, + useSelectedPath, + useSimulationStates, + useSocketStore, } from "../../../../store/store"; import * as THREE from "three"; import * as Types from "../../../../types/world/worldTypes"; @@ -23,859 +23,857 @@ import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floo import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt"; const ConveyorMechanics: React.FC = () => { - const { selectedActionSphere } = useSelectedActionSphere(); - const { selectedPath, setSelectedPath } = useSelectedPath(); - const { simulationStates, setSimulationStates } = useSimulationStates(); - const { floorItems, setFloorItems } = useFloorItems(); - const { socket } = useSocketStore(); + const { selectedActionSphere } = useSelectedActionSphere(); + const { selectedPath, setSelectedPath } = useSelectedPath(); + const { simulationStates, setSimulationStates } = useSimulationStates(); + const { floorItems, setFloorItems } = useFloorItems(); + const { socket } = useSocketStore(); - const actionsContainerRef = useRef(null); - const triggersContainerRef = useRef(null); + const actionsContainerRef = useRef(null); + const triggersContainerRef = useRef(null); - const selectedPoint = useMemo(() => { - if (!selectedActionSphere) return null; - return simulationStates - .filter( - (path): path is Types.ConveyorEventsSchema => path.type === "Conveyor" - ) - .flatMap((path) => path.points) - .find((point) => point.uuid === selectedActionSphere.points.uuid); - }, [selectedActionSphere, simulationStates]); + const selectedPoint = useMemo(() => { + if (!selectedActionSphere) return null; + return simulationStates + .filter( + (path): path is Types.ConveyorEventsSchema => path.type === "Conveyor" + ) + .flatMap((path) => path.points) + .find((point) => point.uuid === selectedActionSphere.points.uuid); + }, [selectedActionSphere, simulationStates]); - const updateBackend = async (updatedPath: Types.ConveyorEventsSchema | undefined) => { - if (!updatedPath) return; - const email = localStorage.getItem("email"); - const organization = email ? email.split("@")[1].split(".")[0] : ""; + const updateBackend = async (updatedPath: Types.ConveyorEventsSchema | undefined) => { + if (!updatedPath) return; + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : ""; - // await setEventApi( - // organization, - // updatedPath.modeluuid, - // { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed } - // ); + // await setEventApi( + // organization, + // updatedPath.modeluuid, + // { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed } + // ); + + const data = { + organization: organization, + modeluuid: updatedPath.modeluuid, + eventData: { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed } + } + + socket.emit('v2:model-asset:updateEventData', data); - const data = { - organization: organization, - modeluuid: updatedPath.modeluuid, - eventData: { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed } } - socket.emit('v2:model-asset:updateEventData', data); + const handleAddAction = () => { + if (!selectedActionSphere) return; - } + const updatedPaths = simulationStates.map((path) => { + if (path.type === "Conveyor") { + return { + ...path, + points: path.points.map((point) => { + if (point.uuid === selectedActionSphere.points.uuid) { + const actionIndex = point.actions.length; + const newAction = { + uuid: THREE.MathUtils.generateUUID(), + name: `Action ${actionIndex + 1}`, + type: "Inherit", + material: "Inherit", + delay: "Inherit", + spawnInterval: "Inherit", + isUsed: false, + }; - const handleAddAction = () => { - if (!selectedActionSphere) return; - - const updatedPaths = simulationStates.map((path) => { - if (path.type === "Conveyor") { - return { - ...path, - points: path.points.map((point) => { - if (point.uuid === selectedActionSphere.points.uuid) { - const actionIndex = point.actions.length; - const newAction = { - uuid: THREE.MathUtils.generateUUID(), - name: `Action ${actionIndex + 1}`, - type: "Inherit", - material: "Inherit", - delay: "Inherit", - spawnInterval: "Inherit", - isUsed: false, - }; - - return { ...point, actions: [...point.actions, newAction] }; + return { ...point, actions: [...point.actions, newAction] }; + } + return point; + }), + }; } - return point; - }), - }; - } - return path; - }); - - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); - - setSimulationStates(updatedPaths); - }; - - const handleDeleteAction = (uuid: string) => { - if (!selectedActionSphere) return; - - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - actions: point.actions.filter( - (action) => action.uuid !== uuid - ), - } - : point - ), - } - : path - ); - - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); - - setSimulationStates(updatedPaths); - }; - - const handleActionSelect = (uuid: string, actionType: string) => { - if (!selectedActionSphere) return; - - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - actions: point.actions.map((action) => - action.uuid === uuid - ? { - ...action, - type: actionType, - material: - actionType === "Spawn" || actionType === "Swap" - ? "Inherit" - : action.material, - delay: - actionType === "Delay" ? "Inherit" : action.delay, - spawnInterval: - actionType === "Spawn" - ? "Inherit" - : action.spawnInterval, - } - : action - ), - } - : point - ), - } - : path - ); - - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); - - setSimulationStates(updatedPaths); - - // Update the selected item to reflect changes - if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { - const updatedAction = updatedPaths - .filter( - (path): path is Types.ConveyorEventsSchema => path.type === "Conveyor" - ) - .flatMap((path) => path.points) - .find((p) => p.uuid === selectedActionSphere.points.uuid) - ?.actions.find((a) => a.uuid === uuid); - - if (updatedAction) { - setSelectedItem({ - type: "action", - item: updatedAction, + return path; }); - } - } - }; - // Modified handleMaterialSelect to ensure it only applies to relevant action types - const handleMaterialSelect = (uuid: string, material: string) => { - if (!selectedActionSphere) return; + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - actions: point.actions.map((action) => - action.uuid === uuid && - (action.type === "Spawn" || action.type === "Swap") - ? { ...action, material } - : action - ), - } - : point - ), - } - : path - ); + setSimulationStates(updatedPaths); + }; - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); + const handleDeleteAction = (uuid: string) => { + if (!selectedActionSphere) return; - setSimulationStates(updatedPaths); + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + actions: point.actions.filter( + (action) => action.uuid !== uuid + ), + } + : point + ), + } + : path + ); - // Update selected item if it's the current action - if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { - setSelectedItem({ - ...selectedItem, - item: { - ...selectedItem.item, - material, - }, - }); - } - }; + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); - const handleDelayChange = (uuid: string, delay: number | string) => { - if (!selectedActionSphere) return; + setSimulationStates(updatedPaths); + }; - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - actions: point.actions.map((action) => - action.uuid === uuid ? { ...action, delay } : action - ), - } - : point - ), - } - : path - ); + const handleActionSelect = (uuid: string, actionType: string) => { + if (!selectedActionSphere) return; - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + actions: point.actions.map((action) => + action.uuid === uuid + ? { + ...action, + type: actionType, + material: + actionType === "Spawn" || actionType === "Swap" + ? "Inherit" + : action.material, + delay: + actionType === "Delay" ? "Inherit" : action.delay, + spawnInterval: + actionType === "Spawn" + ? "Inherit" + : action.spawnInterval, + } + : action + ), + } + : point + ), + } + : path + ); - setSimulationStates(updatedPaths); - }; + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); - const handleSpawnIntervalChange = ( - uuid: string, - spawnInterval: number | string - ) => { - if (!selectedActionSphere) return; + setSimulationStates(updatedPaths); - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - actions: point.actions.map((action) => - action.uuid === uuid - ? { ...action, spawnInterval } - : action - ), - } - : point - ), - } - : path - ); + // Update the selected item to reflect changes + if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { + const updatedAction = updatedPaths + .filter( + (path): path is Types.ConveyorEventsSchema => path.type === "Conveyor" + ) + .flatMap((path) => path.points) + .find((p) => p.uuid === selectedActionSphere.points.uuid) + ?.actions.find((a) => a.uuid === uuid); - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); - - setSimulationStates(updatedPaths); - }; - - const handleSpeedChange = (speed: number | string) => { - if (!selectedPath) return; - - const updatedPaths = simulationStates.map((path) => - path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path - ); - - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); - - setSimulationStates(updatedPaths); - setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } }); - }; - - const handleAddTrigger = () => { - if (!selectedActionSphere) return; - - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => { - if (point.uuid === selectedActionSphere.points.uuid) { - const triggerIndex = point.triggers.length; - const newTrigger = { - uuid: THREE.MathUtils.generateUUID(), - name: `Trigger ${triggerIndex + 1}`, - type: "", - bufferTime: 0, - isUsed: false, - }; - - return { ...point, triggers: [...point.triggers, newTrigger] }; + if (updatedAction) { + setSelectedItem({ + type: "action", + item: updatedAction, + }); } - return point; - }), } - : path - ); + }; - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); + // Modified handleMaterialSelect to ensure it only applies to relevant action types + const handleMaterialSelect = (uuid: string, material: string) => { + if (!selectedActionSphere) return; - setSimulationStates(updatedPaths); - }; + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + actions: point.actions.map((action) => + action.uuid === uuid && + (action.type === "Spawn" || action.type === "Swap") + ? { ...action, material } + : action + ), + } + : point + ), + } + : path + ); - const handleDeleteTrigger = (uuid: string) => { - if (!selectedActionSphere) return; + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - triggers: point.triggers.filter( - (trigger) => trigger.uuid !== uuid - ), - } - : point - ), + setSimulationStates(updatedPaths); + + // Update selected item if it's the current action + if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { + setSelectedItem({ + ...selectedItem, + item: { + ...selectedItem.item, + material, + }, + }); } - : path - ); + }; - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); + const handleDelayChange = (uuid: string, delay: number | string) => { + if (!selectedActionSphere) return; - setSimulationStates(updatedPaths); - }; + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + actions: point.actions.map((action) => + action.uuid === uuid ? { ...action, delay } : action + ), + } + : point + ), + } + : path + ); - const handleTriggerSelect = (uuid: string, triggerType: string) => { - if (!selectedActionSphere) return; + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - triggers: point.triggers.map((trigger) => - trigger.uuid === uuid - ? { ...trigger, type: triggerType } - : trigger - ), - } - : point - ), - } - : path - ); + setSimulationStates(updatedPaths); + }; - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); + const handleSpawnIntervalChange = ( + uuid: string, + spawnInterval: number | string + ) => { + if (!selectedActionSphere) return; - setSimulationStates(updatedPaths); + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + actions: point.actions.map((action) => + action.uuid === uuid + ? { ...action, spawnInterval } + : action + ), + } + : point + ), + } + : path + ); - // Ensure the selectedItem is updated immediately - const updatedTrigger = updatedPaths - .flatMap((path) => (path.type === "Conveyor" ? path.points : [])) - .flatMap((point) => point.triggers) - .find((trigger) => trigger.uuid === uuid); + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); - if (updatedTrigger) { - setSelectedItem({ type: "trigger", item: updatedTrigger }); - } - }; + setSimulationStates(updatedPaths); + }; - // Update the toggle handlers to immediately update the selected item - const handleActionToggle = (uuid: string) => { - if (!selectedActionSphere) return; - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - actions: point.actions.map((action) => ({ - ...action, - isUsed: action.uuid === uuid ? !action.isUsed : false, - })), - } - : point - ), - } - : path - ); + const handleSpeedChange = (speed: number | string) => { + if (!selectedPath) return; - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); + const updatedPaths = simulationStates.map((path) => + path.modeluuid === selectedPath.path.modeluuid ? { ...path, speed } : path + ); - setSimulationStates(updatedPaths); + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.modeluuid === selectedPath.path.modeluuid + ); + updateBackend(updatedPath); - // Immediately update the selected item if it's the one being toggled - if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { - setSelectedItem({ - ...selectedItem, - item: { - ...selectedItem.item, - isUsed: !selectedItem.item.isUsed, - }, - }); - } - }; + setSimulationStates(updatedPaths); + setSelectedPath({ ...selectedPath, path: { ...selectedPath.path, speed } }); + }; - // Do the same for trigger toggle - const handleTriggerToggle = (uuid: string) => { - if (!selectedActionSphere) return; + const handleAddTrigger = () => { + if (!selectedActionSphere) return; - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - triggers: point.triggers.map((trigger) => ({ - ...trigger, - isUsed: trigger.uuid === uuid ? !trigger.isUsed : false, - })), - } - : point - ), - } - : path - ); + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => { + if (point.uuid === selectedActionSphere.points.uuid) { + const triggerIndex = point.triggers.length; + const newTrigger = { + uuid: THREE.MathUtils.generateUUID(), + name: `Trigger ${triggerIndex + 1}`, + type: "", + bufferTime: 0, + isUsed: false, + }; - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); - - setSimulationStates(updatedPaths); - - // Immediately update the selected item if it's the one being toggled - if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) { - setSelectedItem({ - ...selectedItem, - item: { - ...selectedItem.item, - isUsed: !selectedItem.item.isUsed, - }, - }); - } - }; - - const handleTriggerBufferTimeChange = (uuid: string, bufferTime: number) => { - if (!selectedActionSphere) return; - - const updatedPaths = simulationStates.map((path) => - path.type === "Conveyor" - ? { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.points.uuid - ? { - ...point, - triggers: point.triggers.map((trigger) => - trigger.uuid === uuid - ? { ...trigger, bufferTime } - : trigger - ), - } - : point - ), - } - : path - ); - - const updatedPath = updatedPaths.find( - (path): path is Types.ConveyorEventsSchema => - path.type === "Conveyor" && - path.points.some( - (point) => point.uuid === selectedActionSphere.points.uuid - ) - ); - updateBackend(updatedPath); - - setSimulationStates(updatedPaths); - - // Immediately update selectedItem if it's the currently selected trigger - if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) { - setSelectedItem({ - ...selectedItem, - item: { - ...selectedItem.item, - bufferTime, - }, - }); - } - }; - - const [selectedItem, setSelectedItem] = useState<{ - type: "action" | "trigger"; - item: any; - } | null>(null); - - useEffect(() => { - setSelectedItem(null); - }, [selectedActionSphere]); - - return ( -
- {!selectedPath && ( -
- {selectedActionSphere?.path?.modelName || "point name not found"} -
- )} - - {selectedPath && ( -
- {selectedPath.path.modelName || "path name not found"} -
- )} - -
- {!selectedPath && ( - <> -
-
-
Actions
-
- Add -
-
-
-
- {selectedPoint?.actions.map((action) => ( -
-
- setSelectedItem({ type: "action", item: action }) + return { ...point, triggers: [...point.triggers, newTrigger] }; } - > - - -
-
handleDeleteAction(action.uuid)} - > - -
-
- ))} -
-
handleResize(e, actionsContainerRef)} - > - -
-
-
-
-
-
Triggers
-
- Add -
-
-
-
- {selectedPoint?.triggers.map((trigger) => ( -
-
- setSelectedItem({ type: "trigger", item: trigger }) - } - > - - -
-
handleDeleteTrigger(trigger.uuid)} - > - -
-
- ))} -
-
handleResize(e, triggersContainerRef)} - > - -
-
-
- - )} + return point; + }), + } + : path + ); -
- {selectedItem && ( - <> -
{selectedItem.item.name}
+ const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); - {selectedItem.type === "action" && ( - <> - handleActionToggle(selectedItem.item.uuid)} - /> - - handleActionSelect(selectedItem.item.uuid, option) - } - /> + setSimulationStates(updatedPaths); + }; - {/* Only show material dropdown for Spawn/Swap actions */} - {(selectedItem.item.type === "Spawn" || - selectedItem.item.type === "Swap") && ( - - handleMaterialSelect(selectedItem.item.uuid, option) - } - /> + const handleDeleteTrigger = (uuid: string) => { + if (!selectedActionSphere) return; + + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + triggers: point.triggers.filter( + (trigger) => trigger.uuid !== uuid + ), + } + : point + ), + } + : path + ); + + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); + + setSimulationStates(updatedPaths); + }; + + const handleTriggerSelect = (uuid: string, triggerType: string) => { + if (!selectedActionSphere) return; + + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + triggers: point.triggers.map((trigger) => + trigger.uuid === uuid + ? { ...trigger, type: triggerType } + : trigger + ), + } + : point + ), + } + : path + ); + + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); + + setSimulationStates(updatedPaths); + + // Ensure the selectedItem is updated immediately + const updatedTrigger = updatedPaths + .flatMap((path) => (path.type === "Conveyor" ? path.points : [])) + .flatMap((point) => point.triggers) + .find((trigger) => trigger.uuid === uuid); + + if (updatedTrigger) { + setSelectedItem({ type: "trigger", item: updatedTrigger }); + } + }; + + // Update the toggle handlers to immediately update the selected item + const handleActionToggle = (uuid: string) => { + if (!selectedActionSphere) return; + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + actions: point.actions.map((action) => ({ + ...action, + isUsed: action.uuid === uuid ? !action.isUsed : false, + })), + } + : point + ), + } + : path + ); + + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); + + setSimulationStates(updatedPaths); + + // Immediately update the selected item if it's the one being toggled + if (selectedItem?.type === "action" && selectedItem.item.uuid === uuid) { + setSelectedItem({ + ...selectedItem, + item: { + ...selectedItem.item, + isUsed: !selectedItem.item.isUsed, + }, + }); + } + }; + + // Do the same for trigger toggle + const handleTriggerToggle = (uuid: string) => { + if (!selectedActionSphere) return; + + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + triggers: point.triggers.map((trigger) => ({ + ...trigger, + isUsed: trigger.uuid === uuid ? !trigger.isUsed : false, + })), + } + : point + ), + } + : path + ); + + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); + + setSimulationStates(updatedPaths); + + // Immediately update the selected item if it's the one being toggled + if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) { + setSelectedItem({ + ...selectedItem, + item: { + ...selectedItem.item, + isUsed: !selectedItem.item.isUsed, + }, + }); + } + }; + + const handleTriggerBufferTimeChange = (uuid: string, bufferTime: number) => { + if (!selectedActionSphere) return; + + const updatedPaths = simulationStates.map((path) => + path.type === "Conveyor" + ? { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.points.uuid + ? { + ...point, + triggers: point.triggers.map((trigger) => + trigger.uuid === uuid + ? { ...trigger, bufferTime } + : trigger + ), + } + : point + ), + } + : path + ); + + const updatedPath = updatedPaths.find( + (path): path is Types.ConveyorEventsSchema => + path.type === "Conveyor" && + path.points.some( + (point) => point.uuid === selectedActionSphere.points.uuid + ) + ); + updateBackend(updatedPath); + + setSimulationStates(updatedPaths); + + // Immediately update selectedItem if it's the currently selected trigger + if (selectedItem?.type === "trigger" && selectedItem.item.uuid === uuid) { + setSelectedItem({ + ...selectedItem, + item: { + ...selectedItem.item, + bufferTime, + }, + }); + } + }; + + const [selectedItem, setSelectedItem] = useState<{ + type: "action" | "trigger"; + item: any; + } | null>(null); + + useEffect(() => { + setSelectedItem(null); + }, [selectedActionSphere]); + + return ( +
+ {!selectedPath && ( +
+ {selectedActionSphere?.path?.modelName || "point name not found"} +
+ )} + + {selectedPath && ( +
+ {selectedPath.path.modelName || "path name not found"} +
+ )} + +
+ {!selectedPath && ( + <> +
+
+
Actions
+
+ Add +
+
+
+
+ {selectedPoint?.actions.map((action) => ( +
+
+ setSelectedItem({ type: "action", item: action }) + } + > + + +
+
handleDeleteAction(action.uuid)} + > + +
+
+ ))} +
+
handleResize(e, actionsContainerRef)} + > + +
+
+
+
+
+
Triggers
+
+ Add +
+
+
+
+ {selectedPoint?.triggers.map((trigger) => ( +
+
+ setSelectedItem({ type: "trigger", item: trigger }) + } + > + + +
+
handleDeleteTrigger(trigger.uuid)} + > + +
+
+ ))} +
+
handleResize(e, triggersContainerRef)} + > + +
+
+
+ + )} + +
+ {selectedItem && ( + <> +
{selectedItem.item.name}
+ + {selectedItem.type === "action" && ( + <> + handleActionToggle(selectedItem.item.uuid)} + /> + + handleActionSelect(selectedItem.item.uuid, option) + } + /> + + {/* Only show material dropdown for Spawn/Swap actions */} + {(selectedItem.item.type === "Spawn" || + selectedItem.item.type === "Swap") && ( + + handleMaterialSelect(selectedItem.item.uuid, option) + } + /> + )} + + {/* Only show delay input for Delay actions */} + {selectedItem.item.type === "Delay" && ( + { + const numValue = parseInt(value); + handleDelayChange( + selectedItem.item.uuid, + !value ? "Inherit" : numValue + ); + }} + /> + )} + + {/* Only show spawn interval for Spawn actions */} + {selectedItem.item.type === "Spawn" && ( + { + handleSpawnIntervalChange( + selectedItem.item.uuid, + value === "" ? "Inherit" : parseInt(value) + ); + }} + /> + )} + + )} + + {selectedItem.type === "trigger" && ( + <> + handleTriggerToggle(selectedItem.item.uuid)} + /> + + + handleTriggerSelect(selectedItem.item.uuid, option) + } + /> + + {selectedItem.item.type === "Buffer" && ( + { + handleTriggerBufferTimeChange( + selectedItem.item.uuid, + parseInt(value) + ); + }} + /> + )} + + )} + )} - {/* Only show delay input for Delay actions */} - {selectedItem.item.type === "Delay" && ( - { - const numValue = parseInt(value); - handleDelayChange( - selectedItem.item.uuid, - !value ? "Inherit" : numValue - ); - }} - /> - )} - - {/* Only show spawn interval for Spawn actions */} - {selectedItem.item.type === "Spawn" && ( - { - handleSpawnIntervalChange( - selectedItem.item.uuid, - value === "" ? "Inherit" : parseInt(value) - ); - }} - /> - )} - - )} - - {selectedItem.type === "trigger" && ( - <> - handleTriggerToggle(selectedItem.item.uuid)} - /> - - - handleTriggerSelect(selectedItem.item.uuid, option) - } - /> - - {selectedItem.item.type === "Buffer" && ( - { - handleTriggerBufferTimeChange( - selectedItem.item.uuid, - parseInt(value) - ); - }} - /> - )} - - )} - - )} - - {selectedPath && !selectedItem && ( -
- - handleSpeedChange(value === "" ? "Inherit" : parseInt(value)) - } - /> + {selectedPath && !selectedItem && ( +
+ + handleSpeedChange(value === "" ? "Inherit" : parseInt(value)) + } + /> +
+ )} +
+ {!selectedPath && ( +
+ + Configure the point's action and trigger properties. +
+ )} + {selectedPath && ( +
+ + Configure the path properties. +
+ )}
- )}
- {!selectedPath && ( -
- - Configure the point's action and trigger properties. -
- )} - {selectedPath && ( -
- - Configure the path properties. -
- )} -
-
- ); + ); }; export default ConveyorMechanics; diff --git a/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx new file mode 100644 index 0000000..254753e --- /dev/null +++ b/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx @@ -0,0 +1,90 @@ +import React, { useRef, useMemo } from "react"; +import { InfoIcon } from "../../../icons/ExportCommonIcons"; +import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; +import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store"; +import * as Types from '../../../../types/world/worldTypes'; +import PositionInput from "../customInput/PositionInputs"; +import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt"; + +const StaticMachineMechanics: React.FC = () => { + const { selectedActionSphere } = useSelectedActionSphere(); + const { simulationStates, setSimulationStates } = useSimulationStates(); + const { socket } = useSocketStore(); + + const propertiesContainerRef = useRef(null); + + const { selectedPoint, connectedPointUuids } = useMemo(() => { + if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] }; + + const vehiclePaths = simulationStates.filter( + (path): path is Types.StaticMachineEventsSchema => path.type === "StaticMachine" + ); + + const points = vehiclePaths.find( + (path) => path.points.uuid === selectedActionSphere.points.uuid + )?.points; + + if (!points) return { selectedPoint: null, connectedPointUuids: [] }; + + const connectedUuids: string[] = []; + if (points.connections?.targets) { + points.connections.targets.forEach(target => { + connectedUuids.push(target.pointUUID); + }); + } + + return { + selectedPoint: points, + connectedPointUuids: connectedUuids + }; + }, [selectedActionSphere, simulationStates]); + + const updateBackend = async (updatedPath: Types.StaticMachineEventsSchema | undefined) => { + if (!updatedPath) return; + const email = localStorage.getItem("email"); + const organization = email ? email.split("@")[1].split(".")[0] : ""; + + // await setEventApi( + // organization, + // updatedPath.modeluuid, + // { type: "StaticMachine", points: updatedPath.points } + // ); + + const data = { + organization: organization, + modeluuid: updatedPath.modeluuid, + eventData: { type: "StaticMachine", points: updatedPath.points } + } + + socket.emit('v2:model-asset:updateEventData', data); + + } + + + return ( +
+
+ {selectedActionSphere?.path?.modelName || "Machine point not found"} +
+ +
+
+
Machine Properties
+ + {selectedPoint && ( + <> + + + )} +
+ +
+ + Configure machine properties. +
+
+
+ ); +}; + +export default React.memo(StaticMachineMechanics); \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index 9e8b37e..ce399b4 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -28,9 +28,12 @@ const ZoneProperties: React.FC = () => { }; let response = await zoneCameraUpdate(zonesdata, organization); - console.log('response: ', response); + if (response.message === "updated successfully") { + setEdit(false); + } else { + console.log("Not updated Camera Position and Target"); + } - setEdit(false); } catch (error) { console.error("Error in handleSetView:", error); } diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 3de44bf..b704241 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -35,6 +35,7 @@ import { import useToggleStore from "../../store/useUIToggleStore"; import { use3DWidget, + useDroppedObjectsStore, useFloatingWidget, } from "../../store/useDroppedObjectsStore"; @@ -52,8 +53,12 @@ const Tools: React.FC = () => { const { addTemplate } = useTemplateStore(); const { selectedZone } = useSelectedZoneStore(); const { floatingWidget } = useFloatingWidget(); + const { widgets3D } = use3DWidget(); + const zones = useDroppedObjectsStore((state) => state.zones); + + // wall options const { toggleView, setToggleView } = useToggleView(); const { setDeleteModels } = useDeleteModels(); @@ -409,10 +414,9 @@ const Tools: React.FC = () => { widgets3D, selectedZone, templates, - visualizationSocket - }) - } - } + visualizationSocket, + }); + }} >
diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index 80a88df..6527414 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -65,6 +65,8 @@ const AddButtons: React.FC = ({ // Function to toggle lock/unlock a panel const toggleLockPanel = (side: Side) => { + console.log('side: ', side); + //add api const newLockedPanels = selectedZone.lockedPanels.includes(side) ? selectedZone.lockedPanels.filter((panel) => panel !== side) : [...selectedZone.lockedPanels, side]; @@ -92,6 +94,8 @@ const AddButtons: React.FC = ({ // Function to clean all widgets from a panel const cleanPanel = (side: Side) => { + //add api + console.log('side: ', side); const cleanedWidgets = selectedZone.widgets.filter( (widget) => widget.panel !== side ); @@ -100,7 +104,6 @@ const AddButtons: React.FC = ({ ...selectedZone, widgets: cleanedWidgets, }; - // Update the selectedZone state setSelectedZone(updatedZone); }; diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index 0890e5c..03fd44f 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -74,6 +74,7 @@ const DisplayZone: React.FC = ({ const [showLeftArrow, setShowLeftArrow] = useState(false); const [showRightArrow, setShowRightArrow] = useState(false); const { floatingWidget, setFloatingWidget } = useFloatingWidget() + const{setSelectedChartId}=useWidgetStore() // Function to calculate overflow state @@ -178,7 +179,7 @@ const DisplayZone: React.FC = ({ zoneViewPortPosition: response.viewPortposition || {}, }); } catch (error) { - console.error(error); + } } diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx index fbb376f..09a54e1 100644 --- a/app/src/components/ui/componets/DraggableWidget.tsx +++ b/app/src/components/ui/componets/DraggableWidget.tsx @@ -18,6 +18,7 @@ import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData import { useClickOutside } from "./functions/handleWidgetsOuterClick"; import { useSocketStore } from "../../../store/store"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; +import OuterClick from "../../../utils/outerClick"; type Side = "top" | "bottom" | "left" | "right"; @@ -89,6 +90,11 @@ export const DraggableWidget = ({ const isPanelHidden = hiddenPanels.includes(widget.panel); + OuterClick({ + contextClassName: ["chart-container", "floating", "sidebar-right-wrapper"], + setMenuVisible: () => setSelectedChartId(null), + }); + const deleteSelectedChart = async () => { try { const email = localStorage.getItem("email") || ""; @@ -251,36 +257,35 @@ export const DraggableWidget = ({ }); // Track canvas dimensions - + // Current: Two identical useEffect hooks for canvas dimensions + // Remove the duplicate and keep only one + useEffect(() => { + const canvas = document.getElementById("real-time-vis-canvas"); + if (!canvas) return; -// Current: Two identical useEffect hooks for canvas dimensions -// Remove the duplicate and keep only one -useEffect(() => { - const canvas = document.getElementById("real-time-vis-canvas"); - if (!canvas) return; + const updateCanvasDimensions = () => { + const rect = canvas.getBoundingClientRect(); + setCanvasDimensions({ + width: rect.width, + height: rect.height, + }); + }; - const updateCanvasDimensions = () => { - const rect = canvas.getBoundingClientRect(); - setCanvasDimensions({ - width: rect.width, - height: rect.height, - }); - }; + updateCanvasDimensions(); + const resizeObserver = new ResizeObserver(updateCanvasDimensions); + resizeObserver.observe(canvas); - updateCanvasDimensions(); - const resizeObserver = new ResizeObserver(updateCanvasDimensions); - resizeObserver.observe(canvas); - - return () => resizeObserver.unobserve(canvas); -}, []); + return () => resizeObserver.unobserve(canvas); + }, []); return ( <> @@ -296,13 +301,12 @@ useEffect(() => { onDragOver={handleDragOver} onDrop={handleDrop} style={{ - // Apply styles based on panel position width: ["top", "bottom"].includes(widget.panel) - ? `calc(${canvasDimensions.width * 0.16}px - 2px)` // For top/bottom panels, set width - : undefined, // Don't set width if it's left or right + ? `calc(${canvasDimensions.width}px / 6)` + : undefined, height: ["left", "right"].includes(widget.panel) - ? `calc(${canvasDimensions.height * 0.25}px - 2px)` // For left/right panels, set height - : undefined, // Don't set height if it's top or bottom + ? `calc(${canvasDimensions.height - 10}px / 4)` + : undefined, }} ref={chartWidget} onClick={() => setSelectedChartId(widget)} @@ -393,4 +397,4 @@ useEffect(() => { ); }; -// while resize calculate --realTimeViz-container-height pprperly \ No newline at end of file + diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index d870195..f03dea8 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -44,9 +44,7 @@ export default function Dropped3dWidgets() { const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Floor plane for horizontal move const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move const planeIntersect = useRef(new THREE.Vector3()); - // const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0); - // const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); - // const planeIntersect = useRef(new THREE.Vector3()); + const rotationStartRef = useRef<[number, number, number]>([0, 0, 0]); const mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); @@ -60,7 +58,7 @@ export default function Dropped3dWidgets() { async function get3dWidgetData() { const result = await get3dWidgetZoneData(selectedZone.zoneId, organization); - console.log('result: ', result); + setWidgets3D(result); const formattedWidgets = result.map((widget: WidgetData) => ({ @@ -84,8 +82,31 @@ export default function Dropped3dWidgets() { const canvasElement = gl.domElement; + const handleDragEnter = (event: DragEvent) => { + event.preventDefault(); + event.stopPropagation(); + console.log("Drag enter"); + + }; + + const handleDragOver = (event: DragEvent) => { + event.preventDefault(); + event.stopPropagation(); + + }; + + const handleDragLeave = (event: DragEvent) => { + event.preventDefault(); + event.stopPropagation(); + console.log("Drag leave"); + // Remove visual feedback + canvasElement.style.cursor = ""; + }; + const onDrop = async (event: DragEvent) => { event.preventDefault(); + event.stopPropagation(); + canvasElement.style.cursor = ""; // Reset cursor const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; @@ -93,6 +114,12 @@ export default function Dropped3dWidgets() { const group1 = scene.getObjectByName("itemsGroup"); if (!group1) return; + // Update raycaster with current mouse position + const rect = canvasElement.getBoundingClientRect(); + mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; + mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; + raycaster.setFromCamera(mouse, camera); + const intersects = raycaster.intersectObjects(scene.children, true).filter( (intersect) => !intersect.object.name.includes("Roof") && @@ -125,12 +152,21 @@ export default function Dropped3dWidgets() { } }; + // Add all event listeners + // canvasElement.addEventListener("dragenter", handleDragEnter); + // canvasElement.addEventListener("dragover", handleDragOver); + // canvasElement.addEventListener("dragleave", handleDragLeave); canvasElement.addEventListener("drop", onDrop); - return () => { - canvasElement.removeEventListener("drop", onDrop); - }; - }, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]); + return () => { + // // Clean up all event listeners + // canvasElement.removeEventListener("dragenter", handleDragEnter); + // canvasElement.removeEventListener("dragover", handleDragOver); + // canvasElement.removeEventListener("dragleave", handleDragLeave); + canvasElement.removeEventListener("drop", onDrop); + canvasElement.style.cursor = ""; // Ensure cursor is reset + }; + }, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption, gl.domElement, scene, raycaster, camera]); const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; useEffect(() => { @@ -161,7 +197,7 @@ export default function Dropped3dWidgets() { visualizationSocket.emit("v2:viz-3D-widget:add", adding3dWidget); } // let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget) - // console.log('response: ', response); + // addWidget(selectedZone.zoneId, newWidget); setRightSelect(null); @@ -179,7 +215,7 @@ export default function Dropped3dWidgets() { zoneId: selectedZone.zoneId, }; - console.log('deleteWidget: ', deleteWidget); + if (visualizationSocket) { visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget); } @@ -190,7 +226,7 @@ export default function Dropped3dWidgets() { activeZoneWidgets.filter((w: WidgetData) => w.id !== rightClickSelected) ); } catch (error) { - console.error("Error deleting widget:", error); + } finally { setRightClickSelected(null); setRightSelect(null); @@ -304,20 +340,15 @@ export default function Dropped3dWidgets() { const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected); if (!selectedWidget) return; - - - // Format values to 2 decimal places const formatValues = (vals: number[]) => vals.map(val => parseFloat(val.toFixed(2))); - if (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move") { - console.log(`${rightSelect} Completed - Full Position:`, formatValues(selectedWidget.position)); let lastPosition = formatValues(selectedWidget.position) as [number, number, number]; // (async () => { // let response = await update3dWidget(selectedZone, organization, rightClickSelected, lastPosition); - // console.log('response: ', response); + // // if (response) { - // console.log("Widget position updated in API:", response); + // // } // })(); let updatingPosition = { @@ -333,13 +364,13 @@ export default function Dropped3dWidgets() { } else if (rightSelect.includes("Rotate")) { const rotation = selectedWidget.rotation || [0, 0, 0]; - console.log(`${rightSelect} Completed - Full Rotation:`, formatValues(rotation)); + let lastRotation = formatValues(rotation) as [number, number, number]; // (async () => { // let response = await update3dWidgetRotation(selectedZone, organization, rightClickSelected, lastRotation); - // console.log('response: ', response); + // // if (response) { - // console.log("Widget position updated in API:", response); + // // } // })(); let updatingRotation = { @@ -388,49 +419,13 @@ export default function Dropped3dWidgets() { switch (type) { case "ui-Widget 1": - return ( - handleRightClick(e, id)} - /> - ); + return ( handleRightClick(e, id)} />); case "ui-Widget 2": - return ( - handleRightClick(e, id)} - /> - ); + return ( handleRightClick(e, id)} />); case "ui-Widget 3": - return ( - handleRightClick(e, id)} - /> - ); + return ( handleRightClick(e, id)} />); case "ui-Widget 4": - return ( - handleRightClick(e, id)} - /> - ); + return ( handleRightClick(e, id)} />); default: return null; } diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index 4652ec1..bd707f4 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -126,12 +126,11 @@ const DroppedObjects: React.FC = () => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - let deleteFloatingWidget = { floatWidgetID: id, organization: organization, - zoneId: zone.zoneId - } + zoneId: zone.zoneId, + }; if (visualizationSocket) { visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget); @@ -144,9 +143,7 @@ const DroppedObjects: React.FC = () => { // if (res.message === "FloatingWidget deleted successfully") { // deleteObject(zoneName, id, index); // Call the deleteObject method from the store // } - } catch (error) { - - } + } catch (error) {} } const handlePointerDown = (event: React.PointerEvent, index: number) => { @@ -461,15 +458,14 @@ const DroppedObjects: React.FC = () => { position: boundedPosition, }, index: draggingIndex.index, - zoneId: zone.zoneId - } + zoneId: zone.zoneId, + }; if (visualizationSocket) { visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget); } // if (response.message === "Widget updated successfully") { - console.log('boundedPosition: ', boundedPosition); updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); // } @@ -503,106 +499,130 @@ const DroppedObjects: React.FC = () => { setOpenKebabId((prevId) => (prevId === id ? null : id)); }; + const containerHeight = getComputedStyle( + document.documentElement + ).getPropertyValue("--realTimeViz-container-height"); + const containerWidth = getComputedStyle( + document.documentElement + ).getPropertyValue("--realTimeViz-container-width"); + + const heightMultiplier = parseFloat(containerHeight) * 0.14; + + const widthMultiplier = parseFloat(containerWidth) * 0.13; + + console.log("zone.objects: ", zone.objects); return (
- {zone.objects.map((obj, index) => ( -
{ - setSelectedChartId(obj); - handlePointerDown(event, index); - }} - > - {obj.className === "floating total-card" ? ( - <> - - - ) : obj.className === "warehouseThroughput floating" ? ( - <> - - - ) : obj.className === "fleetEfficiency floating" ? ( - <> - - - ) : null} + {zone.objects.map((obj, index) => { + const topPosition = + typeof obj.position.top === "number" + ? `calc(${obj.position.top}px + ${ + isPlaying && selectedZone.activeSides.includes("top") + ? `${heightMultiplier - 55}px` + : "0px" + })` + : "auto"; + + const leftPosition = + typeof obj.position.left === "number" + ? `calc(${obj.position.left}px + ${ + isPlaying && selectedZone.activeSides.includes("left") + ? `${widthMultiplier - 100}px` + : "0px" + })` + : "auto"; + + const rightPosition = + typeof obj.position.right === "number" + ? `calc(${obj.position.right}px + ${ + isPlaying && selectedZone.activeSides.includes("right") + ? `${widthMultiplier - 100}px` + : "0px" + })` + : "auto"; + + const bottomPosition = + typeof obj.position.bottom === "number" + ? `calc(${obj.position.bottom}px + ${ + isPlaying && selectedZone.activeSides.includes("bottom") + ? `${heightMultiplier - 55}px` + : "0px" + })` + : "auto"; + + return (
{ - event.stopPropagation(); - handleKebabClick(obj.id, event); + key={`${zoneName}-${index}`} + className={`${obj.className} ${ + selectedChartId?.id === obj.id && "activeChart" + }`} + ref={chartWidget} + style={{ + position: "absolute", + top: topPosition, + left: leftPosition, + right: rightPosition, + bottom: bottomPosition, + }} + onPointerDown={(event) => { + setSelectedChartId(obj); + handlePointerDown(event, index); }} > - -
- {openKebabId === obj.id && ( -
-
{ - event.stopPropagation(); - handleDuplicate(zoneName, index); // Call the duplicate handler - }} - > -
- -
-
Duplicate
-
-
{ - event.stopPropagation(); - handleDelete(zoneName, obj.id); // Call the delete handler - }} - > -
- -
-
Delete
-
+ {obj.className === "floating total-card" ? ( + + ) : obj.className === "warehouseThroughput floating" ? ( + + ) : obj.className === "fleetEfficiency floating" ? ( + + ) : null} + +
{ + event.stopPropagation(); + handleKebabClick(obj.id, event); + }} + > +
- )} -
- ))} + + {openKebabId === obj.id && ( +
+
{ + event.stopPropagation(); + handleDuplicate(zoneName, index); // Call the duplicate handler + }} + > +
+ +
+
Duplicate
+
+
{ + event.stopPropagation(); + handleDelete(zoneName, obj.id); // Call the delete handler + }} + > +
+ +
+
Delete
+
+
+ )} +
+ ); + })} {/* Render DistanceLines component during drag */} {isPlaying === false && diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index 2e168b4..fe9836d 100644 --- a/app/src/components/ui/componets/Panel.tsx +++ b/app/src/components/ui/componets/Panel.tsx @@ -21,7 +21,6 @@ interface PanelProps { zoneName: string; activeSides: Side[]; panelOrder: Side[]; - lockedPanels: Side[]; zoneId: string; zoneViewPortTarget: number[]; @@ -33,7 +32,6 @@ interface PanelProps { zoneName: string; activeSides: Side[]; panelOrder: Side[]; - lockedPanels: Side[]; zoneId: string; zoneViewPortTarget: number[]; @@ -42,7 +40,7 @@ interface PanelProps { }> >; hiddenPanels: string[]; - setZonesData: React.Dispatch>; // Add this line + setZonesData: React.Dispatch>; } const generateUniqueId = () => @@ -60,14 +58,13 @@ const Panel: React.FC = ({ [side in Side]?: { width: number; height: number }; }>({}); const [openKebabId, setOpenKebabId] = useState(null); - const { isPlaying } = usePlayButtonStore(); const { visualizationSocket } = useSocketStore(); - const [canvasDimensions, setCanvasDimensions] = useState({ width: 0, height: 0, }); + // Track canvas dimensions useEffect(() => { const canvas = document.getElementById("real-time-vis-canvas"); @@ -81,42 +78,20 @@ const Panel: React.FC = ({ }); }; - // Initial measurement updateCanvasDimensions(); - - // Set up ResizeObserver to track changes const resizeObserver = new ResizeObserver(updateCanvasDimensions); resizeObserver.observe(canvas); - return () => { - resizeObserver.unobserve(canvas); - }; + return () => resizeObserver.unobserve(canvas); }, []); - useEffect(() => { - const canvas = document.getElementById("real-time-vis-canvas"); - if (!canvas) return; - - const updateCanvasDimensions = () => { - const rect = canvas.getBoundingClientRect(); - setCanvasDimensions({ - width: rect.width, - height: rect.height, - }); - }; - - // Initial measurement - updateCanvasDimensions(); - - // Set up ResizeObserver to track changes - const resizeObserver = new ResizeObserver(updateCanvasDimensions); - resizeObserver.observe(canvas); - - return () => { - resizeObserver.unobserve(canvas); - }; - }, []); + // Calculate panel size + const panelSize = Math.max( + Math.min(canvasDimensions.width * 0.25, canvasDimensions.height * 0.25), + 170 // Min 170px + ); + // Define getPanelStyle const getPanelStyle = useMemo( () => (side: Side) => { const currentIndex = selectedZone.panelOrder.indexOf(side); @@ -126,125 +101,105 @@ const Panel: React.FC = ({ const topActive = previousPanels.includes("top"); const bottomActive = previousPanels.includes("bottom"); - // Dynamic panel sizes based on canvas width - const panelSizeWidth = Math.max(canvasDimensions.width * 0.165, 200); // Ensure minimum width of 200px - const panelSizeHeight = Math.max(canvasDimensions.width * 0.13, 200); // Ensure minimum height of 200px - switch (side) { case "top": case "bottom": return { - // minWidth: "200px", // Minimum width constraint + minWidth: "170px", width: `calc(100% - ${ - (leftActive ? panelSizeWidth : 0) + - (rightActive ? panelSizeWidth : 0) + (leftActive ? panelSize : 0) + (rightActive ? panelSize : 0) }px)`, - minHeight: "150px", // Minimum height constraint - height: `${panelSizeHeight - 2}px`, // Subtracting for border or margin - left: leftActive ? `${panelSizeWidth}px` : "0", - right: rightActive ? `${panelSizeWidth}px` : "0", + minHeight: "170px", + height: `${panelSize}px`, + left: leftActive ? `${panelSize}px` : "0", + right: rightActive ? `${panelSize}px` : "0", [side]: "0", }; - case "left": case "right": return { - minWidth: "150px", // Minimum width constraint - width: `${panelSizeWidth - 2}px`, // Subtracting for border or margin - // minHeight: "200px", // Minimum height constraint + minWidth: "170px", + width: `${panelSize}px`, + minHeight: "170px", height: `calc(100% - ${ - (topActive ? panelSizeHeight : 0) + - (bottomActive ? panelSizeHeight : 0) + (topActive ? panelSize : 0) + (bottomActive ? panelSize : 0) }px)`, - top: topActive ? `${panelSizeHeight}px` : "0", - bottom: bottomActive ? `${panelSizeHeight}px` : "0", + top: topActive ? `${panelSize}px` : "0", + bottom: bottomActive ? `${panelSize}px` : "0", [side]: "0", }; - default: return {}; } }, - [ - selectedZone.panelOrder, - isPlaying, - canvasDimensions.width, - canvasDimensions.height, - ] + [selectedZone.panelOrder, panelSize] ); + // Handle drop event const handleDrop = (e: React.DragEvent, panel: Side) => { e.preventDefault(); const { draggedAsset } = useWidgetStore.getState(); - if (!draggedAsset) return; - if (isPanelLocked(panel)) return; + if (!draggedAsset || isPanelLocked(panel)) return; const currentWidgetsCount = getCurrentWidgetCount(panel); const maxCapacity = calculatePanelCapacity(panel); - if (currentWidgetsCount >= maxCapacity) return; - addWidgetToPanel(draggedAsset, panel); + if (currentWidgetsCount < maxCapacity) { + addWidgetToPanel(draggedAsset, panel); + } }; + // Check if panel is locked const isPanelLocked = (panel: Side) => selectedZone.lockedPanels.includes(panel); + // Get current widget count in a panel const getCurrentWidgetCount = (panel: Side) => selectedZone.widgets.filter((w) => w.panel === panel).length; + // Calculate panel capacity const calculatePanelCapacity = (panel: Side) => { - const CHART_WIDTH = 170; - const CHART_HEIGHT = 170; - const FALLBACK_HORIZONTAL_CAPACITY = 5; - const FALLBACK_VERTICAL_CAPACITY = 3; + const CHART_WIDTH = panelSize; + const CHART_HEIGHT = panelSize; const dimensions = panelDimensions[panel]; if (!dimensions) { - return panel === "top" || panel === "bottom" - ? FALLBACK_HORIZONTAL_CAPACITY - : FALLBACK_VERTICAL_CAPACITY; + return panel === "top" || panel === "bottom" ? 5 : 3; // Fallback capacities } return panel === "top" || panel === "bottom" - ? Math.floor(dimensions.width / CHART_WIDTH) - : Math.floor(dimensions.height / CHART_HEIGHT); + ? Math.max(1, Math.floor(dimensions.width / CHART_WIDTH)) + : Math.max(1, Math.floor(dimensions.height / CHART_HEIGHT)); }; - // while dublicate check this and add + // Add widget to panel const addWidgetToPanel = async (asset: any, panel: Side) => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; + const newWidget = { ...asset, id: generateUniqueId(), panel, }; + let addWidget = { organization: organization, zoneId: selectedZone.zoneId, widget: newWidget, }; + if (visualizationSocket) { visualizationSocket.emit("v2:viz-widget:add", addWidget); } + setSelectedZone((prev) => ({ ...prev, widgets: [...prev.widgets, newWidget], })); - - try { - // let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); - // if (response.message === "Widget created successfully") { - // setSelectedZone((prev) => ({ - // ...prev, - // widgets: [...prev.widgets, newWidget], - // })); - // } - } catch (error) { - console.error("Error adding widget:", error); - } }; + // Observe panel dimensions useEffect(() => { const observers: ResizeObserver[] = []; const currentPanelRefs = panelRefs.current; @@ -261,6 +216,7 @@ const Panel: React.FC = ({ })); } }); + observer.observe(element); observers.push(observer); } @@ -271,22 +227,15 @@ const Panel: React.FC = ({ }; }, [selectedZone.activeSides]); + // Handle widget reordering const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => { - if (!selectedZone) return; // Ensure selectedZone is not null - setSelectedZone((prev) => { - if (!prev) return prev; // Ensure prev is not null - - // Filter widgets for the specified panel const widgetsInPanel = prev.widgets.filter((w) => w.panel === panel); - - // Reorder widgets within the same panel const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex); - // Merge the reordered widgets back into the full list while preserving the order const updatedWidgets = prev.widgets - .filter((widget) => widget.panel !== panel) // Keep widgets from other panels - .concat(reorderedWidgets); // Add the reordered widgets for the specified panel + .filter((widget) => widget.panel !== panel) + .concat(reorderedWidgets); return { ...prev, @@ -295,12 +244,40 @@ const Panel: React.FC = ({ }); }; + // Calculate capacities and dimensions + const topWidth = getPanelStyle("top").width; + const bottomWidth = getPanelStyle("bottom").width; + const leftHeight = getPanelStyle("left").height; + const rightHeight = getPanelStyle("right").height; + + const topCapacity = calculatePanelCapacity("top"); + const bottomCapacity = calculatePanelCapacity("bottom"); + const leftCapacity = calculatePanelCapacity("left"); + const rightCapacity = calculatePanelCapacity("right"); + return ( <> + + {selectedZone.activeSides.map((side) => (
= ({ }; export default Panel; - -// canvasDimensions.width as percent diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index a9ee657..8044ed2 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -67,9 +67,7 @@ const RealTimeVisulization: React.FC = () => { const { rightClickSelected, setRightClickSelected } = useRightClickSelected(); const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false); - const [floatingWidgets, setFloatingWidgets] = useState< - Record - >({}); + const [floatingWidgets, setFloatingWidgets] = useState>({}); const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); const { visualizationSocket } = useSocketStore(); @@ -81,7 +79,6 @@ const RealTimeVisulization: React.FC = () => { const organization = email?.split("@")[1]?.split(".")[0]; try { const response = await getZone2dData(organization); - // console.log('response: ', response); if (!Array.isArray(response)) { return; @@ -102,7 +99,7 @@ const RealTimeVisulization: React.FC = () => { {} ); setZonesData(formattedData); - } catch (error) {} + } catch (error) { } } GetZoneData(); @@ -200,7 +197,7 @@ const RealTimeVisulization: React.FC = () => { ], }, })); - } catch (error) {} + } catch (error) { } }; useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -267,19 +264,19 @@ const RealTimeVisulization: React.FC = () => { /> )} - {/*
handleDrop(event)} - onDragOver={(event) => event.preventDefault()} +
handleDrop(event)} + onDragOver={(event) => event.preventDefault()} > - -
*/} + +
{activeModule === "visualization" && selectedZone.zoneName !== "" && ( )} diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index 3d2a828..3260eb6 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -47,80 +47,83 @@ const DropDownList: React.FC = ({ const [zoneDataList, setZoneDataList] = useState< { id: string; name: string; assets: Asset[] }[] >([]); + const [zonePoints3D, setZonePoints3D] = useState<[]>([]); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); useEffect(() => { - // console.log(zones); - // setZoneDataList([ - // { id: "2e996073-546c-470c-8323-55bd3700c6aa", name: "zone1" }, - // { id: "3f473bf0-197c-471c-a71f-943fc9ca2b47", name: "zone2" }, - // { id: "905e8fb6-9e18-469b-9474-e0478fb9601b", name: "zone3" }, - // { id: "9d9efcbe-8e96-47eb-bfad-128a9e4c532e", name: "zone4" }, - // { id: "884f3d29-eb5a-49a5-abe9-d11971c08e85", name: "zone5" }, - // { id: "70fa55cd-b5c9-4f80-a8c4-6319af3bfb4e", name: "zone6" }, - // ]) + // const value = (zones || []).map( + // (val: { zoneId: string; zoneName: string }) => ({ + // id: val.zoneId, + // name: val.zoneName, + // }) + // ); + // console.log('zones: ', zones); + const value = (zones || []).map((val: { zoneId: string; zoneName: string }) => ({ + id: val.zoneId, + name: val.zoneName + })); + setZoneDataList(prev => (JSON.stringify(prev) !== JSON.stringify(value) ? value : prev)); + const allPoints = zones.flatMap((zone: any) => zone.points); + setZonePoints3D(allPoints); + // setZoneDataList([ + // { + // id: "zone1", + // name: "Zone 1", + // assets: [ + // { + // id: "asset1", + // name: "Asset 1", + // }, + // { + // id: "asset2", + // name: "Asset 2", + // }, + // { + // id: "asset3", + // name: "Asset 3", + // }, + // ], + // }, + // { + // id: "zone2", + // name: "Zone 2", + // assets: [ + // { + // id: "asset4", + // name: "Asset 4", + // }, + // { + // id: "asset5", + // name: "Asset 5", + // }, + // { + // id: "asset6", + // name: "Asset 6", + // }, + // ], + // }, + // { + // id: "zone3", + // name: "Zone 3", + // assets: [ + // { + // id: "asset7", + // name: "Asset 7", + // }, + // { + // id: "asset8", + // name: "Asset 8", + // }, + // ], + // }, + // ]); - const value = (zones || []).map( - (val: { zoneId: string; zoneName: string }) => ({ - id: val.zoneId, - name: val.zoneName, - }) - ); - setZoneDataList([ - { - id: "zone1", - name: "Zone 1", - assets: [ - { - id: "asset1", - name: "Asset 1", - }, - { - id: "asset2", - name: "Asset 2", - }, - { - id: "asset3", - name: "Asset 3", - }, - ], - }, - { - id: "zone2", - name: "Zone 2", - assets: [ - { - id: "asset4", - name: "Asset 4", - }, - { - id: "asset5", - name: "Asset 5", - }, - { - id: "asset6", - name: "Asset 6", - }, - ], - }, - { - id: "zone3", - name: "Zone 3", - assets: [ - { - id: "asset7", - name: "Asset 7", - }, - { - id: "asset8", - name: "Asset 8", - }, - ], - }, - ]); - }, [zones]); + useEffect(() => { + + // console.log('zonePoints3D: ', zonePoints3D); + }, [zonePoints3D]) return (
diff --git a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx index 0c36977..7fafb79 100644 --- a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx +++ b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx @@ -5,7 +5,7 @@ interface SimpleCardProps { icon: React.ComponentType>; // React component for SVG icon value: string; per: string; // Percentage change - position?: [number, number] + position?: [number, number]; } const SimpleCard: React.FC = ({ @@ -15,7 +15,6 @@ const SimpleCard: React.FC = ({ per, position = [0, 0], }) => { - const handleDragStart = (event: React.DragEvent) => { const rect = event.currentTarget.getBoundingClientRect(); // Get position const cardData = JSON.stringify({ @@ -23,7 +22,7 @@ const SimpleCard: React.FC = ({ value, per, icon: Icon, - + className: event.currentTarget.className, position: [rect.top, rect.left], // ✅ Store position }); diff --git a/app/src/modules/builder/agv/pathNavigator.tsx b/app/src/modules/builder/agv/pathNavigator.tsx index 7d7984c..6369a87 100644 --- a/app/src/modules/builder/agv/pathNavigator.tsx +++ b/app/src/modules/builder/agv/pathNavigator.tsx @@ -29,12 +29,15 @@ export default function PathNavigator({ const [dropPickupPath, setDropPickupPath] = useState<[number, number, number][]>([]); const [initialPosition, setInitialPosition] = useState(null); const [initialRotation, setInitialRotation] = useState(null); - + const [targetPosition] = useState(new THREE.Vector3()); + const [smoothPosition] = useState(new THREE.Vector3()); + const [targetQuaternion] = useState(new THREE.Quaternion()); const distancesRef = useRef([]); const totalDistanceRef = useRef(0); const progressRef = useRef(0); const isWaiting = useRef(false); const timeoutRef = useRef(null); + const pathTransitionProgress = useRef(0); const { scene } = useThree(); const { isPlaying } = usePlayButtonStore(); @@ -44,6 +47,9 @@ export default function PathNavigator({ if (object) { setInitialPosition(object.position.clone()); setInitialRotation(object.rotation.clone()); + smoothPosition.copy(object.position.clone()); + targetPosition.copy(object.position.clone()); + targetQuaternion.setFromEuler(object.rotation.clone()); } }, [scene, id]); @@ -65,22 +71,23 @@ export default function PathNavigator({ setPath([]); setCurrentPhase('initial'); - setPickupDropPath([]); - setDropPickupPath([]); distancesRef.current = []; totalDistanceRef.current = 0; progressRef.current = 0; isWaiting.current = false; + pathTransitionProgress.current = 0; - if (initialPosition && initialRotation) { - const object = scene.getObjectByProperty("uuid", id); - if (object) { - object.position.copy(initialPosition); - object.rotation.copy(initialRotation); - } + const object = scene.getObjectByProperty("uuid", id); + if (object && initialPosition && initialRotation) { + object.position.copy(initialPosition); + object.rotation.copy(initialRotation); + smoothPosition.copy(initialPosition); + targetPosition.copy(initialPosition); + targetQuaternion.setFromEuler(initialRotation); } }; + useEffect(() => { if (!isPlaying) { resetState(); @@ -171,16 +178,16 @@ export default function PathNavigator({ const end = new THREE.Vector3(...path[index + 1]); const dist = distancesRef.current[index]; const t = THREE.MathUtils.clamp((covered - accumulated) / dist, 0, 1); - const position = start.clone().lerp(end, t); - object.position.copy(position); + targetPosition.copy(start).lerp(end, t); + + smoothPosition.lerp(targetPosition, 0.1); + object.position.copy(smoothPosition); const direction = new THREE.Vector3().subVectors(end, start).normalize(); const targetRotationY = Math.atan2(direction.x, direction.z); - - let angleDifference = targetRotationY - object.rotation.y; - angleDifference = ((angleDifference + Math.PI) % (Math.PI * 2)) - Math.PI; - object.rotation.y += angleDifference * 0.1; + targetQuaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), targetRotationY); + object.quaternion.slerp(targetQuaternion, 0.1); }); useEffect(() => { diff --git a/app/src/modules/builder/geomentries/floors/addFloorToScene.ts b/app/src/modules/builder/geomentries/floors/addFloorToScene.ts index e2f0baa..c951ba0 100644 --- a/app/src/modules/builder/geomentries/floors/addFloorToScene.ts +++ b/app/src/modules/builder/geomentries/floors/addFloorToScene.ts @@ -53,7 +53,7 @@ export default function addFloorToScene( const mesh = new THREE.Mesh(geometry, material); mesh.receiveShadow = true; - mesh.position.y = layer; + mesh.position.y = (layer) * CONSTANTS.wallConfig.height; mesh.rotateX(Math.PI / 2); mesh.name = `Floor_Layer_${layer}`; diff --git a/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts b/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts index 8f33b57..9400be2 100644 --- a/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts +++ b/app/src/modules/builder/geomentries/floors/loadOnlyFloors.ts @@ -171,7 +171,7 @@ function loadOnlyFloors( mesh.castShadow = true; mesh.receiveShadow = true; - mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height + 0.03; + mesh.position.y = (floor[0][0][2] - 1) * CONSTANTS.wallConfig.height; mesh.rotateX(Math.PI / 2); mesh.name = `Only_Floor_Line_${floor[0][0][2]}`; diff --git a/app/src/modules/builder/groups/floorItemsGroup.tsx b/app/src/modules/builder/groups/floorItemsGroup.tsx index 96f4fad..6289bd0 100644 --- a/app/src/modules/builder/groups/floorItemsGroup.tsx +++ b/app/src/modules/builder/groups/floorItemsGroup.tsx @@ -1,26 +1,11 @@ import { useFrame, useThree } from "@react-three/fiber"; -import { - useActiveTool, - useAsset3dWidget, - useCamMode, - useDeletableFloorItem, - useDeleteModels, - useFloorItems, - useLoadingProgress, - useRenderDistance, - useselectedFloorItem, - useSelectedItem, - useSimulationStates, - useSocketStore, - useToggleView, - useTransformMode, -} from "../../../store/store"; +import { useActiveTool, useAsset3dWidget, useCamMode, useDeletableFloorItem, useDeleteModels, useFloorItems, useLoadingProgress, useRenderDistance, useselectedFloorItem, useSelectedItem, useSimulationStates, useSocketStore, useToggleView, useTransformMode, } from "../../../store/store"; import assetVisibility from "../geomentries/assets/assetVisibility"; import { useEffect } from "react"; import * as THREE from "three"; import * as Types from "../../../types/world/worldTypes"; import assetManager, { - cancelOngoingTasks, + cancelOngoingTasks, } from "../geomentries/assets/assetManager"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; @@ -31,413 +16,313 @@ import addAssetModel from "../geomentries/assets/addAssetModel"; import { getFloorAssets } from "../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi"; import useModuleStore from "../../../store/useModuleStore"; // import { retrieveGLTF } from "../../../utils/indexDB/idbUtils"; -const assetManagerWorker = new Worker( - new URL( - "../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", - import.meta.url - ) -); -const gltfLoaderWorker = new Worker( - new URL( - "../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", - import.meta.url - ) -); +const assetManagerWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/assetManagerWorker.js", import.meta.url)); +const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); -const FloorItemsGroup = ({ - itemsGroup, - hoveredDeletableFloorItem, - AttachedObject, - floorGroup, - tempLoader, - isTempLoader, - plane, -}: any) => { - const state: Types.ThreeState = useThree(); - const { raycaster, controls }: any = state; - const { renderDistance } = useRenderDistance(); - const { toggleView } = useToggleView(); - const { floorItems, setFloorItems } = useFloorItems(); - const { camMode } = useCamMode(); - const { deleteModels } = useDeleteModels(); - const { setDeletableFloorItem } = useDeletableFloorItem(); - const { transformMode } = useTransformMode(); - const { setselectedFloorItem } = useselectedFloorItem(); - const { activeTool } = useActiveTool(); - const { selectedItem, setSelectedItem } = useSelectedItem(); - const { simulationStates, setSimulationStates } = useSimulationStates(); - const { setLoadingProgress } = useLoadingProgress(); - const { activeModule } = useModuleStore(); - const { socket } = useSocketStore(); - const loader = new GLTFLoader(); - const dracoLoader = new DRACOLoader(); +const FloorItemsGroup = ({ itemsGroup, hoveredDeletableFloorItem, AttachedObject, floorGroup, tempLoader, isTempLoader, plane, }: any) => { + const state: Types.ThreeState = useThree(); + const { raycaster, controls }: any = state; + const { renderDistance } = useRenderDistance(); + const { toggleView } = useToggleView(); + const { floorItems, setFloorItems } = useFloorItems(); + const { camMode } = useCamMode(); + const { deleteModels } = useDeleteModels(); + const { setDeletableFloorItem } = useDeletableFloorItem(); + const { transformMode } = useTransformMode(); + const { setselectedFloorItem } = useselectedFloorItem(); + const { activeTool } = useActiveTool(); + const { selectedItem, setSelectedItem } = useSelectedItem(); + const { simulationStates, setSimulationStates } = useSimulationStates(); + const { setLoadingProgress } = useLoadingProgress(); + const { activeModule } = useModuleStore(); + const { socket } = useSocketStore(); + const loader = new GLTFLoader(); + const dracoLoader = new DRACOLoader(); - dracoLoader.setDecoderPath( - "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/" - ); - loader.setDRACOLoader(dracoLoader); + dracoLoader.setDecoderPath("https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"); + loader.setDRACOLoader(dracoLoader); - useEffect(() => { - const email = localStorage.getItem("email"); - const organization = email!.split("@")[1].split(".")[0]; + useEffect(() => { + const email = localStorage.getItem("email"); + const organization = email!.split("@")[1].split(".")[0]; - let totalAssets = 0; - let loadedAssets = 0; + let totalAssets = 0; + let loadedAssets = 0; - const updateLoadingProgress = (progress: number) => { - if (progress < 100) { - setLoadingProgress(progress); - } else if (progress === 100) { - setTimeout(() => { - setLoadingProgress(100); - setTimeout(() => { - setLoadingProgress(0); - }, 1500); - }, 1000); - } - }; + const updateLoadingProgress = (progress: number) => { + if (progress < 100) { + setLoadingProgress(progress); + } else if (progress === 100) { + setTimeout(() => { + setLoadingProgress(100); + setTimeout(() => { + setLoadingProgress(0); + }, 1500); + }, 1000); + } + }; - getFloorAssets(organization).then((data) => { - if (data.length > 0) { - const uniqueItems = (data as Types.FloorItems).filter( - (item, index, self) => - index === self.findIndex((t) => t.modelfileID === item.modelfileID) - ); - totalAssets = uniqueItems.length; - if (totalAssets === 0) { - updateLoadingProgress(100); - return; - } - gltfLoaderWorker.postMessage({ floorItems: data }); - } else { - gltfLoaderWorker.postMessage({ floorItems: [] }); - loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates); - updateLoadingProgress(100); - } - }); - - gltfLoaderWorker.onmessage = async (event) => { - if (event.data.message === "gltfLoaded" && event.data.modelBlob) { - const blobUrl = URL.createObjectURL(event.data.modelBlob); - - loader.load(blobUrl, (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.remove(blobUrl); - THREE.Cache.add(event.data.modelID, gltf); - - loadedAssets++; - const progress = Math.round((loadedAssets / totalAssets) * 100); - updateLoadingProgress(progress); - - if (loadedAssets === totalAssets) { - loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates); - updateLoadingProgress(100); - } + getFloorAssets(organization).then((data) => { + if (data.length > 0) { + const uniqueItems = (data as Types.FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.modelfileID === item.modelfileID)); + totalAssets = uniqueItems.length; + if (totalAssets === 0) { + updateLoadingProgress(100); + return; + } + gltfLoaderWorker.postMessage({ floorItems: data }); + } else { + gltfLoaderWorker.postMessage({ floorItems: [] }); + loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates); + updateLoadingProgress(100); + } }); - } - }; - }, []); - useEffect(() => { - assetManagerWorker.onmessage = async (event) => { - cancelOngoingTasks(); // Cancel the ongoing process - await assetManager(event.data, itemsGroup, loader); - }; - }, [assetManagerWorker]); + gltfLoaderWorker.onmessage = async (event) => { + if (event.data.message === "gltfLoaded" && event.data.modelBlob) { + const blobUrl = URL.createObjectURL(event.data.modelBlob); - useEffect(() => { - if (toggleView) return; + loader.load(blobUrl, (gltf) => { + URL.revokeObjectURL(blobUrl); + THREE.Cache.remove(blobUrl); + THREE.Cache.add(event.data.modelID, gltf); - const uuids: string[] = []; - itemsGroup.current?.children.forEach((child: any) => { - uuids.push(child.uuid); - }); - const cameraPosition = state.camera.position; + loadedAssets++; + const progress = Math.round((loadedAssets / totalAssets) * 100); + updateLoadingProgress(progress); - assetManagerWorker.postMessage({ - floorItems, - cameraPosition, - uuids, - renderDistance, - }); - }, [camMode, renderDistance]); + if (loadedAssets === totalAssets) { + loadInitialFloorItems(itemsGroup, setFloorItems, setSimulationStates); + updateLoadingProgress(100); + } + }); + } + }; + }, []); - useEffect(() => { - const controls: any = state.controls; - const camera: any = state.camera; + useEffect(() => { + assetManagerWorker.onmessage = async (event) => { + cancelOngoingTasks(); // Cancel the ongoing process + await assetManager(event.data, itemsGroup, loader); + }; + }, [assetManagerWorker]); - if (controls) { - let intervalId: NodeJS.Timeout | null = null; - - const handleChange = () => { + useEffect(() => { if (toggleView) return; const uuids: string[] = []; - itemsGroup.current?.children.forEach((child: any) => { - uuids.push(child.uuid); - }); - const cameraPosition = camera.position; + itemsGroup.current?.children.forEach((child: any) => { uuids.push(child.uuid); }); + const cameraPosition = state.camera.position; - assetManagerWorker.postMessage({ - floorItems, - cameraPosition, - uuids, - renderDistance, - }); - }; + assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance, }); + }, [camMode, renderDistance]); - const startInterval = () => { - if (!intervalId) { - intervalId = setInterval(handleChange, 50); + useEffect(() => { + const controls: any = state.controls; + const camera: any = state.camera; + + if (controls) { + let intervalId: NodeJS.Timeout | null = null; + + const handleChange = () => { + if (toggleView) return; + + const uuids: string[] = []; + itemsGroup.current?.children.forEach((child: any) => { uuids.push(child.uuid); }); + const cameraPosition = camera.position; + + assetManagerWorker.postMessage({ floorItems, cameraPosition, uuids, renderDistance, }); + }; + + const startInterval = () => { + if (!intervalId) { + intervalId = setInterval(handleChange, 50); + } + }; + + const stopInterval = () => { + handleChange(); + if (intervalId) { + clearInterval(intervalId); + intervalId = null; + } + }; + + controls.addEventListener("rest", handleChange); + controls.addEventListener("rest", stopInterval); + controls.addEventListener("control", startInterval); + controls.addEventListener("controlend", stopInterval); + + return () => { + controls.removeEventListener("rest", handleChange); + controls.removeEventListener("rest", stopInterval); + controls.removeEventListener("control", startInterval); + controls.removeEventListener("controlend", stopInterval); + if (intervalId) { + clearInterval(intervalId); + } + }; } - }; + }, [state.controls, floorItems, toggleView, renderDistance]); - const stopInterval = () => { - handleChange(); - if (intervalId) { - clearInterval(intervalId); - intervalId = null; - } - }; + useEffect(() => { + const canvasElement = state.gl.domElement; + let drag = false; + let isLeftMouseDown = false; - controls.addEventListener("rest", handleChange); - controls.addEventListener("rest", stopInterval); - controls.addEventListener("control", startInterval); - controls.addEventListener("controlend", stopInterval); - - return () => { - controls.removeEventListener("rest", handleChange); - controls.removeEventListener("rest", stopInterval); - controls.removeEventListener("control", startInterval); - controls.removeEventListener("controlend", stopInterval); - if (intervalId) { - clearInterval(intervalId); - } - }; - } - }, [state.controls, floorItems, toggleView, renderDistance]); - - useEffect(() => { - const canvasElement = state.gl.domElement; - let drag = false; - let isLeftMouseDown = false; - - const onMouseDown = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = true; - drag = false; - } - }; - - const onMouseMove = () => { - if (isLeftMouseDown) { - drag = true; - } - }; - - const onMouseUp = async (evt: any) => { - if (controls) { - (controls as any).enabled = true; - } - if (evt.button === 0) { - isLeftMouseDown = false; - if (drag) return; - - if (deleteModels) { - DeleteFloorItems( - itemsGroup, - hoveredDeletableFloorItem, - setFloorItems, - setSimulationStates, - socket - ); - } - const Mode = transformMode; - - if (Mode !== null || activeTool === "cursor") { - if (!itemsGroup.current) return; - let intersects = raycaster.intersectObjects( - itemsGroup.current.children, - true - ); - if ( - intersects.length > 0 && - intersects[0]?.object?.parent?.parent?.position && - intersects[0]?.object?.parent?.parent?.scale && - intersects[0]?.object?.parent?.parent?.rotation - ) { - // let currentObject = intersects[0].object; - // while (currentObject) { - // if (currentObject.name === "Scene") { - // break; - // } - // currentObject = currentObject.parent as THREE.Object3D; - // } - // if (currentObject) { - // AttachedObject.current = currentObject as any; - // setselectedFloorItem(AttachedObject.current!); - // } - } else { - const target = controls.getTarget(new THREE.Vector3()); - await controls.setTarget(target.x, 0, target.z, true); - setselectedFloorItem(null); - } - } - } - }; - - const onDblClick = async (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = false; - if (drag) return; - - const Mode = transformMode; - - if (Mode !== null || activeTool === "cursor") { - if (!itemsGroup.current) return; - let intersects = raycaster.intersectObjects( - itemsGroup.current.children, - true - ); - if ( - intersects.length > 0 && - intersects[0]?.object?.parent?.parent?.position && - intersects[0]?.object?.parent?.parent?.scale && - intersects[0]?.object?.parent?.parent?.rotation - ) { - let currentObject = intersects[0].object; - - while (currentObject) { - if (currentObject.name === "Scene") { - break; - } - currentObject = currentObject.parent as THREE.Object3D; + const onMouseDown = (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown = true; + drag = false; } - if (currentObject) { - AttachedObject.current = currentObject as any; - // controls.fitToSphere(AttachedObject.current!, true); + }; - const bbox = new THREE.Box3().setFromObject( - AttachedObject.current - ); - const size = bbox.getSize(new THREE.Vector3()); - const center = bbox.getCenter(new THREE.Vector3()); - - const front = new THREE.Vector3(0, 0, 1); - AttachedObject.current.localToWorld(front); - front.sub(AttachedObject.current.position).normalize(); - - const distance = Math.max(size.x, size.y, size.z) * 2; - const newPosition = center - .clone() - .addScaledVector(front, distance); - - controls.setPosition( - newPosition.x, - newPosition.y, - newPosition.z, - true - ); - controls.setTarget(center.x, center.y, center.z, true); - controls.fitToBox(AttachedObject.current!, true, { - cover: true, - paddingTop: 5, - paddingLeft: 5, - paddingBottom: 5, - paddingRight: 5, - }); - - setselectedFloorItem(AttachedObject.current!); + const onMouseMove = () => { + if (isLeftMouseDown) { + drag = true; + } + }; + + const onMouseUp = async (evt: any) => { + if (controls) { + (controls as any).enabled = true; + } + if (evt.button === 0) { + isLeftMouseDown = false; + if (drag) return; + + if (deleteModels) { + DeleteFloorItems(itemsGroup, hoveredDeletableFloorItem, setFloorItems, setSimulationStates, socket); + } + const Mode = transformMode; + + if (Mode !== null || activeTool === "cursor") { + if (!itemsGroup.current) return; + let intersects = raycaster.intersectObjects( + itemsGroup.current.children, + true + ); + if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) { + // let currentObject = intersects[0].object; + // while (currentObject) { + // if (currentObject.name === "Scene") { + // break; + // } + // currentObject = currentObject.parent as THREE.Object3D; + // } + // if (currentObject) { + // AttachedObject.current = currentObject as any; + // setselectedFloorItem(AttachedObject.current!); + // } + } else { + const target = controls.getTarget(new THREE.Vector3()); + await controls.setTarget(target.x, 0, target.z, true); + setselectedFloorItem(null); + } + } + } + }; + + const onDblClick = async (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown = false; + if (drag) return; + + const Mode = transformMode; + + if (Mode !== null || activeTool === "cursor") { + if (!itemsGroup.current) return; + let intersects = raycaster.intersectObjects(itemsGroup.current.children, true); + if (intersects.length > 0 && intersects[0]?.object?.parent?.parent?.position && intersects[0]?.object?.parent?.parent?.scale && intersects[0]?.object?.parent?.parent?.rotation) { + let currentObject = intersects[0].object; + + while (currentObject) { + if (currentObject.name === "Scene") { + break; + } + currentObject = currentObject.parent as THREE.Object3D; + } + if (currentObject) { + AttachedObject.current = currentObject as any; + // controls.fitToSphere(AttachedObject.current!, true); + + const bbox = new THREE.Box3().setFromObject(AttachedObject.current); + const size = bbox.getSize(new THREE.Vector3()); + const center = bbox.getCenter(new THREE.Vector3()); + + const front = new THREE.Vector3(0, 0, 1); + AttachedObject.current.localToWorld(front); + front.sub(AttachedObject.current.position).normalize(); + + const distance = Math.max(size.x, size.y, size.z) * 2; + const newPosition = center.clone().addScaledVector(front, distance); + + controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true); + controls.setTarget(center.x, center.y, center.z, true); + controls.fitToBox(AttachedObject.current!, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, }); + + setselectedFloorItem(AttachedObject.current!); + } + } else { + const target = controls.getTarget(new THREE.Vector3()); + await controls.setTarget(target.x, 0, target.z, true); + setselectedFloorItem(null); + } + } + } + }; + + const onDrop = (event: any) => { + if (!event.dataTransfer?.files[0]) return; + + if (selectedItem.id !== "" && event.dataTransfer?.files[0]) { + addAssetModel(raycaster, state.camera, state.pointer, floorGroup, setFloorItems, itemsGroup, isTempLoader, tempLoader, socket, selectedItem, setSelectedItem, setSimulationStates, plane); + } + }; + + const onDragOver = (event: any) => { + event.preventDefault(); + }; + + if (activeModule === "builder") { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener("dblclick", onDblClick); + canvasElement.addEventListener("drop", onDrop); + canvasElement.addEventListener("dragover", onDragOver); + } else { + if (controls) { + const target = controls.getTarget(new THREE.Vector3()); + controls.setTarget(target.x, 0, target.z, true); + setselectedFloorItem(null); } - } else { - const target = controls.getTarget(new THREE.Vector3()); - await controls.setTarget(target.x, 0, target.z, true); - setselectedFloorItem(null); - } } - } - }; - const onDrop = (event: any) => { - if (!event.dataTransfer?.files[0]) return; + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("dblclick", onDblClick); + canvasElement.removeEventListener("drop", onDrop); + canvasElement.removeEventListener("dragover", onDragOver); + }; + }, [deleteModels, transformMode, controls, selectedItem, state.camera, state.pointer, activeTool, activeModule,]); - if (selectedItem.id !== "" && event.dataTransfer?.files[0]) { - addAssetModel( - raycaster, - state.camera, - state.pointer, - floorGroup, - setFloorItems, - itemsGroup, - isTempLoader, - tempLoader, - socket, - selectedItem, - setSelectedItem, - setSimulationStates, - plane - ); - } - }; + useFrame(() => { + if (controls) + assetVisibility(itemsGroup, state.camera.position, renderDistance); + if (deleteModels && activeModule === "builder") { + DeletableHoveredFloorItems(state, itemsGroup, hoveredDeletableFloorItem, setDeletableFloorItem); + } else if (!deleteModels) { + if (hoveredDeletableFloorItem.current) { + hoveredDeletableFloorItem.current = undefined; + setDeletableFloorItem(null); + } + } + }); - const onDragOver = (event: any) => { - event.preventDefault(); - }; - - if (activeModule === "builder") { - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener("dblclick", onDblClick); - canvasElement.addEventListener("drop", onDrop); - canvasElement.addEventListener("dragover", onDragOver); - } else { - if (controls) { - const target = controls.getTarget(new THREE.Vector3()); - controls.setTarget(target.x, 0, target.z, true); - setselectedFloorItem(null); - } - } - - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("dblclick", onDblClick); - canvasElement.removeEventListener("drop", onDrop); - canvasElement.removeEventListener("dragover", onDragOver); - }; - }, [ - deleteModels, - transformMode, - controls, - selectedItem, - state.camera, - state.pointer, - activeTool, - activeModule, - ]); - - - useFrame(() => { - if (controls) - assetVisibility(itemsGroup, state.camera.position, renderDistance); - if (deleteModels) { - DeletableHoveredFloorItems( - state, - itemsGroup, - hoveredDeletableFloorItem, - setDeletableFloorItem - ); - } else if (!deleteModels) { - if (hoveredDeletableFloorItem.current) { - hoveredDeletableFloorItem.current = undefined; - setDeletableFloorItem(null); - } - } - }); - - return ; + return ; }; export default FloorItemsGroup; diff --git a/app/src/modules/builder/groups/wallItemsGroup.tsx b/app/src/modules/builder/groups/wallItemsGroup.tsx index c79adde..1439ef5 100644 --- a/app/src/modules/builder/groups/wallItemsGroup.tsx +++ b/app/src/modules/builder/groups/wallItemsGroup.tsx @@ -9,9 +9,13 @@ import handleMeshMissed from "../eventFunctions/handleMeshMissed"; import DeleteWallItems from "../geomentries/walls/deleteWallItems"; import loadInitialWallItems from "../../scene/IntialLoad/loadInitialWallItems"; import AddWallItems from "../geomentries/walls/addWallItems"; +import useModuleStore from "../../../store/useModuleStore"; const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletableWallItem, selectedItemsIndex, setSelectedItemsIndex, CSGGroup }: any) => { + const state = useThree(); + const { socket } = useSocketStore(); + const { pointer, camera, raycaster } = state; const { deleteModels, setDeleteModels } = useDeleteModels(); const { wallItems, setWallItems } = useWallItems(); const { objectPosition, setObjectPosition } = useObjectPosition(); @@ -19,10 +23,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable const { objectRotation, setObjectRotation } = useObjectRotation(); const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); - const { socket } = useSocketStore(); - const state = useThree(); - const { pointer, camera, raycaster } = state; - + const { activeModule } = useModuleStore(); useEffect(() => { // Load Wall Items from the backend @@ -209,7 +210,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable const onMouseUp = (evt: any) => { if (evt.button === 0) { isLeftMouseDown = false; - if (!drag && deleteModels) { + if (!drag && deleteModels && activeModule === "builder") { DeleteWallItems(hoveredDeletableWallItem, setWallItems, wallItems, socket); } } @@ -224,7 +225,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable const onDrop = (event: any) => { if (!event.dataTransfer?.files[0]) return - + pointer.x = (event.clientX / window.innerWidth) * 2 - 1; pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(pointer, camera); @@ -259,7 +260,7 @@ const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletable }, [deleteModels, wallItems]) useEffect(() => { - if (deleteModels) { + if (deleteModels && activeModule === "builder") { handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex); setSelectedWallItem(null); setSelectedItemsIndex(null); diff --git a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts index ec6033b..22b9a83 100644 --- a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts @@ -192,7 +192,7 @@ function processLoadedModel( }, ]); - if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') { + if (item.eventData || item.modelfileID === '67e3db5ac2e8f37134526f40' || item.modelfileID === '67eb7904c2e8f37134527eae') { processEventData(item, setSimulationStates); } @@ -227,10 +227,10 @@ function processEventData(item: Types.EventData, setSimulationStates: any) { data as Types.VehicleEventsSchema ]); - } else if (item.modelfileID === '67e3db95c2e8f37134526fb2') { + } else if (item.modelfileID === '67e3db5ac2e8f37134526f40') { const pointUUID = THREE.MathUtils.generateUUID(); - const pointPosition = new THREE.Vector3(0, 1.75, 0); + const pointPosition = new THREE.Vector3(0, 1.5, -0.5); const staticMachine: Types.StaticMachineEventsSchema = { modeluuid: item.modeluuid, @@ -243,13 +243,39 @@ function processEventData(item: Types.EventData, setSimulationStates: any) { triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] }, }, - position: item.position + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], }; - + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ ...(prevEvents || []), staticMachine as Types.StaticMachineEventsSchema ]); + + } else if (item.modelfileID === '67eb7904c2e8f37134527eae') { + const pointUUID = THREE.MathUtils.generateUUID(); + const pointPosition = new THREE.Vector3(0, 2.75, -0.5); + + const armBot: Types.ArmBotEventsSchema = { + modeluuid: item.modeluuid, + modelName: item.modelname, + type: "ArmBot", + points: { + uuid: pointUUID, + position: [pointPosition.x, pointPosition.y, pointPosition.z], + actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', speed: 1, processes: [] }, + triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, + connections: { source: { modelUUID: item.modeluuid, pointUUID: pointUUID }, targets: [] }, + }, + position: item.position, + rotation: [item.rotation.x, item.rotation.y, item.rotation.z], + } + + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ + ...(prevEvents || []), + armBot as Types.ArmBotEventsSchema + ]); + } } diff --git a/app/src/modules/scene/controls/selection/copyPasteControls.tsx b/app/src/modules/scene/controls/selection/copyPasteControls.tsx index 7b494cd..3d2acee 100644 --- a/app/src/modules/scene/controls/selection/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selection/copyPasteControls.tsx @@ -151,7 +151,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas return updatedItems; }); - let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); + let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; @@ -234,7 +234,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas newEventData.position = newFloorItem.position; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; - setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), newEventData as Types.ConveyorEventsSchema ]); @@ -313,13 +313,44 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; - setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), newEventData as Types.VehicleEventsSchema ]); socket.emit("v2:model-asset:add", data); + } else { + + //REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // obj.userData.modelId, + // false, + // true, + // ); + + //SOCKET + + const data = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + }; + + socket.emit("v2:model-asset:add", data); + } } else { diff --git a/app/src/modules/scene/controls/selection/duplicationControls.tsx b/app/src/modules/scene/controls/selection/duplicationControls.tsx index 852b541..a71412d 100644 --- a/app/src/modules/scene/controls/selection/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selection/duplicationControls.tsx @@ -132,7 +132,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb return updatedItems; }); - let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); + let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; @@ -216,7 +216,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb newEventData.position = newFloorItem.position; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; - setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), newEventData as Types.ConveyorEventsSchema ]); @@ -295,13 +295,44 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; - setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => [ + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), newEventData as Types.VehicleEventsSchema ]); socket.emit("v2:model-asset:add", data); + } else { + + //REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // obj.userData.modelId, + // false, + // true, + // ); + + //SOCKET + + const data = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + socketId: socket.id, + }; + + socket.emit("v2:model-asset:add", data); + } } else { diff --git a/app/src/modules/scene/controls/selection/moveControls.tsx b/app/src/modules/scene/controls/selection/moveControls.tsx index 2693531..5883b62 100644 --- a/app/src/modules/scene/controls/selection/moveControls.tsx +++ b/app/src/modules/scene/controls/selection/moveControls.tsx @@ -180,12 +180,12 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje return updatedItems; }); - let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); + let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; - if (eventData && eventData.type !== 'StaticMachine') { + if (eventData) { if (eventData.type === 'Conveyor' && eventData) { const backendEventData = { @@ -229,7 +229,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje newEventData.position = newFloorItem.position; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; - setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => event.modeluuid === newFloorItem.modeluuid ? { ...event, ...newEventData } @@ -280,7 +280,113 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; - setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { + const updatedEvents = (prevEvents || []).map(event => + event.modeluuid === newFloorItem.modeluuid + ? { ...event, ...newEventData } + : event + ); + return updatedEvents; + }); + + socket.emit("v2:model-asset:add", data); + + } else if (eventData.type === 'StaticMachine' && eventData) { + + const backendEventData = { + type: 'StaticMachine', + points: eventData.points, + }; + + // REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // obj.userData.modelId, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // false, + // true, + // { type: backendEventData.type, points: backendEventData.points } + // ); + + //SOCKET + + const data = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + // eventData: { type: backendEventData.type, points: backendEventData.points }, + socketId: socket.id, + }; + + const newEventData: any = { type: backendEventData.type, points: backendEventData.points }; + newEventData.modeluuid = newFloorItem.modeluuid; + newEventData.modelName = newFloorItem.modelname; + newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; + + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { + const updatedEvents = (prevEvents || []).map(event => + event.modeluuid === newFloorItem.modeluuid + ? { ...event, ...newEventData } + : event + ); + return updatedEvents; + }); + + socket.emit("v2:model-asset:add", data); + + } else if (eventData.type === 'ArmBot' && eventData) { + + const backendEventData = { + type: 'ArmBot', + points: eventData.points, + }; + + // REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // obj.userData.modelId, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // false, + // true, + // { type: backendEventData.type, points: backendEventData.points } + // ); + + //SOCKET + + const data = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + // eventData: { type: backendEventData.type, points: backendEventData.points }, + socketId: socket.id, + }; + + const newEventData: any = { type: backendEventData.type, points: backendEventData.points }; + newEventData.modeluuid = newFloorItem.modeluuid; + newEventData.modelName = newFloorItem.modelname; + newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; + + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => event.modeluuid === newFloorItem.modeluuid ? { ...event, ...newEventData } diff --git a/app/src/modules/scene/controls/selection/rotateControls.tsx b/app/src/modules/scene/controls/selection/rotateControls.tsx index 020705d..cf1ac83 100644 --- a/app/src/modules/scene/controls/selection/rotateControls.tsx +++ b/app/src/modules/scene/controls/selection/rotateControls.tsx @@ -184,13 +184,12 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo return updatedItems; }); - let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); - console.log('eventData: ', eventData); + let eventData: Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema | undefined = simulationStates.find((events) => events.modeluuid === obj.userData.modeluuid); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; - if (eventData && eventData.type !== 'StaticMachine') { + if (eventData) { if (eventData.type === 'Conveyor' && eventData) { const backendEventData = { @@ -233,9 +232,8 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; - console.log('newEventData: ', newEventData); - setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => event.modeluuid === newFloorItem.modeluuid ? { ...event, ...newEventData } @@ -287,7 +285,113 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; - setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { + const updatedEvents = (prevEvents || []).map(event => + event.modeluuid === newFloorItem.modeluuid + ? { ...event, ...newEventData } + : event + ); + return updatedEvents; + }); + + socket.emit("v2:model-asset:add", data); + + } else if (eventData.type === 'StaticMachine' && eventData) { + + const backendEventData = { + type: 'StaticMachine', + points: eventData.points, + }; + + // REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // obj.userData.modelId, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // false, + // true, + // { type: backendEventData.type, points: backendEventData.points } + // ); + + //SOCKET + + const data = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + // eventData: { type: backendEventData.type, points: backendEventData.points }, + socketId: socket.id, + }; + + const newEventData: any = { type: backendEventData.type, points: backendEventData.points }; + newEventData.modeluuid = newFloorItem.modeluuid; + newEventData.modelName = newFloorItem.modelname; + newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; + + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { + const updatedEvents = (prevEvents || []).map(event => + event.modeluuid === newFloorItem.modeluuid + ? { ...event, ...newEventData } + : event + ); + return updatedEvents; + }); + + socket.emit("v2:model-asset:add", data); + + } else if (eventData.type === 'ArmBot' && eventData) { + + const backendEventData = { + type: 'ArmBot', + points: eventData.points, + }; + + // REST + + // await setFloorItemApi( + // organization, + // obj.uuid, + // obj.userData.name, + // obj.userData.modelId, + // [worldPosition.x, worldPosition.y, worldPosition.z], + // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, + // false, + // true, + // { type: backendEventData.type, points: backendEventData.points } + // ); + + //SOCKET + + const data = { + organization, + modeluuid: newFloorItem.modeluuid, + modelname: newFloorItem.modelname, + modelfileID: newFloorItem.modelfileID, + position: newFloorItem.position, + rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, + isLocked: false, + isVisible: true, + // eventData: { type: backendEventData.type, points: backendEventData.points }, + socketId: socket.id, + }; + + const newEventData: any = { type: backendEventData.type, points: backendEventData.points }; + newEventData.modeluuid = newFloorItem.modeluuid; + newEventData.modelName = newFloorItem.modelname; + newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; + + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => event.modeluuid === newFloorItem.modeluuid ? { ...event, ...newEventData } diff --git a/app/src/modules/scene/controls/selection/selectionControls.tsx b/app/src/modules/scene/controls/selection/selectionControls.tsx index 8a464d5..686bf42 100644 --- a/app/src/modules/scene/controls/selection/selectionControls.tsx +++ b/app/src/modules/scene/controls/selection/selectionControls.tsx @@ -240,7 +240,7 @@ const SelectionControls: React.FC = () => { } }); - setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { + setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { const updatedEvents = (prevEvents || []).filter(event => event.modeluuid !== selectedMesh.uuid); return updatedEvents; }); diff --git a/app/src/modules/simulation/path/pathConnector.tsx b/app/src/modules/simulation/path/pathConnector.tsx index 8a295be..805821c 100644 --- a/app/src/modules/simulation/path/pathConnector.tsx +++ b/app/src/modules/simulation/path/pathConnector.tsx @@ -1,9 +1,9 @@ import { useFrame, useThree } from '@react-three/fiber'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import * as THREE from 'three'; import * as Types from '../../../types/world/worldTypes'; import { QuadraticBezierLine } from '@react-three/drei'; -import { useIsConnecting, useSimulationStates, useSocketStore } from '../../../store/store'; +import { useIsConnecting, useRenderDistance, useSimulationStates, useSocketStore } from '../../../store/store'; import useModuleStore from '../../../store/useModuleStore'; import { usePlayButtonStore } from '../../../store/usePlayButtonStore'; import { setEventApi } from '../../../services/factoryBuilder/assest/floorAsset/setEventsApt'; @@ -11,28 +11,21 @@ import { setEventApi } from '../../../services/factoryBuilder/assest/floorAsset/ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject }) { const { activeModule } = useModuleStore(); const { gl, raycaster, scene, pointer, camera } = useThree(); + const { renderDistance } = useRenderDistance(); const { setIsConnecting } = useIsConnecting(); const { simulationStates, setSimulationStates } = useSimulationStates(); const { isPlaying } = usePlayButtonStore(); const { socket } = useSocketStore(); + const groupRefs = useRef<{ [key: string]: any }>({}); - const [firstSelected, setFirstSelected] = useState<{ - modelUUID: string; - sphereUUID: string; - position: THREE.Vector3; - isCorner: boolean; - } | null>(null); + const [firstSelected, setFirstSelected] = useState<{ modelUUID: string; sphereUUID: string; position: THREE.Vector3; isCorner: boolean; } | null>(null); const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3, end: THREE.Vector3, mid: THREE.Vector3 } | null>(null); const [helperlineColor, setHelperLineColor] = useState('red'); - const updatePathConnections = ( - fromModelUUID: string, - fromPointUUID: string, - toModelUUID: string, - toPointUUID: string - ) => { + const updatePathConnections = (fromModelUUID: string, fromPointUUID: string, toModelUUID: string, toPointUUID: string) => { const updatedPaths = simulationStates.map(path => { if (path.type === 'Conveyor') { + // Handle outgoing connections from Conveyor if (path.modeluuid === fromModelUUID) { return { ...path, @@ -61,6 +54,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }) }; } + // Handle incoming connections to Conveyor else if (path.modeluuid === toModelUUID) { return { ...path, @@ -167,82 +161,170 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec } return path; } - // else if (path.type === 'StaticMachine') { - // if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) { - // const newTarget = { - // modelUUID: toModelUUID, - // pointUUID: toPointUUID - // }; - // const existingTargets = path.points.connections.targets || []; + else if (path.type === 'StaticMachine') { + // Handle outgoing connections from StaticMachine + if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) { + const newTarget = { + modelUUID: toModelUUID, + pointUUID: toPointUUID + }; - // // Check if target is an ArmBot - // const toPath = simulationStates.find(p => p.modeluuid === toModelUUID); - // if (toPath?.type !== 'ArmBot') { - // console.log("StaticMachine can only connect to ArmBot"); - // return path; - // } + // Ensure target is an ArmBot + const toPath = simulationStates.find(p => p.modeluuid === toModelUUID); + if (toPath?.type !== 'ArmBot') { + console.log("StaticMachine can only connect to ArmBot"); + return path; + } - // // Check if already has a connection - // if (existingTargets.length >= 1) { - // console.log("StaticMachine can have only one connection"); - // return path; - // } + const existingTargets = path.points.connections.targets || []; - // if (!existingTargets.some(target => - // target.modelUUID === newTarget.modelUUID && - // target.pointUUID === newTarget.pointUUID - // )) { - // return { - // ...path, - // points: { - // ...path.points, - // connections: { - // ...path.points.connections, - // targets: [...existingTargets, newTarget] - // } - // } - // }; - // } - // } - // // Handle incoming connections to StaticMachine - // else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) { - // const reverseTarget = { - // modelUUID: fromModelUUID, - // pointUUID: fromPointUUID - // }; - // const existingTargets = path.points.connections.targets || []; + // Allow only one connection + if (existingTargets.length >= 1) { + console.log("StaticMachine can only have one connection"); + return path; + } - // // Check if source is an ArmBot - // const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID); - // if (fromPath?.type !== 'ArmBot') { - // console.log("StaticMachine can only connect to ArmBot"); - // return path; - // } + if (!existingTargets.some(target => + target.modelUUID === newTarget.modelUUID && + target.pointUUID === newTarget.pointUUID + )) { + return { + ...path, + points: { + ...path.points, + connections: { + ...path.points.connections, + targets: [...existingTargets, newTarget] + } + } + }; + } + } - // // Check if already has a connection - // if (existingTargets.length >= 1) { - // console.log("StaticMachine can have only one connection"); - // return path; - // } + // Handle incoming connections to StaticMachine + else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) { + const reverseTarget = { + modelUUID: fromModelUUID, + pointUUID: fromPointUUID + }; + + const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID); + if (fromPath?.type !== 'ArmBot') { + console.log("StaticMachine can only be connected from ArmBot"); + return path; + } + + const existingTargets = path.points.connections.targets || []; + + if (existingTargets.length >= 1) { + console.log("StaticMachine can only have one connection"); + return path; + } + + if (!existingTargets.some(target => + target.modelUUID === reverseTarget.modelUUID && + target.pointUUID === reverseTarget.pointUUID + )) { + return { + ...path, + points: { + ...path.points, + connections: { + ...path.points.connections, + targets: [...existingTargets, reverseTarget] + } + } + }; + } + } + return path; + } + else if (path.type === 'ArmBot') { + // Handle outgoing connections from ArmBot + if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) { + const newTarget = { + modelUUID: toModelUUID, + pointUUID: toPointUUID + }; + + const toPath = simulationStates.find(p => p.modeluuid === toModelUUID); + if (!toPath) return path; + + const existingTargets = path.points.connections.targets || []; + + // Check if connecting to a StaticMachine and already connected to one + const alreadyConnectedToStatic = existingTargets.some(target => { + const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID); + return targetPath?.type === 'StaticMachine'; + }); + + if (toPath.type === 'StaticMachine') { + if (alreadyConnectedToStatic) { + console.log("ArmBot can only connect to one StaticMachine"); + return path; + } + } + + if (!existingTargets.some(target => + target.modelUUID === newTarget.modelUUID && + target.pointUUID === newTarget.pointUUID + )) { + return { + ...path, + points: { + ...path.points, + connections: { + ...path.points.connections, + targets: [...existingTargets, newTarget] + } + } + }; + } + } + + // Handle incoming connections to ArmBot + else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) { + const reverseTarget = { + modelUUID: fromModelUUID, + pointUUID: fromPointUUID + }; + + const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID); + if (!fromPath) return path; + + const existingTargets = path.points.connections.targets || []; + + const alreadyConnectedFromStatic = existingTargets.some(target => { + const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID); + return targetPath?.type === 'StaticMachine'; + }); + + if (fromPath.type === 'StaticMachine') { + if (alreadyConnectedFromStatic) { + console.log("ArmBot can only be connected from one StaticMachine"); + return path; + } + } + + if (!existingTargets.some(target => + target.modelUUID === reverseTarget.modelUUID && + target.pointUUID === reverseTarget.pointUUID + )) { + return { + ...path, + points: { + ...path.points, + connections: { + ...path.points.connections, + targets: [...existingTargets, reverseTarget] + } + } + }; + } + } + return path; + } - // if (!existingTargets.some(target => - // target.modelUUID === reverseTarget.modelUUID && - // target.pointUUID === reverseTarget.pointUUID - // )) { - // return { - // ...path, - // points: { - // ...path.points, - // connections: { - // ...path.points.connections, - // targets: [...existingTargets, reverseTarget] - // } - // } - // }; - // } - // } - // return path; - // } return path; }); @@ -252,10 +334,10 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec path.modeluuid === fromModelUUID || path.modeluuid === toModelUUID ); - updateBackend(updatedPathDetails); + // updateBackend(updatedPathDetails); }; - const updateBackend = async (updatedPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => { + const updateBackend = async (updatedPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { if (updatedPaths.length === 0) return; const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : ""; @@ -437,6 +519,69 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec return; } + // Check if StaticMachine is involved in the connection + if ((firstPath?.type === 'StaticMachine' && secondPath?.type !== 'ArmBot') || + (secondPath?.type === 'StaticMachine' && firstPath?.type !== 'ArmBot')) { + console.log("StaticMachine can only connect to ArmBot"); + return; + } + + // Check if StaticMachine already has a connection + if (firstPath?.type === 'StaticMachine') { + const staticConnections = firstPath.points.connections.targets.length; + if (staticConnections >= 1) { + console.log("StaticMachine can only have one connection"); + return; + } + } + if (secondPath?.type === 'StaticMachine') { + const staticConnections = secondPath.points.connections.targets.length; + if (staticConnections >= 1) { + console.log("StaticMachine can only have one connection"); + return; + } + } + + // Check if ArmBot is involved + if ((firstPath?.type === 'ArmBot' && secondPath?.type === 'StaticMachine') || + (secondPath?.type === 'ArmBot' && firstPath?.type === 'StaticMachine')) { + + const armBotPath = firstPath?.type === 'ArmBot' ? firstPath : secondPath; + const staticPath = firstPath?.type === 'StaticMachine' ? firstPath : secondPath; + + const armBotConnections = armBotPath.points.connections.targets || []; + const alreadyConnectedToStatic = armBotConnections.some(target => { + const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID); + return targetPath?.type === 'StaticMachine'; + }); + + if (alreadyConnectedToStatic) { + console.log("ArmBot can only connect to one StaticMachine"); + return; + } + + const staticConnections = staticPath.points.connections.targets.length; + if (staticConnections >= 1) { + console.log("StaticMachine can only have one connection"); + return; + } + } + + // Prevent ArmBot ↔ ArmBot + if (firstPath?.type === 'ArmBot' && secondPath?.type === 'ArmBot') { + console.log("Cannot connect two ArmBots together"); + return; + } + + // If one is ArmBot, ensure the other is StaticMachine or Conveyor + if (firstPath?.type === 'ArmBot' || secondPath?.type === 'ArmBot') { + const otherType = firstPath?.type === 'ArmBot' ? secondPath?.type : firstPath?.type; + if (otherType !== 'StaticMachine' && otherType !== 'Conveyor') { + console.log("ArmBot can only connect to Conveyors or one StaticMachine"); + return; + } + } + // At least one must be start/end point if (!firstSelected.isCorner && !isStartOrEnd) { console.log("At least one of the selected spheres must be a start or end point."); @@ -489,6 +634,15 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }; }, [camera, scene, raycaster, firstSelected, simulationStates]); + useFrame(() => { + Object.values(groupRefs.current).forEach((group) => { + if (group) { + const distance = new THREE.Vector3(...group.position.toArray()).distanceTo(camera.position); + group.visible = ((distance <= renderDistance) && !isPlaying); + } + }); + }); + useFrame(() => { if (firstSelected) { raycaster.setFromCamera(pointer, camera); @@ -574,12 +728,50 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec (firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') || (secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor'); + // Check if StaticMachine is connecting to non-ArmBot + const isStaticMachineToNonArmBot = + (firstPath?.type === 'StaticMachine' && secondPath?.type !== 'ArmBot') || + (secondPath?.type === 'StaticMachine' && firstPath?.type !== 'ArmBot'); + + // Check if StaticMachine already has a connection + const isStaticMachineAtMaxConnections = + (firstPath?.type === 'StaticMachine' && firstPath.points.connections.targets.length >= 1) || + (secondPath?.type === 'StaticMachine' && secondPath.points.connections.targets.length >= 1); + + // Check if ArmBot is connecting to StaticMachine + const isArmBotToStaticMachine = + (firstPath?.type === 'ArmBot' && secondPath?.type === 'StaticMachine') || + (secondPath?.type === 'ArmBot' && firstPath?.type === 'StaticMachine'); + + // Prevent multiple StaticMachine connections to ArmBot + let isArmBotAlreadyConnectedToStatic = false; + if (isArmBotToStaticMachine) { + const armBotPath = firstPath?.type === 'ArmBot' ? firstPath : secondPath; + isArmBotAlreadyConnectedToStatic = armBotPath.points.connections.targets.some(target => { + const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID); + return targetPath?.type === 'StaticMachine'; + }); + } + + // Prevent ArmBot to ArmBot + const isArmBotToArmBot = firstPath?.type === 'ArmBot' && secondPath?.type === 'ArmBot'; + + // If ArmBot is involved, other must be Conveyor or StaticMachine + const isArmBotToInvalidType = (firstPath?.type === 'ArmBot' || secondPath?.type === 'ArmBot') && + !(firstPath?.type === 'Conveyor' || firstPath?.type === 'StaticMachine' || + secondPath?.type === 'Conveyor' || secondPath?.type === 'StaticMachine'); + if ( !isDuplicateConnection && !isVehicleToVehicle && !isNonVehicleAlreadyConnected && !isVehicleAtMaxConnections && !isVehicleConnectingToNonConveyor && + !isStaticMachineToNonArmBot && + !isStaticMachineAtMaxConnections && + !isArmBotToArmBot && + !isArmBotToInvalidType && + !isArmBotAlreadyConnectedToStatic && firstSelected.sphereUUID !== sphereUUID && firstSelected.modelUUID !== modelUUID && (firstSelected.isCorner || isConnectable) && @@ -596,6 +788,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec } else { isInvalidConnection = true; } + } if (snappedSphere) { @@ -633,7 +826,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec }); return ( - + {simulationStates.flatMap(path => { if (path.type === 'Conveyor') { return path.points.flatMap(point => @@ -652,7 +845,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec const distance = fromWorldPosition.distanceTo(toWorldPosition); const heightFactor = Math.max(0.5, distance * 0.2); - const midPoint = new THREE.Vector3( (fromWorldPosition.x + toWorldPosition.x) / 2, Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor, @@ -662,6 +854,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec return ( (groupRefs.current[`${point.uuid}-${target.pointUUID}-${index}`] = el!)} start={fromWorldPosition.toArray()} end={toWorldPosition.toArray()} mid={midPoint.toArray()} @@ -676,7 +869,9 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec return null; }) ); - } else if (path.type === 'Vehicle') { + } + + if (path.type === 'Vehicle') { return path.points.connections.targets.map((target, index) => { const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid); const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID); @@ -689,7 +884,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec const distance = fromWorldPosition.distanceTo(toWorldPosition); const heightFactor = Math.max(0.5, distance * 0.2); - const midPoint = new THREE.Vector3( (fromWorldPosition.x + toWorldPosition.x) / 2, Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor, @@ -699,6 +893,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec return ( (groupRefs.current[`${path.points.uuid}-${target.pointUUID}-${index}`] = el!)} start={fromWorldPosition.toArray()} end={toWorldPosition.toArray()} mid={midPoint.toArray()} @@ -713,6 +908,48 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec return null; }); } + + if (path.type === 'StaticMachine') { + return path.points.connections.targets.map((target, index) => { + const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID); + if (targetPath?.type !== 'ArmBot') return null; + + const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid); + const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID); + + if (fromSphere && toSphere) { + const fromWorldPosition = new THREE.Vector3(); + const toWorldPosition = new THREE.Vector3(); + fromSphere.getWorldPosition(fromWorldPosition); + toSphere.getWorldPosition(toWorldPosition); + + const distance = fromWorldPosition.distanceTo(toWorldPosition); + const heightFactor = Math.max(0.5, distance * 0.2); + const midPoint = new THREE.Vector3( + (fromWorldPosition.x + toWorldPosition.x) / 2, + Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor, + (fromWorldPosition.z + toWorldPosition.z) / 2 + ); + + return ( + (groupRefs.current[`${path.points.uuid}-${target.pointUUID}-${index}`] = el!)} + start={fromWorldPosition.toArray()} + end={toWorldPosition.toArray()} + mid={midPoint.toArray()} + color="#42a5f5" + lineWidth={4} + dashed + dashSize={0.75} + dashScale={20} + /> + ); + } + return null; + }); + } + return []; })} @@ -730,6 +967,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec )} ); + } export default PathConnector; \ No newline at end of file diff --git a/app/src/modules/simulation/path/pathCreation.tsx b/app/src/modules/simulation/path/pathCreation.tsx index 62bb79e..839cf39 100644 --- a/app/src/modules/simulation/path/pathCreation.tsx +++ b/app/src/modules/simulation/path/pathCreation.tsx @@ -206,6 +206,7 @@ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObjec return ( (groupRefs.current[path.modeluuid] = el!)} position={path.position} @@ -271,10 +272,11 @@ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObjec })} ); - } else if (path.type === "Vehicle" || path.type === "StaticMachine") { + } else if (path.type === "Vehicle") { return ( (groupRefs.current[path.modeluuid] = el!)} position={path.position} @@ -323,6 +325,114 @@ function PathCreation({ pathsGroupRef, }: { pathsGroupRef: React.MutableRefObjec ); + } else if (path.type === "StaticMachine") { + return ( + (groupRefs.current[path.modeluuid] = el!)} + position={path.position} + rotation={path.rotation} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedPath({ + path, + group: groupRefs.current[path.modeluuid], + }); + setSelectedActionSphere(null); + setTransformMode(null); + setSubModule("mechanics"); + }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSelectedPath(null); + setSubModule("properties"); + }} + > + (sphereRefs.current[path.points.uuid] = el!)} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedActionSphere({ + path, + points: sphereRefs.current[path.points.uuid], + }); + setSubModule("mechanics"); + setSelectedPath(null); + }} + userData={{ points: path.points, path }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSubModule("properties"); + setSelectedActionSphere(null); + }} + > + + + + ); + } else if (path.type === "ArmBot") { + return ( + (groupRefs.current[path.modeluuid] = el!)} + position={path.position} + rotation={path.rotation} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedPath({ + path, + group: groupRefs.current[path.modeluuid], + }); + setSelectedActionSphere(null); + setTransformMode(null); + setSubModule("mechanics"); + }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSelectedPath(null); + setSubModule("properties"); + }} + > + (sphereRefs.current[path.points.uuid] = el!)} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedActionSphere({ + path, + points: sphereRefs.current[path.points.uuid], + }); + setSubModule("mechanics"); + setSelectedPath(null); + }} + userData={{ points: path.points, path }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSubModule("properties"); + setSelectedActionSphere(null); + }} + > + + + + ); } return null; })} diff --git a/app/src/modules/visualization/handleSaveTemplate.ts b/app/src/modules/visualization/handleSaveTemplate.ts index e5f90ab..f192bec 100644 --- a/app/src/modules/visualization/handleSaveTemplate.ts +++ b/app/src/modules/visualization/handleSaveTemplate.ts @@ -64,7 +64,8 @@ export const handleSaveTemplate = async ({ floatingWidget, widgets3D, }; - + + console.log('newTemplate: ', newTemplate); // Extract organization from email const email = localStorage.getItem("email") || ""; const organization = email.includes("@") diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index 88fd467..54fe61f 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -56,7 +56,7 @@ const Project: React.FC = () => { return (
- {/* {loadingProgress && } */} + {loadingProgress && } {!isPlaying && ( <> {toggleThreeD && } diff --git a/app/src/services/factoryBuilder/zones/deleteZoneApi.ts b/app/src/services/factoryBuilder/zones/deleteZoneApi.ts index fbe4a83..2537fb6 100644 --- a/app/src/services/factoryBuilder/zones/deleteZoneApi.ts +++ b/app/src/services/factoryBuilder/zones/deleteZoneApi.ts @@ -15,7 +15,7 @@ export const deleteZonesApi = async (userId: string, organization: string, zoneI } const result = await response.json(); - console.log('result: ', result); + return result; } catch (error) { if (error instanceof Error) { diff --git a/app/src/services/realTimeVisulization/zoneData/getZones.ts b/app/src/services/realTimeVisulization/zoneData/getZones.ts index 8dbf79a..b189050 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZones.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZones.ts @@ -2,8 +2,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR // let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getZoneData = async (zoneId: string, organization: string) => { - console.log("organization: ", organization); - console.log("zoneId: ", zoneId); + try { const response = await fetch( `${url_Backend_dwinzo}/api/v2/A_zone/${zoneId}/${organization}`, diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 725180b..89cd1a7 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -347,12 +347,12 @@ export const useSelectedPath = create((set: any) => ({ })); interface SimulationPathsStore { - simulationStates: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]; + simulationStates: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]; setSimulationStates: ( paths: - | (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[] - | ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[] - ) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) + | (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[] + | ((prev: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[] + ) => (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) ) => void; } diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 465af2c..3b14aac 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -70,6 +70,67 @@ position: relative; overflow: auto; + .template-list { + display: flex; + flex-direction: column; + gap: 1rem; + padding: 1rem; + min-height: 50vh; + max-height: 60vh; + } + + .template-item { + border: 1px solid #e0e0e0; + border-radius: 8px; + padding: 1rem; + transition: box-shadow 0.3s ease; + } + + .template-image-container { + position: relative; + padding-bottom: 56.25%; // 16:9 aspect ratio + } + + .template-image { + position: absolute; + width: 100%; + height: 100%; + object-fit: contain; + border-radius: 4px; + cursor: pointer; + transition: transform 0.3s ease; + } + + .template-details { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 0.5rem; + } + + .template-name { + cursor: pointer; + font-weight: 500; + } + + .delete-button { + padding: 0.25rem 0.5rem; + background: #ff4444; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + transition: opacity 0.3s ease; + } + + .no-templates { + text-align: center; + color: #666; + padding: 2rem; + grid-column: 1 / -1; + } + + .widget-left-sideBar { min-height: 50vh; max-height: 60vh; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index f26ac06..cc3f791 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -24,9 +24,17 @@ } .floating { - width: 100%; - max-width: 250px; - min-height: 83px; + + + width: calc(var(--realTimeViz-container-width) * 0.2); + height: calc(var(--realTimeViz-container-width) * 0.05); + + min-width: 250px; + max-width: 300px; + + min-height: 83px !important; + // max-height: 100px !important; + background: var(--background-color); border: 1.23px solid var(--border-color); box-shadow: 0px 4.91px 4.91px 0px #0000001c; @@ -60,9 +68,8 @@ display: flex; background-color: var(--background-color); position: absolute; - bottom: 10px; + // bottom: 10px; left: 50%; - transform: translate(-50%, 0); gap: 6px; border-radius: 8px; @@ -70,6 +77,7 @@ overflow: auto; max-width: calc(100% - 500px); z-index: 3; + transform: translate(-50%, -100%); &::-webkit-scrollbar { display: none; @@ -116,8 +124,8 @@ } .zone-wrapper.bottom { - bottom: calc(var(--realTimeViz-container-height) * 0.27); - bottom: 200px; + top: var(--bottomWidth); + // bottom: 200px; } .content-container { @@ -138,7 +146,7 @@ display: flex; background-color: rgba(224, 223, 255, 0.5); position: absolute; - bottom: 10px; + // bottom: 10px; left: 50%; transform: translate(-50%, 0); gap: 6px; @@ -203,9 +211,9 @@ .chart-container { width: 100%; - min-height: 150px; + max-height: 100%; - // border: 1px dashed var(--background-color-gray); + border: 1px dashed var(--background-color-gray); border-radius: 8px; box-shadow: var(--box-shadow-medium); padding: 6px 0; @@ -306,7 +314,6 @@ min-height: 150px; .chart-container { - min-width: 160px; } } @@ -324,14 +331,12 @@ left: 0; top: 0; bottom: 0; - - } &.right-panel { right: 0; top: 0; - bottom: 0 + bottom: 0; } &.left-panel, @@ -342,12 +347,11 @@ flex-direction: column; width: 100%; - gap: 6px; .chart-container { width: 100%; - min-height: 160px; + min-height: 150px; max-height: 100%; border-radius: 8px; box-shadow: var(--box-shadow-medium); @@ -355,8 +359,6 @@ background-color: var(--background-color); position: relative; } - - } } } @@ -368,8 +370,8 @@ .playingFlase { .zone-wrapper.bottom { - bottom: calc(var(--realTimeViz-container-height) * 0.3); - bottom: 210px; + top: var(--bottomWidth); + // bottom: 210px; } } @@ -658,9 +660,6 @@ } } } - - - } } @@ -756,14 +755,13 @@ } .connectionSuccess { - outline-color: #43C06D; + outline-color: #43c06d; } .connectionFails { outline-color: #ffe3e0; } - .editWidgetOptions { position: absolute; // top: 50%; diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index 7baf5e0..fce09b1 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -329,6 +329,7 @@ interface StaticMachineEventsSchema { connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; }; position: [number, number, number]; + rotation: [number, number, number]; } interface ArmBotEventsSchema { @@ -343,6 +344,7 @@ interface ArmBotEventsSchema { connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; }; position: [number, number, number]; + rotation: [number, number, number]; } export type EventData = { diff --git a/app/src/utils/outerClick.ts b/app/src/utils/outerClick.ts index de8f7ef..280b3f0 100644 --- a/app/src/utils/outerClick.ts +++ b/app/src/utils/outerClick.ts @@ -1,7 +1,7 @@ import React from "react"; interface OuterClickProps { - contextClassName: string; + contextClassName: string[]; // Make sure this is an array of strings setMenuVisible: React.Dispatch>; } @@ -11,8 +11,12 @@ export default function OuterClick({ }: OuterClickProps) { const handleClick = (event: MouseEvent) => { const targets = event.target as HTMLElement; - // Check if the click is outside the selectable-dropdown-wrapper - if (!targets.closest(`.${contextClassName}`)) { + // Check if the click is outside of any of the provided class names + const isOutside = contextClassName.every( + (className) => !targets.closest(`.${className}`) + ); + + if (isOutside) { setMenuVisible(false); // Close the menu by updating the state } }; @@ -23,7 +27,7 @@ export default function OuterClick({ return () => { document.removeEventListener("click", handleClick); }; - }, []); + }, [contextClassName]); // Add contextClassName to dependency array to handle any changes return null; // This component doesn't render anything }