import { useThree } from "@react-three/fiber"; import React, { useState, useEffect, useRef } from "react"; import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../store/store"; import useModuleStore from "../../../store/useModuleStore"; import { ThreeState } from "../../../types/world/worldTypes"; import * as THREE from "three"; import Throughput from "../../layout/3D-cards/cards/Throughput"; import ProductionCapacity from "../../layout/3D-cards/cards/ProductionCapacity"; import ReturnOfInvestment from "../../layout/3D-cards/cards/ReturnOfInvestment"; import StateWorking from "../../layout/3D-cards/cards/StateWorking"; import { useSelectedZoneStore } from "../../../store/useZoneStore"; import { generateUniqueId } from "../../../functions/generateUniqueId"; import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget"; import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData"; import { use3DWidget } from "../../../store/useDroppedObjectsStore"; import { useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../store/useZone3DWidgetStore"; import { useWidgetStore } from "../../../store/useWidgetStore"; import EditWidgetOption from "../menu/EditWidgetOption"; export default function Dropped3dWidgets() { const { widgetSelect } = useAsset3dWidget(); const { activeModule } = useModuleStore(); const { raycaster, gl, scene, mouse, camera }: ThreeState = useThree(); const { widgetSubOption } = useWidgetSubOption(); const { selectedZone } = useSelectedZoneStore(); const { top, setTop } = useTopData() const { left, setLeft } = useLeftData() const { rightSelect, setRightSelect } = useRightSelected() // ✅ Use Zustand Store instead of useState const { zoneWidgetData, setZoneWidgetData, addWidget, updateWidgetPosition } = useZoneWidgetStore(); const { setWidgets3D } = use3DWidget(); const { visualizationSocket } = useSocketStore(); const { rightClickSelected, setRightClickSelected } = useRightClickSelected() 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()); // let [verticalPlane, setFloorPlanesVertical] = useState( // new THREE.Plane(new THREE.Vector3(0, 1, 0)) // ); useEffect(() => { if (activeModule !== "visualization") return; if (!selectedZone.zoneId) return; const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; async function get3dWidgetData() { let result = await get3dWidgetZoneData(selectedZone.zoneId, organization); setWidgets3D(result); const formattedWidgets = result.map((widget: any) => ({ id: widget.id, type: widget.type, position: widget.position, })); setZoneWidgetData(selectedZone.zoneId, formattedWidgets); } get3dWidgetData(); }, [selectedZone.zoneId, activeModule]); useEffect(() => { if (activeModule !== "visualization") return; if (widgetSubOption === "Floating" || widgetSubOption === "2D") return; if (selectedZone.zoneName === "") return; const canvasElement = gl.domElement; const onDrop = async (event: DragEvent) => { event.preventDefault(); const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; if (!widgetSelect.startsWith("ui")) return; const group1 = scene.getObjectByName("itemsGroup"); if (!group1) return; const intersects = raycaster.intersectObjects(scene.children, true).filter( (intersect) => !intersect.object.name.includes("Roof") && !intersect.object.name.includes("agv-collider") && !intersect.object.name.includes("MeasurementReference") && !intersect.object.userData.isPathObject && !(intersect.object.type === "GridHelper") ); if (intersects.length > 0) { const { x, y, z } = intersects[0].point; const newWidget = { id: generateUniqueId(), type: widgetSelect, position: [x, y, z] as [number, number, number], }; let add3dWidget = { organization: organization, widget: newWidget, zoneId: selectedZone.zoneId } if (visualizationSocket) { visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget) } // let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget); // // if (response.message === "Widget created successfully") { addWidget(selectedZone.zoneId, newWidget); // } } }; canvasElement.addEventListener("drop", onDrop); return () => { canvasElement.removeEventListener("drop", onDrop); }; }, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]); const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; useEffect(() => { if (!rightClickSelected) return; const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; if (rightSelect === "Duplicate") { const widgetToDuplicate = activeZoneWidgets.find(w => w.id === rightClickSelected); if (!widgetToDuplicate) return; const newWidget = { id: generateUniqueId(), type: widgetToDuplicate.type, position: [ widgetToDuplicate.position[0] + 0.5, // Slightly shift position widgetToDuplicate.position[1], widgetToDuplicate.position[2] + 0.5, ] as [number, number, number], }; let add3dWidget = { organization, widget: newWidget, zoneId: selectedZone.zoneId }; // if (visualizationSocket) { // visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget); // } addWidget(selectedZone.zoneId, newWidget); setRightSelect(null); setRightClickSelected(null); } if (rightSelect === "Delete") { let deleteWidget = { organization, widgetId: rightClickSelected, zoneId: selectedZone.zoneId }; // if (visualizationSocket) { // visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget); // } setZoneWidgetData(selectedZone.zoneId, activeZoneWidgets.filter(w => w.id !== rightClickSelected)); setRightClickSelected(null); setRightSelect(null); } if (rightSelect === "Horizontal Move") { } if (rightSelect === "Vertical Move") { } }, [rightSelect, rightClickSelected]); useEffect(() => { const handleMouseMove = (event: MouseEvent) => { if (!rightClickSelected || !rightSelect) return; const selectedZone = Object.keys(zoneWidgetData).find(zoneId => zoneWidgetData[zoneId].some(widget => widget.id === rightClickSelected) ); if (!selectedZone) return; const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected); if (!selectedWidget) return; const rect = gl.domElement.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); if (rightSelect === "Horizontal Move" && raycaster.ray.intersectPlane(plane.current, planeIntersect.current)) { updateWidgetPosition(selectedZone, rightClickSelected, [ planeIntersect.current.x, selectedWidget.position[1], planeIntersect.current.z ]); } if (rightSelect === "Vertical Move") { if (raycaster.ray.intersectPlane(verticalPlane.current, planeIntersect.current)) { updateWidgetPosition(selectedZone, rightClickSelected, [ selectedWidget.position[0], planeIntersect.current.y, // Ensure Y value updates correctly selectedWidget.position[2] ]); } else { console.log("No Intersection with Vertical Plane"); } } }; const handleMouseUp = () => { if (rightClickSelected && (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move")) { setTimeout(() => { setRightClickSelected(null); setRightSelect(null); }, 50); } }; // Attach events to window instead of gl.domElement window.addEventListener("mousemove", handleMouseMove); window.addEventListener("mouseup", handleMouseUp); return () => { window.removeEventListener("mousemove", handleMouseMove); window.removeEventListener("mouseup", handleMouseUp); }; }, [rightClickSelected, rightSelect, zoneWidgetData, gl]); return ( <> {activeZoneWidgets.map(({ id, type, position }) => { const handleRightClick = (event: React.MouseEvent) => { event.preventDefault(); setRightClickSelected(id) }; switch (type) { case "ui-Widget 1": return ; case "ui-Widget 2": return ; case "ui-Widget 3": return ; case "ui-Widget 4": return ; default: return null; } })} ); }