From 238f76cb4c8f31832fbd651d4a77ac8599710bf1 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 2 Apr 2025 18:49:18 +0530 Subject: [PATCH] socket added for 3d and floating Widget --- .../sidebarLeft/visualization/Templates.tsx | 35 +++- app/src/components/ui/Tools.tsx | 4 +- .../ui/componets/DraggableWidget.tsx | 28 +++- .../ui/componets/Dropped3dWidget.tsx | 80 ++++----- .../ui/componets/DroppedFloatingWidgets.tsx | 65 ++++++-- app/src/components/ui/componets/Panel.tsx | 24 ++- .../ui/componets/RealTimeVisulization.tsx | 37 +++-- .../visualization/handleSaveTemplate.ts | 22 ++- .../visualization/realTimeVizSocket.dev.tsx | 155 ++++++++++++++++-- .../zoneData/deleteWidgetApi.ts | 9 +- app/src/store/useDroppedObjectsStore.ts | 43 +++-- app/src/store/useZone3DWidgetStore.ts | 33 ++++ 12 files changed, 401 insertions(+), 134 deletions(-) create mode 100644 app/src/store/useZone3DWidgetStore.ts diff --git a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx index 4b13429..b99b297 100644 --- a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx @@ -5,11 +5,13 @@ 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 { setSelectedZone, selectedZone } = useSelectedZoneStore(); + const { visualizationSocket } = useSocketStore(); useEffect(() => { async function templateData() { @@ -30,12 +32,18 @@ const Templates = () => { try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - - let response = await deleteTemplateApi(id, organization); - - if (response.message === "Template deleted successfully") { - removeTemplate(id); + let deleteTemplate = { + organization: organization, + templateID: id, } + if (visualizationSocket) { + 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); } @@ -48,9 +56,20 @@ const Templates = () => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - let response = await loadTempleteApi(template.id, selectedZone.zoneId, organization); + let loadingTemplate = { + organization: organization, + zoneId: selectedZone.zoneId, + templateID: template.id, + } + console.log('template: ', template); + console.log('loadingTemplate: ', loadingTemplate); - if (response.message === "Template placed in Zone") { + if (visualizationSocket) { + 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` @@ -64,7 +83,7 @@ const Templates = () => { useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val); }); } - } + // } } catch (error) { console.error("Error loading template:", error); } diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 71ebfe3..bb3928d 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -27,6 +27,7 @@ import { useMovePoint, useRefTextUpdate, useSelectedWallItem, + useSocketStore, useToggleView, useToolMode, useTransformMode, @@ -42,7 +43,7 @@ const Tools: React.FC = () => { const dropdownRef = useRef(null); const [openDrop, setOpenDrop] = useState(false); - + const { visualizationSocket } = useSocketStore(); const { activeModule } = useModuleStore(); const { isPlaying, setIsPlaying } = usePlayButtonStore(); const { addTemplate } = useTemplateStore(); @@ -397,6 +398,7 @@ const Tools: React.FC = () => { widgets3D, selectedZone, templates, + visualizationSocket }) } } diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx index 096779e..21fdf53 100644 --- a/app/src/components/ui/componets/DraggableWidget.tsx +++ b/app/src/components/ui/componets/DraggableWidget.tsx @@ -92,6 +92,7 @@ export const DraggableWidget = ({ widgetID: widget.id, organization: organization } + console.log('deleteWidget: ', deleteWidget); if (visualizationSocket) { visualizationSocket.emit("v2:viz-widget:delete", deleteWidget) } @@ -160,14 +161,27 @@ export const DraggableWidget = ({ id: `${widget.id}-copy-${Date.now()}`, }; - const response = await duplicateWidgetApi(selectedZone.zoneId, organization, duplicatedWidget); - - if (response?.message === "Widget created successfully") { - setSelectedZone((prevZone: any) => ({ - ...prevZone, - widgets: [...prevZone.widgets, duplicatedWidget], - })); + let duplicateWidget = { + organization: organization, + zoneId: selectedZone.zoneId, + widget: duplicatedWidget } + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-widget:add", duplicateWidget) + } + setSelectedZone((prevZone: any) => ({ + ...prevZone, + widgets: [...prevZone.widgets, duplicatedWidget], + })); + + // const response = await duplicateWidgetApi(selectedZone.zoneId, organization, duplicatedWidget); + + // if (response?.message === "Widget created successfully") { + // setSelectedZone((prevZone: any) => ({ + // ...prevZone, + // widgets: [...prevZone.widgets, duplicatedWidget], + // })); + // } } catch (error) { } finally { diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index 7ce1617..7da8039 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -1,7 +1,7 @@ import { useThree } from "@react-three/fiber"; import React, { useState, useEffect } from "react"; -import { useAsset3dWidget, useWidgetSubOption } from "../../../store/store"; +import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../store/store"; import useModuleStore from "../../../store/useModuleStore"; import { ThreeState } from "../../../types/world/worldTypes"; import * as THREE from "three"; @@ -14,21 +14,23 @@ 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 { useZoneWidgetStore } from "../../../store/useZone3DWidgetStore"; export default function Dropped3dWidgets() { const { widgetSelect } = useAsset3dWidget(); const { activeModule } = useModuleStore(); const { raycaster, gl, scene }: ThreeState = useThree(); - const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); - const { selectedZone } = useSelectedZoneStore(); // Get the currently active zone - // πŸ”₯ Store widget data (id, type, position) based on the selected zone - const [zoneWidgetData, setZoneWidgetData] = useState< - Record - >({}); - const { setWidgets3D } = use3DWidget() + const { widgetSubOption } = useWidgetSubOption(); + const { selectedZone } = useSelectedZoneStore(); + + // βœ… Use Zustand Store instead of useState + const { zoneWidgetData, setZoneWidgetData, addWidget } = useZoneWidgetStore(); + const { setWidgets3D } = use3DWidget(); + const { visualizationSocket } = useSocketStore(); + useEffect(() => { - if (activeModule !== "visualization") return - if (selectedZone.zoneName === "") return; + if (activeModule !== "visualization") return; + if (!selectedZone.zoneId) return; const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; @@ -36,37 +38,36 @@ export default function Dropped3dWidgets() { async function get3dWidgetData() { let result = await get3dWidgetZoneData(selectedZone.zoneId, organization); console.log('result: ', result); - setWidgets3D(result) - // Ensure the extracted data has id, type, and position correctly mapped + setWidgets3D(result); + const formattedWidgets = result.map((widget: any) => ({ id: widget.id, type: widget.type, position: widget.position, })); - setZoneWidgetData((prev) => ({ - ...prev, - [selectedZone.zoneId]: formattedWidgets, - })); + setZoneWidgetData(selectedZone.zoneId, formattedWidgets); } get3dWidgetData(); - }, [selectedZone.zoneId, activeModule]); useEffect(() => { if (activeModule !== "visualization") return; - if (widgetSubOption === "Floating") return; - if (widgetSubOption === "2D") return; - if (selectedZone.zoneName === "") return + if (widgetSubOption === "Floating" || widgetSubOption === "2D") return; + if (selectedZone.zoneName === "") return; + const canvasElement = gl.domElement; + const onDrop = async (event: DragEvent) => { - event.preventDefault(); // Prevent default browser behavior + 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") && @@ -75,40 +76,41 @@ export default function Dropped3dWidgets() { !intersect.object.userData.isPathObject && !(intersect.object.type === "GridHelper") ); + if (intersects.length > 0) { const { x, y, z } = intersects[0].point; - - // βœ… Explicitly define position as a tuple - const newWidget: { id: string; type: string; position: [number, number, number] } = { + const newWidget = { id: generateUniqueId(), type: widgetSelect, - position: [x, y, z], // Ensures TypeScript recognizes it as a tuple + position: [x, y, z] as [number, number, number], }; - - let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget) - console.log('response: ', response); - - if (response.message === "Widget created successfully") { - // βœ… Store widgets uniquely for each zone - setZoneWidgetData((prev) => ({ - ...prev, - [selectedZone.zoneId]: [...(prev[selectedZone.zoneId] || []), newWidget], - })); + let add3dWidget = { + organization: organization, + widget: newWidget, + zoneId: selectedZone.zoneId } + console.log('add3dWidget: ', add3dWidget); + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget) + } + + // let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget); + // console.log('response: ', response); + + // if (response.message === "Widget created successfully") { + addWidget(selectedZone.zoneId, newWidget); + // } } }; - canvasElement.addEventListener("drop", onDrop); return () => { canvasElement.removeEventListener("drop", onDrop); }; }, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]); - // Get widgets for the currently active zone const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; - console.log('activeZoneWidgets: ', activeZoneWidgets); return ( <> @@ -130,5 +132,3 @@ export default function Dropped3dWidgets() { ); } - - diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index 9c3f4c4..d80fd7c 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -21,6 +21,7 @@ import TotalCardComponent from "../realTimeVis/floating/TotalCardComponent"; import WarehouseThroughputComponent from "../realTimeVis/floating/WarehouseThroughputComponent"; import FleetEfficiencyComponent from "../realTimeVis/floating/FleetEfficiencyComponent"; import { useWidgetStore } from "../../../store/useWidgetStore"; +import { useSocketStore } from "../../../store/store"; interface DraggingState { zone: string; index: number; @@ -43,6 +44,7 @@ interface DraggingState { }; } const DroppedObjects: React.FC = () => { + const { visualizationSocket } = useSocketStore(); const zones = useDroppedObjectsStore((state) => state.zones); const [openKebabId, setOpenKebabId] = useState(null); const updateObjectPosition = useDroppedObjectsStore( @@ -98,29 +100,41 @@ const DroppedObjects: React.FC = () => { const zoneEntries = Object.entries(zones); if (zoneEntries.length === 0) return null; const [zoneName, zone] = zoneEntries[0]; + function handleDuplicate(zoneName: string, index: number) { setOpenKebabId(null) duplicateObject(zoneName, index); // Call the duplicateObject method from the store } - async function handleDelete(zoneName: string, id: string, index: number) { + async function handleDelete(zoneName: string, id: string) { try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - - let res = await deleteFloatingWidgetApi(id, organization); - console.log('res: ', res); - - if (res.message === "FloatingWidget deleted successfully") { - deleteObject(zoneName, id, index); // Call the deleteObject method from the store + + + let deleteFloatingWidget = { + floatWidgetID: id, + organization: organization, + zoneId: zone.zoneId } + + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget) + } + deleteObject(zoneName, id); + + // let res = await deleteFloatingWidgetApi(id, organization); + // s + + // if (res.message === "FloatingWidget deleted successfully") { + // deleteObject(zoneName, id, index); // Call the deleteObject method from the store + // } } catch (error) { - console.error("Error deleting floating widget:", error); + } } - const handlePointerDown = (event: React.PointerEvent, index: number) => { if ((event.target as HTMLElement).closest(".kebab-options") || (event.target as HTMLElement).closest(".kebab")) { return; // Prevent dragging when clicking on the kebab menu or its options @@ -278,15 +292,30 @@ const DroppedObjects: React.FC = () => { // Save to backend const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - const response = await addingFloatingWidgets(zone.zoneId, organization, { - ...zone.objects[draggingIndex.index], - position: boundedPosition, - }); - console.log('response: ', response); + // const response = await addingFloatingWidgets(zone.zoneId, organization, { + // ...zone.objects[draggingIndex.index], + // position: boundedPosition, + // }); + - if (response.message === "Widget updated successfully") { - updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); + let updateFloatingWidget = { + organization: organization, + widget: { + ...zone.objects[draggingIndex.index], + position: boundedPosition, + }, + index:draggingIndex.index, + 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); + // } // // Clean up // setDraggingIndex(null); @@ -298,7 +327,7 @@ const DroppedObjects: React.FC = () => { // animationRef.current = null; // } } catch (error) { - console.error("Error in handlePointerUp:", error); + } finally { // Clean up regardless of success or failure setDraggingIndex(null); @@ -390,7 +419,7 @@ const DroppedObjects: React.FC = () => {
{ event.stopPropagation(); - handleDelete(zoneName, obj.id, index); // Call the delete handler + handleDelete(zoneName, obj.id); // Call the delete handler }}>
diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index 56cdc06..ea0d576 100644 --- a/app/src/components/ui/componets/Panel.tsx +++ b/app/src/components/ui/componets/Panel.tsx @@ -153,8 +153,6 @@ const Panel: React.FC = ({ zoneId: selectedZone.zoneId, widget: newWidget } - console.log('newWidget: ', newWidget); - console.log('addWidget: ', addWidget); if (visualizationSocket) { visualizationSocket.emit("v2:viz-widget:add", addWidget) } @@ -163,18 +161,18 @@ const Panel: React.FC = ({ widgets: [...prev.widgets, newWidget], })); - // try { - // let response = await addingWidgets(selectedZone.zoneId, organization, 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); - // } + // if (response.message === "Widget created successfully") { + // setSelectedZone((prev) => ({ + // ...prev, + // widgets: [...prev.widgets, newWidget], + // })); + // } + } catch (error) { + console.error("Error adding widget:", error); + } }; diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index 4a40270..0b9ba4a 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -144,12 +144,6 @@ const RealTimeVisulization: React.FC = () => { }; console.log('newObject: ', newObject); - let response = await addingFloatingWidgets( - selectedZone.zoneId, - organization, - newObject - ); - // Only set zone if it’s not already in the store (prevents overwriting objects) const existingZone = useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; @@ -159,12 +153,28 @@ const RealTimeVisulization: React.FC = () => { .setZone(selectedZone.zoneName, selectedZone.zoneId); } - // Add the dropped object to the zone if the API call is successful - if (response.message === "FloatWidget created successfully") { - useDroppedObjectsStore - .getState() - .addObject(selectedZone.zoneName, newObject); + let addFloatingWidget = { + organization: organization, + widget: newObject, + zoneId: selectedZone.zoneId } + console.log('newObject: ', newObject); + + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-float:add", addFloatingWidget) + } + + // let response = await addingFloatingWidgets( + // selectedZone.zoneId, + // organization, + // newObject + // ); + // Add the dropped object to the zone if the API call is successful + // if (response.message === "FloatWidget created successfully") { + useDroppedObjectsStore + .getState() + .addObject(selectedZone.zoneName, newObject); + // } // Update floating widgets state setFloatingWidgets((prevWidgets) => ({ @@ -209,6 +219,11 @@ const RealTimeVisulization: React.FC = () => { {activeModule === "visualization" && selectedZone.zoneName !== "" && } {activeModule === "visualization" && } {/* */} + {/* + + */} {activeModule === "visualization" && ( <> => { try { // Check if the selected zone has any widgets @@ -47,7 +50,7 @@ export const handleSaveTemplate = async ({ // Capture visualization snapshot const snapshot = await captureVisualization(); - console.log("snapshot: ", snapshot); + // if (!snapshot) { // return; // } @@ -72,18 +75,25 @@ export const handleSaveTemplate = async ({ console.error("Organization could not be determined from email."); return; } + let saveTemplate = { + organization: organization, + template: newTemplate, + }; + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-template:add", saveTemplate); + } // Save the template try { - const response = await saveTemplateApi(organization, newTemplate); - console.log("Save API Response:", response); + addTemplate(newTemplate); + // const response = await saveTemplateApi(organization, newTemplate); + // console.log("Save API Response:", response); // Add template only if API call succeeds - addTemplate(newTemplate); } catch (apiError) { - console.error("Error saving template to API:", apiError); + // console.error("Error saving template to API:", apiError); } } catch (error) { - console.error("Error in handleSaveTemplate:", error); + // console.error("Error in handleSaveTemplate:", error); } }; diff --git a/app/src/modules/visualization/realTimeVizSocket.dev.tsx b/app/src/modules/visualization/realTimeVizSocket.dev.tsx index 4210d01..ad5e226 100644 --- a/app/src/modules/visualization/realTimeVizSocket.dev.tsx +++ b/app/src/modules/visualization/realTimeVizSocket.dev.tsx @@ -1,16 +1,27 @@ import { useEffect } from "react"; import { useSocketStore } from "../../store/store"; import { useSelectedZoneStore } from "../../store/useZoneStore"; +import { useDroppedObjectsStore } from "../../store/useDroppedObjectsStore"; +import { useZoneWidgetStore } from "../../store/useZone3DWidgetStore"; +import useTemplateStore from "../../store/useTemplateStore"; export default function SocketRealTimeViz() { const { visualizationSocket } = useSocketStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); + const deleteObject = useDroppedObjectsStore((state) => state.deleteObject); + const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject); + const updateObjectPosition = useDroppedObjectsStore((state) => state.updateObjectPosition); + const { addWidget } = useZoneWidgetStore() + const { templates, removeTemplate } = useTemplateStore(); + const { setTemplates } = useTemplateStore(); + useEffect(() => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; if (visualizationSocket) { //add panel response visualizationSocket.on("viz-panel:response:updates", (addPanel: any) => { + console.log('addPanel: ', addPanel); if (addPanel.success) { let addPanelData = addPanel.data.data setSelectedZone(addPanelData) @@ -18,32 +29,35 @@ export default function SocketRealTimeViz() { }) //delete panel response visualizationSocket.on("viz-panel:response:delete", (deletePanel: any) => { + console.log('deletePanel: ', deletePanel); if (deletePanel.success) { let deletePanelData = deletePanel.data.data setSelectedZone(deletePanelData) } }) - // add 2dWidget - visualizationSocket.on("viz-widget:response:updates", (response: any) => { - console.log('response: ', response); - if (response.success && response.data) { + // add 2dWidget response + visualizationSocket.on("viz-widget:response:updates", (add2dWidget: any) => { + console.log('add2dWidget: ', add2dWidget); + + if (add2dWidget.success && add2dWidget.data) { setSelectedZone((prev) => { const isWidgetAlreadyAdded = prev.widgets.some( - (widget) => widget.id === response.data.widgetData.id + (widget) => widget.id === add2dWidget.data.widgetData.id ); if (isWidgetAlreadyAdded) return prev; // Prevent duplicate addition return { ...prev, - zoneId: response.data.zoneId, - zoneName: response.data.zoneName, - widgets: [...prev.widgets, response.data.widgetData], // Append new widget + zoneId: add2dWidget.data.zoneId, + zoneName: add2dWidget.data.zoneName, + widgets: [...prev.widgets, add2dWidget.data.widgetData], // Append new widget }; }); } }); - //delete 2D Widget + //delete 2D Widget response visualizationSocket.on("viz-widget:response:delete", (deleteWidget: any) => { console.log('deleteWidget: ', deleteWidget); + if (deleteWidget?.success && deleteWidget.data) { setSelectedZone((prevZone: any) => ({ ...prevZone, @@ -53,12 +67,127 @@ export default function SocketRealTimeViz() { })); } }); + //add Floating Widget response + visualizationSocket.on("viz-float:response:updates", (addFloatingWidget: any) => { + console.log('addFloatingWidget: ', addFloatingWidget); + + if (addFloatingWidget.success) { + if (addFloatingWidget.success && addFloatingWidget.message === "FloatWidget created successfully") { + const state = useDroppedObjectsStore.getState(); + const zone = state.zones[addFloatingWidget.data.zoneName]; + if (!zone) { + state.setZone(addFloatingWidget.data.zoneName, addFloatingWidget.data.zoneId); + } + const existingObjects = zone ? zone.objects : []; + const newWidget = addFloatingWidget.data.widget; + // βœ… Check if the widget ID already exists before adding + const isAlreadyAdded = existingObjects.some(obj => obj.id === newWidget.id); + if (isAlreadyAdded) { + + return; // Don't add the widget if it already exists + } + // Add widget only if it doesn't exist + state.addObject(addFloatingWidget.data.zoneName, newWidget); + } + if (addFloatingWidget.message === "Widget updated successfully") { + updateObjectPosition(addFloatingWidget.data.zoneName, addFloatingWidget.data.index, addFloatingWidget.data.position); + } + } + }); + //duplicate Floating Widget response + visualizationSocket.on("viz-float:response:addDuplicate", (duplicateFloatingWidget: any) => { + console.log('duplicateFloatingWidget: ', duplicateFloatingWidget); + + if (duplicateFloatingWidget.success && duplicateFloatingWidget.message === "duplicate FloatWidget created successfully") { + useDroppedObjectsStore.setState((state) => { + const zone = state.zones[duplicateFloatingWidget.data.zoneName]; + if (!zone) return state; // Zone doesn't exist, return state as is + const existingObjects = zone.objects; + const newWidget = duplicateFloatingWidget.data.widget; + // βœ… Check if the object with the same ID already exists + const isAlreadyAdded = existingObjects.some(obj => obj.id === newWidget.id); + if (isAlreadyAdded) { + + return state; // Don't update state if it's already there + } + return { + zones: { + ...state.zones, + [duplicateFloatingWidget.data.zoneName]: { + ...zone, + objects: [...existingObjects, newWidget], // Append only if it's not a duplicate + }, + }, + }; + }); + } + }); + //delete Floating Widget response + visualizationSocket.on("viz-float:response:delete", (deleteFloatingWidget: any) => { + console.log('deleteFloatingWidget: ', deleteFloatingWidget); + + if (deleteFloatingWidget.success) { + deleteObject(deleteFloatingWidget.data.zoneName, deleteFloatingWidget.data.floatWidgetID); + } + }); + //add 3D Widget response + visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => { + console.log('add3DWidget: ', add3DWidget); + + if (add3DWidget.success) { + if (add3DWidget.message === "Widget created successfully") { + addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget); + } + } + }); + // add Template response + visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => { + console.log('addingTemplate: ', addingTemplate); + + if (addingTemplate.success) { + if (addingTemplate.message === "Template saved successfully") { + setTemplates(addingTemplate.data); + } + } + }); + //load Template response + visualizationSocket.on("viz-template:response:addTemplateZone", (loadTemplate: any) => { + console.log('loadTemplate: ', loadTemplate); + + if (loadTemplate.success) { + if (loadTemplate.message === "Template placed in Zone") { + let template = loadTemplate.data.template + setSelectedZone({ + panelOrder: template.panelOrder, + activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides` + widgets: template.widgets, + }); + useDroppedObjectsStore.getState().setZone(template.zoneName, template.zoneId); + + if (Array.isArray(template.floatingWidget)) { + template.floatingWidget.forEach((val: any) => { + useDroppedObjectsStore.getState().addObject(template.zoneName, val); + }); + } + } + + } + }); + //delete Template response + visualizationSocket.on("viz-template:response:delete", (deleteTemplate: any) => { + console.log('deleteTemplate: ', deleteTemplate); + + if (deleteTemplate.success) { + if (deleteTemplate.message === 'Template deleted successfully') { + removeTemplate(deleteTemplate.data); + } + + + } + }); } - }, []) + }, [visualizationSocket]) - useEffect(() => { - - }, [selectedZone]) return ( <> ) diff --git a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts index e57e8cb..7607c95 100644 --- a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts +++ b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts @@ -3,21 +3,24 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const deleteWidgetApi = async ( widgetID: string, - organization: string + organization: string, + zoneId:string ) => { + console.log('zoneId: ', zoneId); + console.log('organization: ', organization); + console.log('widgetID: ', widgetID); try { const response = await fetch(`${url_Backend_dwinzo}/api/v2/delete/widget`, { method: "PATCH", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ organization, widgetID }), + body: JSON.stringify({ organization, widgetID,zoneId }), }); if (!response.ok) { throw new Error("Failed to delete widget in the zone"); } - const result = await response.json(); return result; } catch (error) { diff --git a/app/src/store/useDroppedObjectsStore.ts b/app/src/store/useDroppedObjectsStore.ts index 45f40e0..8f0067e 100644 --- a/app/src/store/useDroppedObjectsStore.ts +++ b/app/src/store/useDroppedObjectsStore.ts @@ -1,5 +1,6 @@ import { create } from "zustand"; import { addingFloatingWidgets } from "../services/realTimeVisulization/zoneData/addFloatingWidgets"; +import { useSocketStore } from "./store"; type DroppedObject = { className: string; @@ -36,7 +37,7 @@ type DroppedObjectsState = { bottom: number | "auto"; } ) => void; - deleteObject: (zoneName: string, id: string, index: number) => void; // Add this line + deleteObject: (zoneName: string, id: string) => void; // Add this line duplicateObject: (zoneName: string, index: number) => void; // Add this line }; @@ -77,10 +78,10 @@ export const useDroppedObjectsStore = create((set) => ({ }; }), - deleteObject: (zoneName: string, id: string, index: number) => + deleteObject: (zoneName: string, id: string) => set((state) => { const zone = state.zones[zoneName]; - console.log("zone: ", zone); + if (!zone) return state; return { zones: { @@ -94,6 +95,8 @@ export const useDroppedObjectsStore = create((set) => ({ duplicateObject: async (zoneName: string, index: number) => { const state = useDroppedObjectsStore.getState(); // Get the current state const zone = state.zones[zoneName]; + let socketState = useSocketStore.getState(); + let visualizationSocket = socketState.visualizationSocket; if (!zone) return; @@ -120,8 +123,28 @@ export const useDroppedObjectsStore = create((set) => ({ }, }; - console.log("zone: ", zone.zoneId); - console.log("duplicatedObject: ", duplicatedObject); + let duplicateFloatingWidget = { + organization: organization, + widget: duplicatedObject, + zoneId: zone.zoneId, + index: index, + }; + + if (visualizationSocket) { + visualizationSocket.emit( + "v2:viz-float:addDuplicate", + duplicateFloatingWidget + ); + } + useDroppedObjectsStore.setState((state) => ({ + zones: { + ...state.zones, + [zoneName]: { + ...state.zones[zoneName], + objects: [...state.zones[zoneName].objects, duplicatedObject], // Append duplicated object + }, + }, + })); // Make async API call outside of Zustand set function // let response = await addingFloatingWidgets( @@ -132,15 +155,7 @@ export const useDroppedObjectsStore = create((set) => ({ // if (response.message === "FloatWidget created successfully") { // Update the state inside `set` - useDroppedObjectsStore.setState((state) => ({ - zones: { - ...state.zones, - [zoneName]: { - ...state.zones[zoneName], - objects: [...state.zones[zoneName].objects, duplicatedObject], // Append duplicated object - }, - }, - })); + // } }, })); diff --git a/app/src/store/useZone3DWidgetStore.ts b/app/src/store/useZone3DWidgetStore.ts new file mode 100644 index 0000000..fbb8e74 --- /dev/null +++ b/app/src/store/useZone3DWidgetStore.ts @@ -0,0 +1,33 @@ +import { create } from "zustand"; + +type WidgetData = { + id: string; + type: string; + position: [number, number, number]; +}; + +type ZoneWidgetStore = { + zoneWidgetData: Record; + setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) => void; + addWidget: (zoneId: string, widget: WidgetData) => void; +}; + +export const useZoneWidgetStore = create((set) => ({ + zoneWidgetData: {}, + + setZoneWidgetData: (zoneId, widgets) => + set((state) => ({ + zoneWidgetData: { + ...state.zoneWidgetData, + [zoneId]: widgets, + }, + })), + + addWidget: (zoneId, widget) => + set((state) => ({ + zoneWidgetData: { + ...state.zoneWidgetData, + [zoneId]: [...(state.zoneWidgetData[zoneId] || []), widget], + }, + })), +}));