From efc46eaa6dc9106fac96d710a78d98dbcce0303f Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Tue, 16 Sep 2025 12:21:52 +0530 Subject: [PATCH] seperated socket store --- .../components/Dashboard/DashboardCard.tsx | 3 +- .../components/Dashboard/DashboardMain.tsx | 33 +- app/src/components/Dashboard/SidePannel.tsx | 2 +- .../Dashboard/socket/projectSocketRes.tsx | 6 +- .../components/layout/scenes/MainScene.tsx | 11 +- .../properties/GlobalProperties.tsx | 2 +- .../properties/SelectedAisleProperties.tsx | 307 +++++------- .../properties/SelectedDecalProperties.tsx | 91 ++-- .../properties/SelectedFloorProperties.tsx | 107 ++-- .../properties/SelectedWallProperties.tsx | 95 +--- app/src/components/ui/Tools.tsx | 3 +- .../ui/collaboration/threads/Messages.tsx | 13 +- .../ui/collaboration/threads/ThreadChat.tsx | 11 +- .../Decal/decalCreator/decalCreator.tsx | 2 +- .../eventHandler/useDecalEventHandlers.ts | 173 +++---- .../aisle/aisleCreator/aisleCreator.tsx | 3 +- app/src/modules/builder/asset/assetsGroup.tsx | 3 +- .../eventHandlers/useModelEventHandlers.ts | 3 +- app/src/modules/builder/dfx/LoadBlueprint.tsx | 19 +- .../floor/floorCreator/floorCreator.tsx | 28 +- .../line/eventHandler/useLineEventHandler.ts | 3 +- .../eventHandler/usePointEventHandler.ts | 3 +- .../builder/wall/wallCreator/wallCreator.tsx | 5 +- .../eventHandler/useWallAssetEventHandler.ts | 3 +- .../builder/wallAsset/wallAssetCreator.tsx | 9 +- .../builder/zone/zoneCreator/zoneCreator.tsx | 23 +- .../collaboration/camera/collabCams.tsx | 17 +- .../collaboration/socket/builderResponses.tsx | 2 +- .../socket/threadSocketResponses.dev.tsx | 3 +- .../collaboration/socket/userResponses.tsx | 2 +- app/src/modules/scene/controls/controls.tsx | 3 +- .../selection2D/moveControls2D.tsx | 3 +- .../selection2D/selectionControls2D.tsx | 22 +- .../selection3D/copyPasteControls3D.tsx | 24 +- .../selection3D/duplicationControls3D.tsx | 22 +- .../selection3D/moveControls3D.tsx | 20 +- .../selection3D/rotateControls3D.tsx | 19 +- .../selection3D/selectionControls3D.tsx | 76 ++- .../selection3D/transformControls3D.tsx | 3 +- .../transformControls/transformControls.tsx | 23 +- .../handlers/use2DRedoHandler.ts | 195 ++++---- .../handlers/use2DUndoHandler.ts | 198 ++++---- .../handlers/use3DRedoHandler.ts | 2 +- .../handlers/use3DUndoHandler.ts | 2 +- .../undoRedo2D/undoRedo2DControls.tsx | 3 +- .../undoRedo3D/undoRedo3DControls.tsx | 3 +- app/src/modules/scene/scene.tsx | 3 +- .../socket/realTimeVizSocket.dev.tsx | 467 +++++++----------- .../visualization/template/Templates.tsx | 2 +- .../widgets/2d/DraggableWidget.tsx | 2 +- .../widgets/3d/Dropped3dWidget.tsx | 35 +- .../floating/DroppedFloatingWidgets.tsx | 30 +- .../widgets/panel/AddButtons.tsx | 23 +- .../visualization/widgets/panel/Panel.tsx | 2 +- app/src/pages/Dashboard.tsx | 2 +- app/src/pages/Project.tsx | 38 +- app/src/store/builder/store.ts | 117 ----- app/src/store/collaboration/useCollabStore.ts | 6 +- app/src/store/socket/useSocketStore.ts | 125 +++++ .../visualization/useDroppedObjectsStore.ts | 331 ++++++------- 60 files changed, 1402 insertions(+), 1384 deletions(-) create mode 100644 app/src/store/socket/useSocketStore.ts diff --git a/app/src/components/Dashboard/DashboardCard.tsx b/app/src/components/Dashboard/DashboardCard.tsx index 75fcdf8..d2aca40 100644 --- a/app/src/components/Dashboard/DashboardCard.tsx +++ b/app/src/components/Dashboard/DashboardCard.tsx @@ -3,10 +3,11 @@ import { createPortal } from "react-dom"; import { useNavigate } from "react-router-dom"; import img from "../../assets/image/image.png"; import { getUserData } from "../../functions/getUserData"; -import { useLoadingProgress, useProjectName, useSocketStore } from "../../store/builder/store"; +import { useLoadingProgress, useProjectName } from "../../store/builder/store"; import OuterClick from "../../utils/outerClick"; import { KebabIcon } from "../icons/ExportCommonIcons"; import { getAllProjectsApi } from "../../services/dashboard/getAllProjectsApi"; +import { useSocketStore } from "../../store/socket/useSocketStore"; // import { viewProject } from "../../services/dashboard/viewProject"; // import { updateProject } from "../../services/dashboard/updateProject"; diff --git a/app/src/components/Dashboard/DashboardMain.tsx b/app/src/components/Dashboard/DashboardMain.tsx index 56717e5..a80f866 100644 --- a/app/src/components/Dashboard/DashboardMain.tsx +++ b/app/src/components/Dashboard/DashboardMain.tsx @@ -1,9 +1,13 @@ import React, { useEffect, useState } from "react"; +import { getUserData } from "../../functions/getUserData"; +import { useSocketStore } from "../../store/socket/useSocketStore"; + +import { Modal } from "../templates/PreviewModal"; +import ProjectSocketRes from "./socket/projectSocketRes"; import DashboardNavBar from "./DashboardNavBar"; import DashboardCard from "./DashboardCard"; import MarketPlaceBanner from "./MarketPlaceBanner"; -import { getUserData } from "../../functions/getUserData"; -import { useSocketStore } from "../../store/builder/store"; + import { getAllProjectsApi } from "../../services/dashboard/getAllProjectsApi"; import { sharedWithMeProjectsApi } from "../../services/dashboard/sharedWithMeProjectApi"; import { recentlyViewedApi } from "../../services/dashboard/recentlyViewedApi"; @@ -12,8 +16,6 @@ import { searchProjectApi } from "../../services/dashboard/searchProjectsApi"; import { trashSearchProjectApi } from "../../services/dashboard/trashSearchProjectApi"; import { restoreTrashApi } from "../../services/dashboard/restoreTrashApi"; import { generateUniqueId } from "../../functions/generateUniqueId"; -import ProjectSocketRes from "./socket/projectSocketRes"; -import { Modal } from "../templates/PreviewModal"; interface DashboardMainProps { activeFolder: Folder; @@ -125,11 +127,7 @@ const DashboardMain: React.FC = ({ activeFolder }) => { updateStateAfterRemove(projectId); }; - const handleDuplicate = async ( - projectId: string, - projectName: string, - thumbnail: string - ): Promise => { + const handleDuplicate = async (projectId: string, projectName: string, thumbnail: string): Promise => { if (projectSocket) { projectSocket.emit("v1:project:Duplicate", { userId, @@ -220,16 +218,10 @@ const DashboardMain: React.FC = ({ activeFolder }) => {
{activeFolder === "projects" && (
- -
@@ -237,12 +229,7 @@ const DashboardMain: React.FC = ({ activeFolder }) => {
{renderProjects()}
- +
{/* 🔹 Delete Confirmation Modal */} diff --git a/app/src/components/Dashboard/SidePannel.tsx b/app/src/components/Dashboard/SidePannel.tsx index b9a7756..f83995f 100644 --- a/app/src/components/Dashboard/SidePannel.tsx +++ b/app/src/components/Dashboard/SidePannel.tsx @@ -5,7 +5,7 @@ import darkThemeImage from "../../assets/image/darkThemeProject.png"; import lightThemeImage from "../../assets/image/lightThemeProject.png"; import { SettingsIcon } from "../icons/ExportCommonIcons"; import { getUserData } from "../../functions/getUserData"; -import { useSocketStore } from "../../store/builder/store"; +import { useSocketStore } from "../../store/socket/useSocketStore"; // import { createProject } from "../../services/dashboard/createProject"; diff --git a/app/src/components/Dashboard/socket/projectSocketRes.tsx b/app/src/components/Dashboard/socket/projectSocketRes.tsx index e6f837f..a7e2f13 100644 --- a/app/src/components/Dashboard/socket/projectSocketRes.tsx +++ b/app/src/components/Dashboard/socket/projectSocketRes.tsx @@ -1,10 +1,10 @@ import React, { useEffect } from "react"; -import { useLoadingProgress, useSocketStore } from "../../../store/builder/store"; +import { useNavigate } from "react-router-dom"; +import { useSocketStore } from "../../../store/socket/useSocketStore"; +import { useLoadingProgress } from "../../../store/builder/store"; import { getUserData } from "../../../functions/getUserData"; import { getAllProjectsApi } from "../../../services/dashboard/getAllProjectsApi"; import { recentlyViewedApi } from "../../../services/dashboard/recentlyViewedApi"; -import { useNavigate } from "react-router-dom"; - interface DashboardProjectCollection { [key: string]: DashboardProject[]; diff --git a/app/src/components/layout/scenes/MainScene.tsx b/app/src/components/layout/scenes/MainScene.tsx index 411376b..b2d0c99 100644 --- a/app/src/components/layout/scenes/MainScene.tsx +++ b/app/src/components/layout/scenes/MainScene.tsx @@ -1,7 +1,8 @@ import { useEffect } from "react"; import { useParams } from "react-router-dom"; -import { useLoadingProgress, useRenameModeStore, useIsComparing, useSelectedComment, useSocketStore, useWidgetSubOption, useToggleView } from "../../../store/builder/store"; +import { useLoadingProgress, useRenameModeStore, useIsComparing, useSelectedComment, useWidgetSubOption, useToggleView } from "../../../store/builder/store"; import useModuleStore from "../../../store/ui/useModuleStore"; +import { useSocketStore } from "../../../store/socket/useSocketStore"; import { usePlayButtonStore } from "../../../store/ui/usePlayButtonStore"; import { useSelectedZoneStore } from "../../../store/visualization/useZoneStore"; import { useFloatingWidget } from "../../../store/visualization/useDroppedObjectsStore"; @@ -42,7 +43,7 @@ function MainScene() { const { toggleView } = useToggleView(); const { isPlaying } = usePlayButtonStore(); const { widgetSubOption } = useWidgetSubOption(); - const { visualizationSocket } = useSocketStore(); + const { builderSocket, visualizationSocket } = useSocketStore(); const { selectedZone } = useSelectedZoneStore(); const { setFloatingWidget } = useFloatingWidget(); const { selectedFloorAsset, setSelectedFloorAsset } = useBuilderStore(); @@ -62,6 +63,12 @@ function MainScene() { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + useEffect(() => { + if (builderSocket && projectId) { + builderSocket.emit("joinRoom", { projectId: projectId }); + } + }, [builderSocket, projectId]); + useEffect(() => { if (activeModule !== "simulation") { clearComparisonState(); diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index b3204e6..5d45514 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -11,11 +11,11 @@ import { useResetCamera, useRoofVisibility, useShadows, - useSocketStore, useTileDistance, useToggleView, useWallVisibility, } from "../../../../store/builder/store"; +import { useSocketStore } from "../../../../store/socket/useSocketStore"; import { useSceneStore } from "../../../../store/scene/useSceneStore"; import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment"; import * as CONSTANTS from "../../../../types/world/worldConstants"; diff --git a/app/src/components/layout/sidebarRight/properties/SelectedAisleProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedAisleProperties.tsx index a61dcb9..8f2a940 100644 --- a/app/src/components/layout/sidebarRight/properties/SelectedAisleProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/SelectedAisleProperties.tsx @@ -15,7 +15,7 @@ import Solid from "../../../../assets/image/aisleTypes/Solid.png"; import InputToggle from "../../../ui/inputs/InputToggle"; import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; import { useSceneContext } from "../../../../modules/scene/sceneContext"; -import { useSocketStore } from "../../../../store/builder/store"; +import { useSocketStore } from "../../../../store/socket/useSocketStore"; import { getUserData } from "../../../../functions/getUserData"; import { aisleTextureList } from "./AisleProperties"; @@ -43,31 +43,27 @@ const SelectedAisleProperties: React.FC = () => { const updateBackend = (updatedAisle: Aisle) => { if (updatedAisle && projectId) { - if (!builderSocket?.connected) { - // API - upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || ''); - + upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || ""); } else { - // SOCKET const data = { projectId: projectId, - versionId: selectedVersion?.versionId || '', + versionId: selectedVersion?.versionId || "", userId: userId, organization: organization, aisleUuid: updatedAisle.aisleUuid, points: updatedAisle.points, - type: updatedAisle.type - } + type: updatedAisle.type, + }; - builderSocket.emit('v1:model-aisle:add', data); + builderSocket.emit("v1:model-aisle:add", data); } } - } + }; const aisleTypes: { name: string; @@ -75,86 +71,86 @@ const SelectedAisleProperties: React.FC = () => { id: string; thumbnail: string; }[] = [ - { name: "Solid", type: "solid-aisle", id: "1", thumbnail: Solid }, - { name: "Dotted", type: "dotted-aisle", id: "2", thumbnail: Dotted }, - { name: "Dashed", type: "dashed-aisle", id: "3", thumbnail: Dashed }, - { name: "Arrow", type: "arrow-aisle", id: "4", thumbnail: Arrow }, - { name: "Continuous Arrows", type: "arrows-aisle", id: "5", thumbnail: Arrows }, - { name: "Directional", type: "junction-aisle", id: "6", thumbnail: Directional }, - { name: "Arc", type: "arc-aisle", id: "7", thumbnail: Arc }, - { name: "Circle", type: "circle-aisle", id: "8", thumbnail: Circle }, - ]; + { name: "Solid", type: "solid-aisle", id: "1", thumbnail: Solid }, + { name: "Dotted", type: "dotted-aisle", id: "2", thumbnail: Dotted }, + { name: "Dashed", type: "dashed-aisle", id: "3", thumbnail: Dashed }, + { name: "Arrow", type: "arrow-aisle", id: "4", thumbnail: Arrow }, + { name: "Continuous Arrows", type: "arrows-aisle", id: "5", thumbnail: Arrows }, + { name: "Directional", type: "junction-aisle", id: "6", thumbnail: Directional }, + { name: "Arc", type: "arc-aisle", id: "7", thumbnail: Arc }, + { name: "Circle", type: "circle-aisle", id: "8", thumbnail: Circle }, + ]; const createAisleTypeObject = (newType: AisleTypes, currentType: AisleType): AisleType => { switch (newType) { - case 'solid-aisle': + case "solid-aisle": return { - aisleType: 'solid-aisle', + aisleType: "solid-aisle", aisleColor: currentType.aisleColor, - aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1 + aisleWidth: "aisleWidth" in currentType ? currentType.aisleWidth : 0.1, } as SolidAisle; - case 'dashed-aisle': + case "dashed-aisle": return { - aisleType: 'dashed-aisle', + aisleType: "dashed-aisle", aisleColor: currentType.aisleColor, - aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1, - dashLength: 'dashLength' in currentType ? (currentType as DashedAisle).dashLength : 0.5, - gapLength: 'gapLength' in currentType ? (currentType as DashedAisle).gapLength : 0.3 + aisleWidth: "aisleWidth" in currentType ? currentType.aisleWidth : 0.1, + dashLength: "dashLength" in currentType ? (currentType as DashedAisle).dashLength : 0.5, + gapLength: "gapLength" in currentType ? (currentType as DashedAisle).gapLength : 0.3, } as DashedAisle; - case 'dotted-aisle': + case "dotted-aisle": return { - aisleType: 'dotted-aisle', + aisleType: "dotted-aisle", aisleColor: currentType.aisleColor, - dotRadius: 'dotRadius' in currentType ? (currentType as DottedAisle).dotRadius : 0.1, - gapLength: 'gapLength' in currentType ? (currentType as DottedAisle).gapLength : 0.3 + dotRadius: "dotRadius" in currentType ? (currentType as DottedAisle).dotRadius : 0.1, + gapLength: "gapLength" in currentType ? (currentType as DottedAisle).gapLength : 0.3, } as DottedAisle; - case 'arrow-aisle': + case "arrow-aisle": return { - aisleType: 'arrow-aisle', + aisleType: "arrow-aisle", aisleColor: currentType.aisleColor, - aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1 + aisleWidth: "aisleWidth" in currentType ? currentType.aisleWidth : 0.1, } as ArrowAisle; - case 'arrows-aisle': + case "arrows-aisle": return { - aisleType: 'arrows-aisle', + aisleType: "arrows-aisle", aisleColor: currentType.aisleColor, - aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1, - aisleLength: 'aisleLength' in currentType ? (currentType as ArrowsAisle).aisleLength : 0.6, - gapLength: 'gapLength' in currentType ? (currentType as ArrowsAisle).gapLength : 0.3 + aisleWidth: "aisleWidth" in currentType ? currentType.aisleWidth : 0.1, + aisleLength: "aisleLength" in currentType ? (currentType as ArrowsAisle).aisleLength : 0.6, + gapLength: "gapLength" in currentType ? (currentType as ArrowsAisle).gapLength : 0.3, } as ArrowsAisle; - case 'arc-aisle': + case "arc-aisle": return { - aisleType: 'arc-aisle', + aisleType: "arc-aisle", aisleColor: currentType.aisleColor, - aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1, - isFlipped: 'isFlipped' in currentType ? (currentType as ArcAisle).isFlipped : false + aisleWidth: "aisleWidth" in currentType ? currentType.aisleWidth : 0.1, + isFlipped: "isFlipped" in currentType ? (currentType as ArcAisle).isFlipped : false, } as ArcAisle; - case 'circle-aisle': + case "circle-aisle": return { - aisleType: 'circle-aisle', + aisleType: "circle-aisle", aisleColor: currentType.aisleColor, - aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1 + aisleWidth: "aisleWidth" in currentType ? currentType.aisleWidth : 0.1, } as CircleAisle; - case 'junction-aisle': + case "junction-aisle": return { - aisleType: 'junction-aisle', + aisleType: "junction-aisle", aisleColor: currentType.aisleColor, - aisleWidth: 'aisleWidth' in currentType ? currentType.aisleWidth : 0.1, - isFlipped: 'isFlipped' in currentType ? (currentType as JunctionAisle).isFlipped : false + aisleWidth: "aisleWidth" in currentType ? currentType.aisleWidth : 0.1, + isFlipped: "isFlipped" in currentType ? (currentType as JunctionAisle).isFlipped : false, } as JunctionAisle; default: return { - aisleType: 'solid-aisle', + aisleType: "solid-aisle", aisleColor: currentType.aisleColor, - aisleWidth: 0.1 + aisleWidth: 0.1, } as SolidAisle; } }; @@ -164,14 +160,14 @@ const SelectedAisleProperties: React.FC = () => { const newAisleType = createAisleTypeObject(newType, selectedAisleData.type); const updatedAisle = updateAisle(selectedAisleData.aisleUuid, { - type: newAisleType + type: newAisleType, }); setSelectedAisle({ aisleData: selectedAisle.aisleData, aisleMesh: null }); setSelectedAisleData({ ...selectedAisleData, - type: newAisleType + type: newAisleType, }); if (updatedAisle) { @@ -186,9 +182,9 @@ const SelectedAisleProperties: React.FC = () => { ...selectedAisleData, type: { ...selectedAisleData.type, - aisleColor: value - } - }) + aisleColor: value, + }, + }); if (updatedAisle) { updateBackend(updatedAisle); @@ -197,21 +193,21 @@ const SelectedAisleProperties: React.FC = () => { const handleAisleWidthChange = (value: string) => { const width = parseFloat(value); - if (!isNaN(width) && selectedAisleData.type.aisleType !== 'dotted-aisle') { + if (!isNaN(width) && selectedAisleData.type.aisleType !== "dotted-aisle") { const updatedAisle = updateAisle(selectedAisleData.aisleUuid, { type: { ...selectedAisleData.type, - aisleWidth: width - } + aisleWidth: width, + }, }); setSelectedAisleData({ ...selectedAisleData, type: { ...selectedAisleData.type, - aisleWidth: width - } - }) + aisleWidth: width, + }, + }); if (updatedAisle) { updateBackend(updatedAisle); @@ -221,18 +217,18 @@ const SelectedAisleProperties: React.FC = () => { const handleDashLengthChange = (value: string) => { const length = parseFloat(value); - if (!isNaN(length) && selectedAisleData.type.aisleType === 'dashed-aisle') { + if (!isNaN(length) && selectedAisleData.type.aisleType === "dashed-aisle") { const updatedAisle = setDashedAisleProperties(selectedAisleData.aisleUuid, { - dashLength: length + dashLength: length, }); setSelectedAisleData({ ...selectedAisleData, type: { ...(selectedAisleData.type as DashedAisle), - dashLength: length - } - }) + dashLength: length, + }, + }); if (updatedAisle) { updateBackend(updatedAisle); @@ -242,51 +238,51 @@ const SelectedAisleProperties: React.FC = () => { const handleGapLengthChange = (value: string) => { const length = parseFloat(value); - if (!isNaN(length) && (selectedAisleData.type.aisleType === 'dashed-aisle' || selectedAisleData.type.aisleType === 'dotted-aisle' || selectedAisleData.type.aisleType === 'arrows-aisle')) { - if (selectedAisleData.type.aisleType === 'dashed-aisle') { + if (!isNaN(length) && (selectedAisleData.type.aisleType === "dashed-aisle" || selectedAisleData.type.aisleType === "dotted-aisle" || selectedAisleData.type.aisleType === "arrows-aisle")) { + if (selectedAisleData.type.aisleType === "dashed-aisle") { const updatedAisle = setDashedAisleProperties(selectedAisleData.aisleUuid, { - gapLength: length + gapLength: length, }); setSelectedAisleData({ ...selectedAisleData, type: { ...(selectedAisleData.type as DashedAisle), - gapLength: length - } - }) + gapLength: length, + }, + }); if (updatedAisle) { updateBackend(updatedAisle); } - } else if (selectedAisleData.type.aisleType === 'dotted-aisle') { + } else if (selectedAisleData.type.aisleType === "dotted-aisle") { const updatedAisle = setDottedAisleProperties(selectedAisleData.aisleUuid, { - gapLength: length + gapLength: length, }); setSelectedAisleData({ ...selectedAisleData, type: { ...(selectedAisleData.type as DottedAisle), - gapLength: length - } - }) + gapLength: length, + }, + }); if (updatedAisle) { updateBackend(updatedAisle); } - } else if (selectedAisleData.type.aisleType === 'arrows-aisle') { + } else if (selectedAisleData.type.aisleType === "arrows-aisle") { const updatedAisle = setArrowsAisleProperties(selectedAisleData.aisleUuid, { - gapLength: length + gapLength: length, }); setSelectedAisleData({ ...selectedAisleData, type: { ...(selectedAisleData.type as ArrowsAisle), - gapLength: length - } - }) + gapLength: length, + }, + }); if (updatedAisle) { updateBackend(updatedAisle); @@ -297,18 +293,18 @@ const SelectedAisleProperties: React.FC = () => { const handleDotRadiusChange = (value: string) => { const radius = parseFloat(value); - if (!isNaN(radius) && selectedAisleData.type.aisleType === 'dotted-aisle') { + if (!isNaN(radius) && selectedAisleData.type.aisleType === "dotted-aisle") { const updatedAisle = setDottedAisleProperties(selectedAisleData.aisleUuid, { - dotRadius: radius + dotRadius: radius, }); setSelectedAisleData({ ...selectedAisleData, type: { ...(selectedAisleData.type as DottedAisle), - dotRadius: radius - } - }) + dotRadius: radius, + }, + }); if (updatedAisle) { updateBackend(updatedAisle); @@ -318,18 +314,18 @@ const SelectedAisleProperties: React.FC = () => { const handleAisleLengthChange = (value: string) => { const length = parseFloat(value); - if (!isNaN(length) && selectedAisleData.type.aisleType === 'arrows-aisle') { + if (!isNaN(length) && selectedAisleData.type.aisleType === "arrows-aisle") { const updatedAisle = setArrowsAisleProperties(selectedAisleData.aisleUuid, { - aisleLength: length + aisleLength: length, }); setSelectedAisleData({ ...selectedAisleData, type: { ...(selectedAisleData.type as ArrowsAisle), - aisleLength: length - } - }) + aisleLength: length, + }, + }); if (updatedAisle) { updateBackend(updatedAisle); @@ -338,20 +334,20 @@ const SelectedAisleProperties: React.FC = () => { }; const handleIsFlippedChange = () => { - if (selectedAisleData.type.aisleType === 'arc-aisle' || selectedAisleData.type.aisleType === 'junction-aisle') { + if (selectedAisleData.type.aisleType === "arc-aisle" || selectedAisleData.type.aisleType === "junction-aisle") { const currentType = selectedAisleData.type as ArcAisle | JunctionAisle; const currentFlipped = currentType.isFlipped || false; const updatedAisle = setArcAisleWidth(selectedAisleData.aisleUuid, { - isFlipped: !currentFlipped + isFlipped: !currentFlipped, }); setSelectedAisleData({ ...selectedAisleData, type: { ...currentType, - isFlipped: !currentFlipped - } - }) + isFlipped: !currentFlipped, + }, + }); if (updatedAisle) { updateBackend(updatedAisle); @@ -361,83 +357,34 @@ const SelectedAisleProperties: React.FC = () => { const renderAdvancedProperties = () => { switch (selectedAisleData.type.aisleType) { - case 'dashed-aisle': + case "dashed-aisle": const dashedType = selectedAisleData.type as DashedAisle; return ( <> - - + + ); - case 'dotted-aisle': + case "dotted-aisle": const dottedType = selectedAisleData.type as DottedAisle; return ( <> - - + + ); - case 'arrows-aisle': + case "arrows-aisle": const arrowsType = selectedAisleData.type as ArrowsAisle; return ( <> - - + + ); - case 'junction-aisle': - case 'arc-aisle': + case "junction-aisle": + case "arc-aisle": const flippedType = selectedAisleData.type as ArcAisle | JunctionAisle; - return ( - - ); + return ; default: return null; } @@ -449,26 +396,15 @@ const SelectedAisleProperties: React.FC = () => { {/* Basic Properties */}
- {selectedAisleData.type.aisleType !== 'dotted-aisle' && - - } + {selectedAisleData.type.aisleType !== "dotted-aisle" && ( + + )} {renderAdvancedProperties()}
{/* Presets */}
- @@ -493,11 +425,7 @@ const SelectedAisleProperties: React.FC = () => { {/* Texture */}
- - diff --git a/app/src/components/layout/sidebarRight/properties/SelectedFloorProperties.tsx b/app/src/components/layout/sidebarRight/properties/SelectedFloorProperties.tsx index 04bfa01..4a5e782 100644 --- a/app/src/components/layout/sidebarRight/properties/SelectedFloorProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/SelectedFloorProperties.tsx @@ -6,7 +6,7 @@ import { useBuilderStore } from "../../../../store/builder/useBuilderStore"; import { useSceneContext } from "../../../../modules/scene/sceneContext"; import { useParams } from "react-router-dom"; import { getUserData } from "../../../../functions/getUserData"; -import { useSocketStore } from "../../../../store/builder/store"; +import { useSocketStore } from "../../../../store/socket/useSocketStore"; import { materials } from "./FloorProperties"; import { upsertFloorApi } from "../../../../services/factoryBuilder/floor/upsertFloorApi"; @@ -42,23 +42,21 @@ const SelectedFloorProperties = () => { const updatedFloor = updateFloor(floor.floorUuid, { floorDepth: parsed }); if (projectId) { if (!builderSocket?.connected) { - // API - upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + upsertFloorApi(projectId, selectedVersion?.versionId || "", floor); } else { - // SOCKET const data = { floorData: updatedFloor, projectId: projectId, - versionId: selectedVersion?.versionId || '', + versionId: selectedVersion?.versionId || "", userId: userId, - organization: organization - } + organization: organization, + }; - builderSocket.emit('v1:model-Floor:add', data); + builderSocket.emit("v1:model-Floor:add", data); } } } @@ -71,23 +69,21 @@ const SelectedFloorProperties = () => { const updatedFloor = updateFloor(floor.floorUuid, { bevelStrength: parsed }); if (projectId) { if (!builderSocket?.connected) { - // API - upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + upsertFloorApi(projectId, selectedVersion?.versionId || "", floor); } else { - // SOCKET const data = { floorData: updatedFloor, projectId: projectId, - versionId: selectedVersion?.versionId || '', + versionId: selectedVersion?.versionId || "", userId: userId, - organization: organization - } + organization: organization, + }; - builderSocket.emit('v1:model-Floor:add', data); + builderSocket.emit("v1:model-Floor:add", data); } } } @@ -99,26 +95,23 @@ const SelectedFloorProperties = () => { const updatedFloor = updateFloor(floor.floorUuid, { isBeveled: !floor.isBeveled }); if (projectId) { if (!builderSocket?.connected) { - // API - upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + upsertFloorApi(projectId, selectedVersion?.versionId || "", floor); } else { - // SOCKET const data = { floorData: updatedFloor, projectId: projectId, - versionId: selectedVersion?.versionId || '', + versionId: selectedVersion?.versionId || "", userId: userId, - organization: organization - } + organization: organization, + }; - builderSocket.emit('v1:model-Floor:add', data); + builderSocket.emit("v1:model-Floor:add", data); } } - }; const handleSelectMaterial = (material: { textureId: string; textureName: string }) => { @@ -127,26 +120,23 @@ const SelectedFloorProperties = () => { const updatedFloor = updateFloor(floor.floorUuid, { [key]: material.textureId }); if (projectId) { if (!builderSocket?.connected) { - // API - upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + upsertFloorApi(projectId, selectedVersion?.versionId || "", floor); } else { - // SOCKET const data = { floorData: updatedFloor, projectId: projectId, - versionId: selectedVersion?.versionId || '', + versionId: selectedVersion?.versionId || "", userId: userId, - organization: organization - } + organization: organization, + }; - builderSocket.emit('v1:model-Floor:add', data); + builderSocket.emit("v1:model-Floor:add", data); } } - }; if (!floor) return null; @@ -161,28 +151,9 @@ const SelectedFloorProperties = () => {
Floor
- - - + + +
@@ -194,29 +165,17 @@ const SelectedFloorProperties = () => {
{(["top", "side"] as const).map((surface) => ( - ))}
- {selectedMaterials[activeSurface].textureName} + {selectedMaterials[activeSurface].textureName}
@@ -225,18 +184,10 @@ const SelectedFloorProperties = () => { {materials.map((material, index) => { const isSelected = selectedMaterials[activeSurface].textureId === material.textureId; return ( - ))}
- {selectedMaterials[activeSide].textureName} + {selectedMaterials[activeSide].textureName}
@@ -195,18 +162,10 @@ const SelectedWallProperties = () => { const isSelected = selectedMaterials[activeSide].textureId === material.textureId; return ( - @@ -254,7 +264,12 @@ const AddButtons: React.FC = ({ selectedZone, setSelectedZone, set {/* Lock/Unlock Panel */} - diff --git a/app/src/modules/visualization/widgets/panel/Panel.tsx b/app/src/modules/visualization/widgets/panel/Panel.tsx index 145dc9b..154dd42 100644 --- a/app/src/modules/visualization/widgets/panel/Panel.tsx +++ b/app/src/modules/visualization/widgets/panel/Panel.tsx @@ -4,12 +4,12 @@ import { Draggable } from "gsap/Draggable"; import { DraggableWidget } from "../2d/DraggableWidget"; import { useWidgetStore } from "../../../../store/ui/useWidgetStore"; import { generateUniqueId } from "../../../../functions/generateUniqueId"; -import { useSocketStore } from "../../../../store/builder/store"; import { useParams } from "react-router-dom"; import { arrayMove } from "@dnd-kit/sortable"; import { clamp } from "three/src/math/MathUtils"; import { getUserData } from "../../../../functions/getUserData"; import { useSceneContext } from "../../../scene/sceneContext"; +import { useSocketStore } from "../../../../store/socket/useSocketStore"; gsap.registerPlugin(Draggable); diff --git a/app/src/pages/Dashboard.tsx b/app/src/pages/Dashboard.tsx index 37665b2..f5c6a5f 100644 --- a/app/src/pages/Dashboard.tsx +++ b/app/src/pages/Dashboard.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import { useSocketStore } from "../store/builder/store"; +import { useSocketStore } from "../store/socket/useSocketStore"; import { getUserData } from "../functions/getUserData"; import SidePannel from "../components/Dashboard/SidePannel"; import DashboardTutorial from "../components/Dashboard/DashboardTutorial"; diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index b273372..0126105 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -1,18 +1,22 @@ import React, { useEffect } from "react"; -import useModuleStore from "../store/ui/useModuleStore"; -import { useSocketStore, useProjectName, useActiveTool } from "../store/builder/store"; import { useNavigate, useParams } from "react-router-dom"; +import useModuleStore from "../store/ui/useModuleStore"; +import { useSocketStore } from "../store/socket/useSocketStore"; import { useSelectedUserStore } from "../store/collaboration/useCollabStore"; -import FollowPerson from "../components/templates/FollowPerson"; +import { useProjectName, useActiveTool } from "../store/builder/store"; +import { handleCanvasCursors } from "../utils/mouseUtils/handleCanvasCursors"; + +import { getUserData } from "../functions/getUserData"; +import { viewProjectApi } from "../services/dashboard/viewProjectApi"; +import { getAllProjectsApi } from "../services/dashboard/getAllProjectsApi"; +import { sharedWithMeProjectsApi } from "../services/dashboard/sharedWithMeProjectApi"; + import { useLogger } from "../components/ui/log/LoggerContext"; +import { SceneProvider } from "../modules/scene/sceneContext"; + +import FollowPerson from "../components/templates/FollowPerson"; import RenderOverlay from "../components/templates/Overlay"; import LogList from "../components/ui/log/LogList"; -import { getAllProjectsApi } from "../services/dashboard/getAllProjectsApi"; -import { viewProjectApi } from "../services/dashboard/viewProjectApi"; -import { getUserData } from "../functions/getUserData"; -import { SceneProvider } from "../modules/scene/sceneContext"; -import { sharedWithMeProjectsApi } from "../services/dashboard/sharedWithMeProjectApi"; -import { handleCanvasCursors } from "../utils/mouseUtils/handleCanvasCursors"; import MainScene from "../components/layout/scenes/MainScene"; import ComparisonScene from "../components/layout/scenes/ComparisonScene"; @@ -20,6 +24,7 @@ const Project: React.FC = () => { let navigate = useNavigate(); const echo = useLogger(); const { setActiveModule } = useModuleStore(); + const { initializeBuilderSocket, initializeVisualizationSocket, initializeThreadSocket, disconnectBuilderSocket, disconnectVisualizationSocket, disconnectThreadSocket } = useSocketStore(); const { projectId } = useParams(); const { setProjectName } = useProjectName(); const { userId, email } = getUserData(); @@ -64,8 +69,10 @@ const Project: React.FC = () => { const token = localStorage.getItem("token"); const refreshToken = localStorage.getItem("refreshToken"); echo.warn("Validating token"); - if (token && refreshToken) { - useSocketStore.getState().initializeBuilderSocket(token, refreshToken); + if (token && refreshToken && projectId) { + initializeBuilderSocket(token, refreshToken, projectId); + initializeVisualizationSocket(token, refreshToken, projectId); + initializeThreadSocket(token, refreshToken, projectId); } echo.success("Project initialized and loaded successfully"); } else { @@ -73,7 +80,14 @@ const Project: React.FC = () => { } // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + return () => { + if (projectId) { + disconnectBuilderSocket(projectId); + disconnectVisualizationSocket(projectId); + disconnectThreadSocket(projectId); + } + }; + }, [projectId]); useEffect(() => { handleCanvasCursors(activeTool); diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index 3bd6435..7030d51 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -1,123 +1,6 @@ import { create } from "zustand"; -import { io, Socket } from "socket.io-client"; import * as CONSTANTS from "../../types/world/worldConstants"; -interface SocketStore { - builderSocket: Socket | null; - visualizationSocket: Socket | null; - dashBoardSocket: Socket | null; - projectSocket: Socket | null; - threadSocket: Socket | null; - - initializeBuilderSocket: (token?: string, refreshToken?: string) => void; - initializeVisualizationSocket: (token?: string, refreshToken?: string) => void; - initializeDashBoardSocket: (token?: string, refreshToken?: string) => void; - initializeProjectSocket: (token?: string, refreshToken?: string) => void; - initializeThreadSocket: (token?: string, refreshToken?: string) => void; - - disconnectBuilderSocket: () => void; - disconnectVisualizationSocket: () => void; - disconnectDashBoardSocket: () => void; - disconnectProjectSocket: () => void; - disconnectThreadSocket: () => void; - - disconnectAll: () => void; -} - -export const useSocketStore = create((set, get) => ({ - builderSocket: null, - visualizationSocket: null, - dashBoardSocket: null, - projectSocket: null, - threadSocket: null, - - initializeBuilderSocket: (token, refreshToken) => { - if (get().builderSocket) return; - const builderSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`, { - reconnection: true, - auth: { token, refreshToken }, - }); - set({ builderSocket }); - }, - - initializeVisualizationSocket: (token, refreshToken) => { - if (get().visualizationSocket) return; - const visualizationSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`, { - reconnection: true, - auth: { token, refreshToken }, - }); - set({ visualizationSocket }); - }, - - initializeDashBoardSocket: (token, refreshToken) => { - if (get().dashBoardSocket) return; - const dashBoardSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`, { - reconnection: true, - auth: { token, refreshToken }, - }); - set({ dashBoardSocket }); - }, - - initializeProjectSocket: (token, refreshToken) => { - if (get().projectSocket) return; - const projectSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`, { - reconnection: true, - auth: { token, refreshToken }, - }); - set({ projectSocket }); - }, - - initializeThreadSocket: (token, refreshToken) => { - if (get().threadSocket) return; - const threadSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`, { - reconnection: true, - auth: { token, refreshToken }, - }); - set({ threadSocket }); - }, - - disconnectBuilderSocket: () => { - get().builderSocket?.disconnect(); - set({ builderSocket: null }); - }, - - disconnectVisualizationSocket: () => { - get().visualizationSocket?.disconnect(); - set({ visualizationSocket: null }); - }, - - disconnectDashBoardSocket: () => { - get().dashBoardSocket?.disconnect(); - set({ dashBoardSocket: null }); - }, - - disconnectProjectSocket: () => { - get().projectSocket?.disconnect(); - set({ projectSocket: null }); - }, - - disconnectThreadSocket: () => { - get().threadSocket?.disconnect(); - set({ threadSocket: null }); - }, - - disconnectAll: () => { - get().builderSocket?.disconnect(); - get().visualizationSocket?.disconnect(); - get().dashBoardSocket?.disconnect(); - get().projectSocket?.disconnect(); - get().threadSocket?.disconnect(); - - set({ - builderSocket: null, - visualizationSocket: null, - dashBoardSocket: null, - projectSocket: null, - threadSocket: null, - }); - }, -})); - export const useLoadingProgress = create<{ loadingProgress: number; setLoadingProgress: (x: number) => void; diff --git a/app/src/store/collaboration/useCollabStore.ts b/app/src/store/collaboration/useCollabStore.ts index b768126..2f7721d 100644 --- a/app/src/store/collaboration/useCollabStore.ts +++ b/app/src/store/collaboration/useCollabStore.ts @@ -1,9 +1,9 @@ -import { create } from 'zustand'; +import { create } from "zustand"; interface SelectedUser { color: string; name: string; - id: string, + id: string; location?: { position: { x: number; @@ -20,7 +20,7 @@ interface SelectedUser { y: number; z: number; }; - } + }; } interface SelectedUserStore { diff --git a/app/src/store/socket/useSocketStore.ts b/app/src/store/socket/useSocketStore.ts new file mode 100644 index 0000000..53dd34b --- /dev/null +++ b/app/src/store/socket/useSocketStore.ts @@ -0,0 +1,125 @@ +import { create } from "zustand"; +import { io, Socket } from "socket.io-client"; + +interface SocketStore { + builderSocket: Socket | null; + visualizationSocket: Socket | null; + dashBoardSocket: Socket | null; + projectSocket: Socket | null; + threadSocket: Socket | null; + + initializeBuilderSocket: (token: string, refreshToken: string, projectId: string) => void; + initializeVisualizationSocket: (token: string, refreshToken: string, projectId: string) => void; + initializeThreadSocket: (token: string, refreshToken: string, projectId: string) => void; + initializeDashBoardSocket: (token: string, refreshToken: string) => void; + initializeProjectSocket: (token: string, refreshToken: string) => void; + + disconnectBuilderSocket: (projectId: string) => void; + disconnectVisualizationSocket: (projectId: string) => void; + disconnectThreadSocket: (projectId: string) => void; + disconnectDashBoardSocket: () => void; + disconnectProjectSocket: () => void; + + disconnectAll: (projectId?: string) => void; +} + +export const useSocketStore = create((set, get) => ({ + builderSocket: null, + visualizationSocket: null, + dashBoardSocket: null, + projectSocket: null, + threadSocket: null, + + initializeBuilderSocket: (token, refreshToken, projectId) => { + if (get().builderSocket) return; + const builderSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`, { + reconnection: true, + auth: { token, refreshToken, projectId }, + }); + set({ builderSocket }); + }, + + initializeVisualizationSocket: (token, refreshToken, projectId) => { + if (get().visualizationSocket) return; + const visualizationSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`, { + reconnection: true, + auth: { token, refreshToken, projectId }, + }); + set({ visualizationSocket }); + }, + + initializeThreadSocket: (token, refreshToken, projectId) => { + if (get().threadSocket) return; + const threadSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`, { + reconnection: true, + auth: { token, refreshToken, projectId }, + }); + set({ threadSocket }); + }, + + initializeDashBoardSocket: (token, refreshToken) => { + if (get().dashBoardSocket) return; + const dashBoardSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`, { + reconnection: true, + auth: { token, refreshToken }, + }); + set({ dashBoardSocket }); + }, + + initializeProjectSocket: (token, refreshToken) => { + if (get().projectSocket) return; + const projectSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`, { + reconnection: true, + auth: { token, refreshToken }, + }); + set({ projectSocket }); + }, + + disconnectBuilderSocket: (projectId) => { + get().builderSocket?.emit("leaveRoom", { projectId }); + get().builderSocket?.disconnect(); + set({ builderSocket: null }); + }, + + disconnectVisualizationSocket: (projectId) => { + get().visualizationSocket?.emit("leaveRoom", { projectId }); + get().visualizationSocket?.disconnect(); + set({ visualizationSocket: null }); + }, + + disconnectThreadSocket: (projectId) => { + get().threadSocket?.emit("leaveRoom", { projectId }); + get().threadSocket?.disconnect(); + set({ threadSocket: null }); + }, + + disconnectDashBoardSocket: () => { + get().dashBoardSocket?.disconnect(); + set({ dashBoardSocket: null }); + }, + + disconnectProjectSocket: () => { + get().projectSocket?.disconnect(); + set({ projectSocket: null }); + }, + + disconnectAll: (projectId) => { + get().builderSocket?.emit("leaveRoom", { projectId }); + get().visualizationSocket?.emit("leaveRoom", { projectId }); + get().threadSocket?.emit("leaveRoom", { projectId }); + + get().builderSocket?.disconnect(); + get().visualizationSocket?.disconnect(); + get().dashBoardSocket?.disconnect(); + get().projectSocket?.disconnect(); + get().threadSocket?.disconnect(); + + set({ + builderSocket: null, + visualizationSocket: null, + dashBoardSocket: null, + projectSocket: null, + threadSocket: null, + }); + }, +})); diff --git a/app/src/store/visualization/useDroppedObjectsStore.ts b/app/src/store/visualization/useDroppedObjectsStore.ts index 111032d..cf3ec54 100644 --- a/app/src/store/visualization/useDroppedObjectsStore.ts +++ b/app/src/store/visualization/useDroppedObjectsStore.ts @@ -1,214 +1,199 @@ import { create } from "zustand"; -import { useSocketStore } from "../builder/store"; +import { useSocketStore } from "../socket/useSocketStore"; import useChartStore from "./useChartStore"; import { getUserData } from "../../functions/getUserData"; type DroppedObject = { - className: string; - id: string; - position: { - top: number | "auto"; - left: number | "auto"; - right: number | "auto"; - bottom: number | "auto"; - }; - value?: number; - per?: string; - header?: string; - Data: {}; + className: string; + id: string; + position: { + top: number | "auto"; + left: number | "auto"; + right: number | "auto"; + bottom: number | "auto"; + }; + value?: number; + per?: string; + header?: string; + Data: {}; }; type Zone = { - zoneName: string; - zoneUuid: string; - objects: DroppedObject[]; + zoneName: string; + zoneUuid: string; + objects: DroppedObject[]; }; type DroppedObjectsState = { - zones: Record; - setZone: (zoneName: string, zoneUuid: string) => void; - addObject: (zoneName: string, newObject: DroppedObject) => void; - updateObjectPosition: ( - zoneName: string, - index: number, - newPosition: { - top: number | "auto"; - left: number | "auto"; - right: number | "auto"; - bottom: number | "auto"; - } - ) => void; - deleteObject: (zoneName: string, id: string) => void; // Add this line - duplicateObject: ( - zoneName: string, - index: number, - projectId?: string, - versionId?: string - ) => void; // Add this line + zones: Record; + setZone: (zoneName: string, zoneUuid: string) => void; + addObject: (zoneName: string, newObject: DroppedObject) => void; + updateObjectPosition: ( + zoneName: string, + index: number, + newPosition: { + top: number | "auto"; + left: number | "auto"; + right: number | "auto"; + bottom: number | "auto"; + } + ) => void; + deleteObject: (zoneName: string, id: string) => void; // Add this line + duplicateObject: (zoneName: string, index: number, projectId?: string, versionId?: string) => void; // Add this line }; export const useDroppedObjectsStore = create((set) => ({ - zones: {}, + zones: {}, - setZone: (zoneName: string, zoneUuid: string) => - set((state) => ({ - zones: { - [zoneName]: state.zones[zoneName] || { - zoneName, - zoneUuid, - objects: [], - }, // Keep existing zone if it exists - }, - })), + setZone: (zoneName: string, zoneUuid: string) => + set((state) => ({ + zones: { + [zoneName]: state.zones[zoneName] || { + zoneName, + zoneUuid, + objects: [], + }, // Keep existing zone if it exists + }, + })), - addObject: (zoneName: string, newObject: DroppedObject) => - set((state) => ({ - zones: { - ...state.zones, - [zoneName]: { - ...state.zones[zoneName], - objects: [...state.zones[zoneName].objects, newObject], // Append new object - }, - }, - })), + addObject: (zoneName: string, newObject: DroppedObject) => + set((state) => ({ + zones: { + ...state.zones, + [zoneName]: { + ...state.zones[zoneName], + objects: [...state.zones[zoneName].objects, newObject], // Append new object + }, + }, + })), - updateObjectPosition: (zoneName, index, newPosition) => - set((state) => { - const zone = state.zones[zoneName]; - if (!zone) return state; - return { - zones: { - [zoneName]: { - ...zone, - objects: zone.objects.map((obj, i) => - i === index ? { ...obj, position: newPosition } : obj - ), - }, - }, - }; - }), + updateObjectPosition: (zoneName, index, newPosition) => + set((state) => { + const zone = state.zones[zoneName]; + if (!zone) return state; + return { + zones: { + [zoneName]: { + ...zone, + objects: zone.objects.map((obj, i) => (i === index ? { ...obj, position: newPosition } : obj)), + }, + }, + }; + }), - deleteObject: (zoneName: string, id: string) => - set((state) => { - const zone = state.zones[zoneName]; + deleteObject: (zoneName: string, id: string) => + set((state) => { + const zone = state.zones[zoneName]; - if (!zone) return state; - return { - zones: { - [zoneName]: { - ...zone, - objects: zone.objects.filter((obj) => obj.id !== id), // Remove object at the given index - }, - }, - }; - }), + if (!zone) return state; + return { + zones: { + [zoneName]: { + ...zone, + objects: zone.objects.filter((obj) => obj.id !== id), // Remove object at the given index + }, + }, + }; + }), - duplicateObject: async ( - zoneName: string, - index: number, - projectId?: string, - versionId?: string - ) => { - const state = useDroppedObjectsStore.getState(); // Get the current state - const zone = state.zones[zoneName]; - let socketState = useSocketStore.getState(); - let iotData = useChartStore.getState(); - let visualizationSocket = socketState.visualizationSocket; - let iotMeasurements = iotData.flotingMeasurements; - let iotDuration = iotData.flotingDuration; - let iotHeader = iotData.header; + duplicateObject: async (zoneName: string, index: number, projectId?: string, versionId?: string) => { + const state = useDroppedObjectsStore.getState(); // Get the current state + const zone = state.zones[zoneName]; + let socketState = useSocketStore.getState(); + let iotData = useChartStore.getState(); + let visualizationSocket = socketState.visualizationSocket; + let iotMeasurements = iotData.flotingMeasurements; + let iotDuration = iotData.flotingDuration; + let iotHeader = iotData.header; - if (!zone) return; + if (!zone) return; - const originalObject = zone.objects[index]; - if (!originalObject) return; - const { userId, organization, email } = getUserData(); + const originalObject = zone.objects[index]; + if (!originalObject) return; + const { userId, organization, email } = getUserData(); - // Create a shallow copy of the object with a unique ID and slightly adjusted position - const duplicatedObject: DroppedObject = { - ...originalObject, - Data: { - measurements: iotMeasurements, - duration: iotDuration, - }, - header: iotHeader, - id: `${originalObject.id}-copy-${Date.now()}`, // Unique ID - position: { - ...originalObject.position, - top: - typeof originalObject.position.top === "number" - ? originalObject.position.top + 20 // Offset vertically - : originalObject.position.top, - left: - typeof originalObject.position.left === "number" - ? originalObject.position.left + 20 // Offset horizontally - : originalObject.position.left, - }, - }; - // console.log("duplicated object", duplicatedObject); + // Create a shallow copy of the object with a unique ID and slightly adjusted position + const duplicatedObject: DroppedObject = { + ...originalObject, + Data: { + measurements: iotMeasurements, + duration: iotDuration, + }, + header: iotHeader, + id: `${originalObject.id}-copy-${Date.now()}`, // Unique ID + position: { + ...originalObject.position, + top: + typeof originalObject.position.top === "number" + ? originalObject.position.top + 20 // Offset vertically + : originalObject.position.top, + left: + typeof originalObject.position.left === "number" + ? originalObject.position.left + 20 // Offset horizontally + : originalObject.position.left, + }, + }; + // console.log("duplicated object", duplicatedObject); - let duplicateFloatingWidget = { - organization, - widget: duplicatedObject, - zoneUuid: zone.zoneUuid, - index: index, - versionId, - projectId, - userId, - }; + let duplicateFloatingWidget = { + organization, + widget: duplicatedObject, + zoneUuid: zone.zoneUuid, + index: index, + versionId, + projectId, + userId, + }; - if (visualizationSocket) { - visualizationSocket.emit( - "v1:viz-float:addDuplicate", - duplicateFloatingWidget - ); - } - useDroppedObjectsStore.setState((state) => ({ - zones: { - ...state.zones, - [zoneName]: { - ...state.zones[zoneName], - objects: [...state.zones[zoneName].objects, duplicatedObject], // Append duplicated object - }, - }, - })); + if (visualizationSocket) { + visualizationSocket.emit("v1: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( - // zone.zoneUuid, - // organization, - // duplicatedObject - // ); + // Make async API call outside of Zustand set function + // let response = await addingFloatingWidgets( + // zone.zoneUuid, + // organization, + // duplicatedObject + // ); - // if (response.message === "FloatWidget created successfully") { - // Update the state inside `set` + // if (response.message === "FloatWidget created successfully") { + // Update the state inside `set` - // } - }, + // } + }, })); export interface DroppedObjects { - header: string; - id: string; - Data: {}; - value: string | number; // ✅ Allows both numbers and formatted strings - per: string; - className: string; - position: { top: number; left: number; right: number; bottom: number }; // ✅ Ensures position is a tuple + header: string; + id: string; + Data: {}; + value: string | number; // ✅ Allows both numbers and formatted strings + per: string; + className: string; + position: { top: number; left: number; right: number; bottom: number }; // ✅ Ensures position is a tuple } export interface Zones { - zoneName: string; - zoneUuid: string; - objects: DroppedObject[]; + zoneName: string; + zoneUuid: string; + objects: DroppedObject[]; } export const use3DWidget = create((set: any) => ({ - widgets3D: [], - setWidgets3D: (x: any) => set({ widgets3D: x }), + widgets3D: [], + setWidgets3D: (x: any) => set({ widgets3D: x }), })); export const useFloatingWidget = create((set: any) => ({ - floatingWidget: [], - setFloatingWidget: (x: any) => set({ floatingWidget: x }), + floatingWidget: [], + setFloatingWidget: (x: any) => set({ floatingWidget: x }), }));