diff --git a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx index 62a5d0f..97ee22b 100644 --- a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx +++ b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx @@ -260,10 +260,10 @@ function FloorCreator() { }, ], }); - - setTempPoints([]); - setIsCreating(false); } + + setTempPoints([]); + setIsCreating(false); } }; diff --git a/app/src/modules/builder/line/eventHandler/useLineEventHandler.ts b/app/src/modules/builder/line/eventHandler/useLineEventHandler.ts index 6ba4db1..9ecdeaa 100644 --- a/app/src/modules/builder/line/eventHandler/useLineEventHandler.ts +++ b/app/src/modules/builder/line/eventHandler/useLineEventHandler.ts @@ -10,6 +10,7 @@ import { useSelectedPoints } from "../../../../store/simulation/useSimulationSto import useWallAssetResponseHandler from "../../../collaboration/responseHandler/useWallAssetResponseHandler"; import useWallResponseHandler from "../../../collaboration/responseHandler/useWallResponseHandler"; import useFloorResponseHandler from "../../../collaboration/responseHandler/useFloorResponseHandler"; +import useZoneResponseHandler from "../../../collaboration/responseHandler/useZoneResponseHandler"; import { upsertWallApi } from "../../../../services/factoryBuilder/wall/upsertWallApi"; import { deleteWallApi } from "../../../../services/factoryBuilder/wall/deleteWallApi"; @@ -40,10 +41,11 @@ export function useLineEventHandler({ points }: Readonly) { const { getWallAssetsByWall } = wallAssetStore(); const { peekRemoveWallByPoints, setPosition: setWallPosition, getWallByPoints, getConnectedWallsByWallId } = wallStore(); const { peekRemoveFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId, getFloorsByPoints } = floorStore(); - const { removeZoneByPoints, setPosition: setZonePosition, getZonesByPointId, getZonesByPoints } = zoneStore(); + const { peekRemoveZoneByPoints, setPosition: setZonePosition, getZonesByPointId, getZonesByPoints } = zoneStore(); const { updateWallAssetInScene, removeWallAssetFromScene } = useWallAssetResponseHandler(); const { updateWallInScene, removeWallFromScene } = useWallResponseHandler(); const { updateFloorInScene, removeFloorFromScene } = useFloorResponseHandler(); + const { updateZoneInScene, removeZoneFromScene } = useZoneResponseHandler(); const { selectedVersion } = versionStore(); const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore(); const [dragOffset, setDragOffset] = useState(null); @@ -311,7 +313,23 @@ export function useLineEventHandler({ points }: Readonly) { if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone); + upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + return; + } + if (data.message === "Zone Updated Successfully") { + updateZoneInScene(updatedZone, () => { + echo.info(`Updated zone: ${updatedZone.zoneName}`); + }); + } else { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + }); } else { // SOCKET @@ -564,19 +582,35 @@ export function useLineEventHandler({ points }: Readonly) { } if (points[0].pointType === "Zone" && points[1].pointType === "Zone") { const Zones = getZonesByPoints(points); - const { removedZones, updatedZones } = removeZoneByPoints(points); + const { removedZones, updatedZones } = peekRemoveZoneByPoints(points); if (removedZones.length > 0) { - removedZones.forEach((zone) => { + removedZones.forEach((removedZone) => { if (projectId) { if (!builderSocket?.connected) { // API - deleteZoneApi(projectId, selectedVersion?.versionId || "", zone.zoneUuid); + deleteZoneApi(projectId, selectedVersion?.versionId || "", removedZone.zoneUuid) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error removing zone`); + return; + } + if (data.message === "Zone Deleted Successfully") { + removeZoneFromScene(removedZone.zoneUuid, () => { + echo.info(`Removed zone: ${removedZone.zoneName}`); + }); + } else { + echo.error(`Error removing zone: ${removedZone.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error removing zone: ${removedZone.zoneName}`); + }); } else { // SOCKET const data = { - zoneUuid: zone.zoneUuid, + zoneUuid: removedZone.zoneUuid, projectId: projectId, versionId: selectedVersion?.versionId || "", userId: userId, @@ -605,17 +639,33 @@ export function useLineEventHandler({ points }: Readonly) { }); } if (updatedZones.length > 0) { - updatedZones.forEach((zone) => { + updatedZones.forEach((updatedZone) => { if (projectId) { if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", zone); + upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + return; + } + if (data.message === "Zone Updated Successfully") { + updateZoneInScene(updatedZone, () => { + echo.info(`Updated zone: ${updatedZone.zoneName}`); + }); + } else { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + }); } else { // SOCKET const data = { - zoneData: zone, + zoneData: updatedZone, projectId: projectId, versionId: selectedVersion?.versionId || "", userId: userId, diff --git a/app/src/modules/builder/point/eventHandler/usePointEventHandler.ts b/app/src/modules/builder/point/eventHandler/usePointEventHandler.ts index 9909a61..08b379a 100644 --- a/app/src/modules/builder/point/eventHandler/usePointEventHandler.ts +++ b/app/src/modules/builder/point/eventHandler/usePointEventHandler.ts @@ -12,6 +12,7 @@ import useWallAssetResponseHandler from "../../../collaboration/responseHandler/ import useWallResponseHandler from "../../../collaboration/responseHandler/useWallResponseHandler"; import useAisleResponseHandler from "../../../collaboration/responseHandler/useAisleResponseHandler"; import useFloorResponseHandler from "../../../collaboration/responseHandler/useFloorResponseHandler"; +import useZoneResponseHandler from "../../../collaboration/responseHandler/useZoneResponseHandler"; import { upsertAisleApi } from "../../../../services/factoryBuilder/aisle/upsertAisleApi"; import { deleteAisleApi } from "../../../../services/factoryBuilder/aisle/deleteAisleApi"; @@ -44,10 +45,11 @@ export function usePointEventHandler({ point }: { point: Point }) { const { updateWallInScene, removeWallFromScene } = useWallResponseHandler(); const { updateAisleInScene, removeAisleFromScene } = useAisleResponseHandler(); const { updateFloorInScene, removeFloorFromScene } = useFloorResponseHandler(); + const { updateZoneInScene, removeZoneFromScene } = useZoneResponseHandler(); const { setPosition: setAislePosition, peekRemovePoint: peekRemoveAislePoint, getAislesByPointId } = aisleStore(); const { setPosition: setWallPosition, peekRemovePoint: peekRemoveWallPoint, getWallsByPointId } = wallStore(); const { setPosition: setFloorPosition, peekRemovePoint: peekRemoveFloorPoint, getFloorsByPointId } = floorStore(); - const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore(); + const { setPosition: setZonePosition, peekRemovePoint: peekRemoveZonePoint, getZonesByPointId } = zoneStore(); const { selectedVersion } = versionStore(); const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({ uuid: point.pointUuid, @@ -362,7 +364,23 @@ export function usePointEventHandler({ point }: { point: Point }) { if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone); + upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + return; + } + if (data.message === "Zone Updated Successfully") { + updateZoneInScene(updatedZone, () => { + echo.info(`Updated zone: ${updatedZone.zoneName}`); + }); + } else { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + }); } else { // SOCKET @@ -683,20 +701,36 @@ export function usePointEventHandler({ point }: { point: Point }) { } if (point.pointType === "Zone") { const Zones = getZonesByPointId(point.pointUuid); - const { removedZones, updatedZones } = removeZonePoint(point.pointUuid); + const { removedZones, updatedZones } = peekRemoveZonePoint(point.pointUuid); setHoveredPoint(null); if (removedZones.length > 0) { - removedZones.forEach((zone) => { + removedZones.forEach((removedZone) => { if (projectId) { if (!builderSocket?.connected) { // API - deleteZoneApi(projectId, selectedVersion?.versionId || "", zone.zoneUuid); + deleteZoneApi(projectId, selectedVersion?.versionId || "", removedZone.zoneUuid) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error removing zone`); + return; + } + if (data.message === "Zone Deleted Successfully") { + removeZoneFromScene(removedZone.zoneUuid, () => { + echo.info(`Removed zone: ${removedZone.zoneName}`); + }); + } else { + echo.error(`Error removing zone: ${removedZone.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error removing zone: ${removedZone.zoneName}`); + }); } else { // SOCKET const data = { - zoneUuid: zone.zoneUuid, + zoneUuid: removedZone.zoneUuid, projectId: projectId, versionId: selectedVersion?.versionId || "", userId: userId, @@ -725,17 +759,33 @@ export function usePointEventHandler({ point }: { point: Point }) { }); } if (updatedZones.length > 0) { - updatedZones.forEach((zone) => { + updatedZones.forEach((updatedZone) => { if (projectId) { if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", zone); + upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + return; + } + if (data.message === "Zone Updated Successfully") { + updateZoneInScene(updatedZone, () => { + echo.info(`Updated zone: ${updatedZone.zoneName}`); + }); + } else { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + }); } else { // SOCKET const data = { - zoneData: zone, + zoneData: updatedZone, projectId: projectId, versionId: selectedVersion?.versionId || "", userId: userId, diff --git a/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx index 10a67b6..dda4ebf 100644 --- a/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx +++ b/app/src/modules/builder/zone/zoneCreator/zoneCreator.tsx @@ -9,6 +9,7 @@ import { useParams } from "react-router-dom"; import { getUserData } from "../../../../functions/getUserData"; import ReferencePoint from "../../point/reference/referencePoint"; import ReferenceZone from "./referenceZone"; +import useZoneResponseHandler from "../../../collaboration/responseHandler/useZoneResponseHandler"; import getCenteroidPoint from "../../functions/getCenteroid"; import generateUniqueZoneName from "../functions/generateUniqueZoneName"; @@ -23,7 +24,8 @@ function ZoneCreator() { const { activeLayer } = useActiveLayer(); const { builderSocket } = useSocketStore(); const { zoneStore, undoRedo2DStore, versionStore } = useSceneContext(); - const { addZone, getZonePointById, zones } = zoneStore(); + const { zones } = zoneStore(); + const { addZoneToScene, removeZoneFromScene } = useZoneResponseHandler(); const { push2D } = undoRedo2DStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); @@ -57,6 +59,55 @@ function ZoneCreator() { } }; + const addZoneToBackend = (zone: Zone) => { + if (projectId) { + if (!builderSocket?.connected) { + // API + + upsertZoneApi(projectId, selectedVersion?.versionId || "", zone) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error adding or updating zone`); + setTempPoints([]); + setIsCreating(false); + return; + } + if (data.message === "Zone Created Successfully") { + addZoneToScene(zone, () => { + echo.info(`Added zone: ${zone.zoneName}`); + }); + } else { + removeZoneFromScene(zone.zoneUuid, () => { + echo.error(`Error adding or updating zone: ${zone.zoneName}`); + setTempPoints([]); + setIsCreating(false); + }); + } + }) + .catch(() => { + echo.error(`Error adding or updating zone: ${zone.zoneName}`); + setTempPoints([]); + setIsCreating(false); + }); + } else { + // SOCKET + + const data = { + zoneData: zone, + projectId: projectId, + versionId: selectedVersion?.versionId || "", + userId: userId, + organization: organization, + }; + + builderSocket.emit("v1:zone:add", data); + + setTempPoints([]); + setIsCreating(false); + } + } + }; + const onMouseClick = () => { if (drag.current || !toggleView) return; @@ -113,7 +164,7 @@ function ZoneCreator() { viewPortTarget: viewPortPosition ? [viewPortPosition.x, 0, viewPortPosition.y] : [0, 0, 0], }; - addZone(zone); + addZoneToBackend(zone); push2D({ type: "Draw", @@ -129,25 +180,6 @@ function ZoneCreator() { ], }); - if (projectId) { - if (!builderSocket?.connected) { - // API - - upsertZoneApi(projectId, selectedVersion?.versionId || "", zone); - } else { - // SOCKET - - const data = { - zoneData: zone, - projectId: projectId, - versionId: selectedVersion?.versionId || "", - userId: userId, - organization: organization, - }; - - builderSocket.emit("v1:zone:add", data); - } - } setTempPoints([]); setIsCreating(false); } else if (isCreating && snappedPoint && !tempPoints.some((p) => p.pointUuid === snappedPoint.pointUuid)) { @@ -169,7 +201,7 @@ function ZoneCreator() { viewPortTarget: viewPortPosition ? [viewPortPosition.x, 0, viewPortPosition.y] : [0, 0, 0], }; - addZone(zone); + addZoneToBackend(zone); push2D({ type: "Draw", @@ -185,25 +217,6 @@ function ZoneCreator() { ], }); - if (projectId) { - if (!builderSocket?.connected) { - // API - - upsertZoneApi(projectId, selectedVersion?.versionId || "", zone); - } else { - // SOCKET - - const data = { - zoneData: zone, - projectId: projectId, - versionId: selectedVersion?.versionId || "", - userId: userId, - organization: organization, - }; - - builderSocket.emit("v1:zone:add", data); - } - } setTempPoints([]); setIsCreating(false); } else if (tempPoints.length === 0 || (tempPoints.length > 1 && !tempPoints.slice(1).some((p) => p.pointUuid === pointIntersects.object.uuid))) { @@ -234,7 +247,7 @@ function ZoneCreator() { viewPortTarget: viewPortPosition ? [viewPortPosition.x, 0, viewPortPosition.y] : [0, 0, 0], }; - addZone(zone); + addZoneToBackend(zone); push2D({ type: "Draw", @@ -249,27 +262,8 @@ function ZoneCreator() { }, ], }); - - if (projectId) { - if (!builderSocket?.connected) { - // API - - upsertZoneApi(projectId, selectedVersion?.versionId || "", zone); - } else { - // SOCKET - - const data = { - zoneData: zone, - projectId: projectId, - versionId: selectedVersion?.versionId || "", - userId: userId, - organization: organization, - }; - - builderSocket.emit("v1:zone:add", data); - } - } } + setTempPoints([]); setIsCreating(false); } @@ -302,26 +296,7 @@ function ZoneCreator() { canvasElement.removeEventListener("click", onMouseClick); canvasElement.removeEventListener("contextmenu", onContext); }; - }, [ - gl, - camera, - scene, - raycaster, - plane, - toggleView, - toolMode, - activeLayer, - builderSocket, - tempPoints, - isCreating, - zones, - addZone, - getZonePointById, - zoneColor, - zoneHeight, - snappedPosition, - snappedPoint, - ]); + }, [gl, camera, raycaster, plane, toggleView, toolMode, activeLayer, builderSocket, tempPoints, isCreating, zones, zoneColor, zoneHeight, snappedPosition, snappedPoint]); return ( <> diff --git a/app/src/modules/collaboration/socket/builderResponses.tsx b/app/src/modules/collaboration/socket/builderResponses.tsx index e227296..cfab5a7 100644 --- a/app/src/modules/collaboration/socket/builderResponses.tsx +++ b/app/src/modules/collaboration/socket/builderResponses.tsx @@ -7,6 +7,7 @@ import useWallAssetResponseHandler from "../responseHandler/useWallAssetResponse import useWallResponseHandler from "../responseHandler/useWallResponseHandler"; import useAisleResponseHandler from "../responseHandler/useAisleResponseHandler"; import useFloorResponseHandler from "../responseHandler/useFloorResponseHandler"; +import useZoneResponseHandler from "../responseHandler/useZoneResponseHandler"; function BuilderResponses() { const { assetStore } = useSceneContext(); @@ -18,6 +19,7 @@ function BuilderResponses() { const { addWallToScene, updateWallInScene, removeWallFromScene } = useWallResponseHandler(); const { addAisleToScene, updateAisleInScene, removeAisleFromScene } = useAisleResponseHandler(); const { addFloorToScene, updateFloorInScene, removeFloorFromScene } = useFloorResponseHandler(); + const { addZoneToScene, updateZoneInScene, removeZoneFromScene } = useZoneResponseHandler(); //#region Asset useEffect(() => { @@ -478,15 +480,60 @@ function BuilderResponses() { if (!builderSocket) return; builderSocket.on("v1:zone:response:updates", (data: any) => { - if (!data.message) return; - if (data.message === "zone created successfully") { - } else if (data.message === "zone updated") { + if (!data.message || !data.data) { + echo.error(`Error adding or updating zone`); + return; + } + if (data.message === "Zone Created Successfully") { + const zone: Zone = { + zoneUuid: data.data.zoneUuid, + zoneName: data.data.zoneName, + zoneHeight: data.data.zoneHeight, + zoneColor: data.data.zoneColor, + points: data.data.points, + viewPortPosition: data.data.viewPortPosition, + viewPortTarget: data.data.viewPortTarget, + }; + + addZoneToScene(zone, () => { + echo.info(`Added zone: ${zone.zoneName}`); + }); + } else if (data.message === "Zone Updated Successfully") { + const zone: Zone = { + zoneUuid: data.data.zoneUuid, + zoneName: data.data.zoneName, + zoneHeight: data.data.zoneHeight, + zoneColor: data.data.zoneColor, + points: data.data.points, + viewPortPosition: data.data.viewPortPosition, + viewPortTarget: data.data.viewPortTarget, + }; + + updateZoneInScene(zone, () => { + // if (selectedZone?.zoneData.zoneUuid === zone.zoneUuid) { + // setSelectedZone({ zoneData: zone, zoneMesh: selectedZone.zoneMesh }); + // } + + echo.info(`Updated zone: ${zone.zoneName}`); + }); + } else { + removeZoneFromScene(data.data.zoneUuid, () => { + echo.error(`Error adding or updating zone: ${data?.data?.zoneName}`); + }); } }); builderSocket.on("v1:zone:response:delete", (data: any) => { - if (!data.message) return; - if (data.message === "zone deleted created successfully") { + if (!data.message || !data.data) { + echo.error(`Error deleting zone`); + return; + } + if (data.message === "Zone Deleted Successfully") { + removeZoneFromScene(data.data.zoneUuid, () => { + echo.info(`Removed zone: ${data.data.zoneName}`); + }); + } else { + echo.error(`Error removing zone: ${data?.data?.zoneName}`); } }); diff --git a/app/src/modules/scene/controls/controls.tsx b/app/src/modules/scene/controls/controls.tsx index e422959..add6457 100644 --- a/app/src/modules/scene/controls/controls.tsx +++ b/app/src/modules/scene/controls/controls.tsx @@ -10,6 +10,7 @@ import { useSceneStore } from "../../../store/scene/useSceneStore"; import CamMode from "../camera/camMode"; import SwitchView from "../camera/switchView"; import SyncCam from "../camera/syncCam"; +// import GizmoControls from "./gizmoControls/gizmoControls"; import ContextControls from "./contextControls/contextControls"; import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D"; import SelectionControls3D from "./selectionControls/selection3D/selectionControls3D"; @@ -166,7 +167,9 @@ export default function Controls() { {/* 3D */} - + + {/* */} + @@ -180,7 +183,7 @@ export default function Controls() { - + {/* 2D */} diff --git a/app/src/modules/scene/gizmo/gizmo.tsx b/app/src/modules/scene/controls/gizmoControls/gizmoControls.tsx similarity index 86% rename from app/src/modules/scene/gizmo/gizmo.tsx rename to app/src/modules/scene/controls/gizmoControls/gizmoControls.tsx index 68c36aa..b7e7950 100644 --- a/app/src/modules/scene/gizmo/gizmo.tsx +++ b/app/src/modules/scene/controls/gizmoControls/gizmoControls.tsx @@ -2,20 +2,14 @@ import { useEffect, useRef } from "react"; import { useThree, useFrame } from "@react-three/fiber"; import { ViewportGizmo } from "three-viewport-gizmo"; import { PerspectiveCamera, WebGLRenderer, Scene } from "three"; +import { CameraControls } from "@react-three/drei"; -type Controls = { - enabled: boolean; - setPosition: (...args: number[]) => void; - getTarget: (target: any) => void; - addEventListener: (type: string, listener: (...args: any[]) => void) => void; -}; - -export const Gizmo = () => { +const GizmoControls = () => { const { camera, gl, scene, controls } = useThree<{ camera: PerspectiveCamera; gl: WebGLRenderer; scene: Scene; - controls?: Controls; + controls: CameraControls; }>(); const gizmoRef = useRef(null); @@ -23,6 +17,7 @@ export const Gizmo = () => { useEffect(() => { const gizmo = new ViewportGizmo(camera, gl, {}); gizmoRef.current = gizmo; + gizmoRef.current.renderOrder = 2; const resize = () => { const width = window.innerWidth; @@ -65,3 +60,5 @@ export const Gizmo = () => { return null; }; + +export default GizmoControls; diff --git a/app/src/modules/scene/controls/pointControls/moveControls2D.tsx b/app/src/modules/scene/controls/pointControls/moveControls2D.tsx index 26df635..16547df 100644 --- a/app/src/modules/scene/controls/pointControls/moveControls2D.tsx +++ b/app/src/modules/scene/controls/pointControls/moveControls2D.tsx @@ -21,6 +21,7 @@ import useWallAssetResponseHandler from "../../../collaboration/responseHandler/ import useWallResponseHandler from "../../../collaboration/responseHandler/useWallResponseHandler"; import useAisleResponseHandler from "../../../collaboration/responseHandler/useAisleResponseHandler"; import useFloorResponseHandler from "../../../collaboration/responseHandler/useFloorResponseHandler"; +import useZoneResponseHandler from "../../../collaboration/responseHandler/useZoneResponseHandler"; function MoveControls2D({ movedObjects, setMovedObjects, pastedObjects, setPastedObjects, duplicatedObjects, setDuplicatedObjects, rotatedObjects, setRotatedObjects }: any) { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); @@ -39,6 +40,7 @@ function MoveControls2D({ movedObjects, setMovedObjects, pastedObjects, setPaste const { updateWallInScene } = useWallResponseHandler(); const { updateAisleInScene } = useAisleResponseHandler(); const { updateFloorInScene } = useFloorResponseHandler(); + const { updateZoneInScene } = useZoneResponseHandler(); const { push2D } = undoRedo2DStore(); const { setPosition: setAislePosition, getAislesByPointId, getAisleById } = aisleStore(); const { setPosition: setWallPosition, getWallsByPointId, getWallById } = wallStore(); @@ -458,7 +460,23 @@ function MoveControls2D({ movedObjects, setMovedObjects, pastedObjects, setPaste if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone); + upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + return; + } + if (data.message === "Zone Updated Successfully") { + updateZoneInScene(updatedZone, () => { + echo.info(`Updated zone: ${updatedZone.zoneName}`); + }); + } else { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + }); } else { // SOCKET diff --git a/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx b/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx index 7167cd1..f674fed 100644 --- a/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx @@ -16,6 +16,7 @@ import useWallAssetResponseHandler from "../../../../collaboration/responseHandl import useWallResponseHandler from "../../../../collaboration/responseHandler/useWallResponseHandler"; import useAisleResponseHandler from "../../../../collaboration/responseHandler/useAisleResponseHandler"; import useFloorResponseHandler from "../../../../collaboration/responseHandler/useFloorResponseHandler"; +import useZoneResponseHandler from "../../../../collaboration/responseHandler/useZoneResponseHandler"; import MoveControls2D from "../../pointControls/moveControls2D"; import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi"; @@ -48,6 +49,7 @@ const SelectionControls2D: React.FC = () => { const { removeWallFromScene } = useWallResponseHandler(); const { removeAisleFromScene } = useAisleResponseHandler(); const { removeFloorFromScene, updateFloorInScene } = useFloorResponseHandler(); + const { removeZoneFromScene, updateZoneInScene } = useZoneResponseHandler(); const { push2D } = undoRedo2DStore(); const { peekRemovePoint: peekRemoveAislePoint } = aisleStore(); const { peekRemovePoint: peekRemoveWallPoint } = wallStore(); @@ -371,17 +373,33 @@ const SelectionControls2D: React.FC = () => { const Zones = getZonesByPointId(point.pointUuid); const { removedZones, updatedZones } = removeZonePoint(point.pointUuid); if (removedZones.length > 0) { - removedZones.forEach((zone) => { + removedZones.forEach((removedZone) => { if (projectId) { if (!builderSocket?.connected) { // API - deleteZoneApi(projectId, selectedVersion?.versionId || "", zone.zoneUuid); + deleteZoneApi(projectId, selectedVersion?.versionId || "", removedZone.zoneUuid) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error removing zone`); + return; + } + if (data.message === "Zone Deleted Successfully") { + removeZoneFromScene(removedZone.zoneUuid, () => { + echo.info(`Removed zone: ${removedZone.zoneName}`); + }); + } else { + echo.error(`Error removing zone: ${removedZone.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error removing zone: ${removedZone.zoneName}`); + }); } else { // SOCKET const data = { - zoneUuid: zone.zoneUuid, + zoneUuid: removedZone.zoneUuid, projectId: projectId, versionId: selectedVersion?.versionId || "", userId: userId, @@ -402,17 +420,33 @@ const SelectionControls2D: React.FC = () => { processedZones.push(...removedZonesData); } if (updatedZones.length > 0) { - updatedZones.forEach((zone) => { + updatedZones.forEach((updatedZone) => { if (projectId) { if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", zone); + upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + return; + } + if (data.message === "Zone Updated Successfully") { + updateZoneInScene(updatedZone, () => { + echo.info(`Updated zone: ${updatedZone.zoneName}`); + }); + } else { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error updating zone: ${updatedZone.zoneName}`); + }); } else { // SOCKET const data = { - zoneData: zone, + zoneData: updatedZone, projectId: projectId, versionId: selectedVersion?.versionId || "", userId: userId, diff --git a/app/src/modules/scene/controls/undoRedoControls/handlers/use2DRedoHandler.ts b/app/src/modules/scene/controls/undoRedoControls/handlers/use2DRedoHandler.ts index 2906828..cb73bd5 100644 --- a/app/src/modules/scene/controls/undoRedoControls/handlers/use2DRedoHandler.ts +++ b/app/src/modules/scene/controls/undoRedoControls/handlers/use2DRedoHandler.ts @@ -5,6 +5,7 @@ import { useSocketStore } from "../../../../../store/socket/useSocketStore"; import useWallResponseHandler from "../../../../collaboration/responseHandler/useWallResponseHandler"; import useAisleResponseHandler from "../../../../collaboration/responseHandler/useAisleResponseHandler"; import useFloorResponseHandler from "../../../../collaboration/responseHandler/useFloorResponseHandler"; +import useZoneResponseHandler from "../../../../collaboration/responseHandler/useZoneResponseHandler"; import { upsertWallApi } from "../../../../../services/factoryBuilder/wall/upsertWallApi"; import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi"; @@ -19,12 +20,12 @@ import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/ups import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi"; function use2DRedoHandler() { - const { undoRedo2DStore, zoneStore, versionStore } = useSceneContext(); + const { undoRedo2DStore, versionStore } = useSceneContext(); const { redo2D, peekRedo2D } = undoRedo2DStore(); const { addWallToScene, removeWallFromScene, updateWallInScene } = useWallResponseHandler(); const { addAisleToScene, removeAisleFromScene, updateAisleInScene } = useAisleResponseHandler(); const { addFloorToScene, removeFloorFromScene, updateFloorInScene } = useFloorResponseHandler(); - const { addZone, removeZone, updateZone } = zoneStore(); + const { addZoneToScene, removeZoneFromScene, updateZoneInScene } = useZoneResponseHandler(); const { selectedVersion } = versionStore(); const { userId, organization } = getUserData(); const { projectId } = useParams(); @@ -241,19 +242,19 @@ function use2DRedoHandler() { upsertFloorApi(projectId, selectedVersion?.versionId || "", floorData) .then((data) => { if (!data.message || !data.data) { - echo.error(`Error adding floor`); + echo.error(`Error adding floor: ${floorData.floorName}`); return; } if (data.message === "Floor Created Successfully") { addFloorToScene(floorData, () => { - echo.info(`Added floor: ${floorData.floorUuid}`); + echo.info(`Added floor: ${floorData.floorName}`); }); } else { - echo.error(`Error adding floor: ${floorData.floorUuid}`); + echo.error(`Error adding floor: ${floorData.floorName}`); } }) .catch(() => { - echo.error(`Error adding floor: ${floorData.floorUuid}`); + echo.error(`Error adding floor: ${floorData.floorName}`); }); } else { // SOCKET @@ -279,7 +280,7 @@ function use2DRedoHandler() { deleteFloorApi(projectId, selectedVersion?.versionId || "", floorUuid) .then((data) => { if (!data.message || !data.data) { - echo.error(`Error removing floor`); + echo.error(`Error removing floor: ${floorUuid}`); return; } if (data.message === "Floor Deleted Successfully") { @@ -317,17 +318,17 @@ function use2DRedoHandler() { upsertFloorApi(projectId, selectedVersion?.versionId || "", updatedData) .then((data) => { if (!data.message || !data.data) { - echo.error(`Error updating floor`); + echo.error(`Error updating floor: ${updatedData.floorName}`); return; } if (data.message === "Floor Updated Successfully") { updateFloorInScene(updatedData, () => { - echo.info(`Updated floor: ${floorUuid}`); + echo.info(`Updated floor: ${updatedData.floorName}`); }); } }) .catch(() => { - echo.error(`Error updating floor: ${floorUuid}`); + echo.error(`Error updating floor: ${updatedData.floorName}`); }); } else { // SOCKET @@ -346,12 +347,27 @@ function use2DRedoHandler() { }; const createZoneFromBackend = (zoneData: Zone) => { - addZone(zoneData); if (projectId) { if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", zoneData); + upsertZoneApi(projectId, selectedVersion?.versionId || "", zoneData) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error adding zone: ${zoneData.zoneName}`); + return; + } + if (data.message === "Zone Created Successfully") { + addZoneToScene(zoneData, () => { + echo.info(`Added zone: ${zoneData.zoneName}`); + }); + } else { + echo.error(`Error adding zone: ${zoneData.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error adding zone: ${zoneData.zoneName}`); + }); } else { // SOCKET @@ -369,12 +385,27 @@ function use2DRedoHandler() { }; const removeZoneFromBackend = (zoneUuid: string) => { - removeZone(zoneUuid); if (projectId) { if (!builderSocket?.connected) { // API - deleteZoneApi(projectId, selectedVersion?.versionId || "", zoneUuid); + deleteZoneApi(projectId, selectedVersion?.versionId || "", zoneUuid) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error removing zone: ${zoneUuid}`); + return; + } + if (data.message === "Zone Deleted Successfully") { + removeZoneFromScene(zoneUuid, () => { + echo.info(`Removed zone: ${zoneUuid}`); + }); + } else { + echo.error(`Error removing zone: ${zoneUuid}`); + } + }) + .catch(() => { + echo.error(`Error removing zone: ${zoneUuid}`); + }); } else { // SOCKET @@ -392,12 +423,25 @@ function use2DRedoHandler() { }; const updateZoneFromBackend = (zoneUuid: string, updatedData: Zone) => { - updateZone(zoneUuid, updatedData); if (projectId) { if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedData); + upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedData) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error updating zone: ${updatedData.zoneName}`); + return; + } + if (data.message === "Zone Updated Successfully") { + updateZoneInScene(updatedData, () => { + echo.info(`Updated zone: ${updatedData.zoneName}`); + }); + } + }) + .catch(() => { + echo.error(`Error updating zone: ${updatedData.zoneName}`); + }); } else { // SOCKET diff --git a/app/src/modules/scene/controls/undoRedoControls/handlers/use2DUndoHandler.ts b/app/src/modules/scene/controls/undoRedoControls/handlers/use2DUndoHandler.ts index 7d644bd..12d724c 100644 --- a/app/src/modules/scene/controls/undoRedoControls/handlers/use2DUndoHandler.ts +++ b/app/src/modules/scene/controls/undoRedoControls/handlers/use2DUndoHandler.ts @@ -5,6 +5,7 @@ import { useSocketStore } from "../../../../../store/socket/useSocketStore"; import useWallResponseHandler from "../../../../collaboration/responseHandler/useWallResponseHandler"; import useAisleResponseHandler from "../../../../collaboration/responseHandler/useAisleResponseHandler"; import useFloorResponseHandler from "../../../../collaboration/responseHandler/useFloorResponseHandler"; +import useZoneResponseHandler from "../../../../collaboration/responseHandler/useZoneResponseHandler"; import { upsertWallApi } from "../../../../../services/factoryBuilder/wall/upsertWallApi"; import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi"; @@ -19,12 +20,12 @@ import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/ups import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi"; function use2DUndoHandler() { - const { undoRedo2DStore, zoneStore, versionStore } = useSceneContext(); + const { undoRedo2DStore, versionStore } = useSceneContext(); const { undo2D, peekUndo2D } = undoRedo2DStore(); const { addWallToScene, removeWallFromScene, updateWallInScene } = useWallResponseHandler(); const { addAisleToScene, removeAisleFromScene, updateAisleInScene } = useAisleResponseHandler(); const { addFloorToScene, removeFloorFromScene, updateFloorInScene } = useFloorResponseHandler(); - const { addZone, removeZone, updateZone } = zoneStore(); + const { addZoneToScene, removeZoneFromScene, updateZoneInScene } = useZoneResponseHandler(); const { selectedVersion } = versionStore(); const { userId, organization } = getUserData(); const { projectId } = useParams(); @@ -240,19 +241,19 @@ function use2DUndoHandler() { upsertFloorApi(projectId, selectedVersion?.versionId || "", floorData) .then((data) => { if (!data.message || !data.data) { - echo.error(`Error adding floor`); + echo.error(`Error adding floor: ${floorData.floorName}`); return; } if (data.message === "Floor Created Successfully") { addFloorToScene(floorData, () => { - echo.info(`Added floor: ${floorData.floorUuid}`); + echo.info(`Added floor: ${floorData.floorName}`); }); } else { - echo.error(`Error adding floor: ${floorData.floorUuid}`); + echo.error(`Error adding floor: ${floorData.floorName}`); } }) .catch(() => { - echo.error(`Error adding floor: ${floorData.floorUuid}`); + echo.error(`Error adding floor: ${floorData.floorName}`); }); } else { // SOCKET @@ -265,7 +266,6 @@ function use2DUndoHandler() { organization: organization, }; - console.log('data: ', data); builderSocket.emit("v1:model-Floor:add", data); } } @@ -279,7 +279,7 @@ function use2DUndoHandler() { deleteFloorApi(projectId, selectedVersion?.versionId || "", floorUuid) .then((data) => { if (!data.message || !data.data) { - echo.error(`Error removing floor`); + echo.error(`Error removing floor: ${floorUuid}`); return; } if (data.message === "Floor Deleted Successfully") { @@ -317,17 +317,17 @@ function use2DUndoHandler() { upsertFloorApi(projectId, selectedVersion?.versionId || "", updatedData) .then((data) => { if (!data.message || !data.data) { - echo.error(`Error updating floor`); + echo.error(`Error updating floor: ${updatedData.floorName}`); return; } if (data.message === "Floor Updated Successfully") { updateFloorInScene(updatedData, () => { - echo.info(`Updated floor: ${updatedData.floorUuid}`); + echo.info(`Updated floor: ${updatedData.floorName}`); }); } }) .catch(() => { - echo.error(`Error updating floor: ${updatedData.floorUuid}`); + echo.error(`Error updating floor: ${updatedData.floorName}`); }); } else { // SOCKET @@ -346,12 +346,27 @@ function use2DUndoHandler() { }; const createZoneToBackend = (zoneData: Zone) => { - addZone(zoneData); if (projectId) { if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", zoneData); + upsertZoneApi(projectId, selectedVersion?.versionId || "", zoneData) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error adding zone: ${zoneData.zoneName}`); + return; + } + if (data.message === "Zone Created Successfully") { + addZoneToScene(zoneData, () => { + echo.info(`Added zone: ${zoneData.zoneName}`); + }); + } else { + echo.error(`Error adding zone: ${zoneData.zoneName}`); + } + }) + .catch(() => { + echo.error(`Error adding zone: ${zoneData.zoneName}`); + }); } else { // SOCKET @@ -369,12 +384,27 @@ function use2DUndoHandler() { }; const removeZoneToBackend = (zoneUuid: string) => { - removeZone(zoneUuid); if (projectId) { if (!builderSocket?.connected) { // API - deleteZoneApi(projectId, selectedVersion?.versionId || "", zoneUuid); + deleteZoneApi(projectId, selectedVersion?.versionId || "", zoneUuid) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error removing zone: ${zoneUuid}`); + return; + } + if (data.message === "Zone Deleted Successfully") { + removeZoneFromScene(zoneUuid, () => { + echo.info(`Removed zone: ${zoneUuid}`); + }); + } else { + echo.error(`Error removing zone: ${zoneUuid}`); + } + }) + .catch(() => { + echo.error(`Error removing zone: ${zoneUuid}`); + }); } else { // SOCKET @@ -392,12 +422,25 @@ function use2DUndoHandler() { }; const updateZoneToBackend = (zoneUuid: string, updatedData: Zone) => { - updateZone(zoneUuid, updatedData); if (projectId) { if (!builderSocket?.connected) { // API - upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedData); + upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedData) + .then((data) => { + if (!data.message || !data.data) { + echo.error(`Error updating zone: ${updatedData.zoneName}`); + return; + } + if (data.message === "Zone Updated Successfully") { + updateZoneInScene(updatedData, () => { + echo.info(`Updated zone: ${updatedData.zoneName}`); + }); + } + }) + .catch(() => { + echo.error(`Error updating zone: ${updatedData.zoneName}`); + }); } else { // SOCKET diff --git a/app/src/modules/simulation/spatialUI/vehicle/useDraggableGLTF.ts b/app/src/modules/simulation/spatialUI/vehicle/useDraggableGLTF.ts index 8adec6b..f31ba33 100644 --- a/app/src/modules/simulation/spatialUI/vehicle/useDraggableGLTF.ts +++ b/app/src/modules/simulation/spatialUI/vehicle/useDraggableGLTF.ts @@ -7,9 +7,7 @@ type OnUpdateCallback = (object: THREE.Object3D) => void; export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { const { camera, gl, controls, scene } = useThree(); const activeObjRef = useRef(null); - const planeRef = useRef( - new THREE.Plane(new THREE.Vector3(0, 1, 0), 0) - ); + const planeRef = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); const offsetRef = useRef(new THREE.Vector3()); const initialPositionRef = useRef(new THREE.Vector3()); @@ -80,22 +78,14 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { // Add offset for dragging intersection.add(offsetRef.current); - console.log('intersection: ', intersection); // Get the parent's world matrix if exists const parent = activeObjRef.current.parent; const targetPosition = new THREE.Vector3(); if (isShiftKeyPressed) { - console.log('isShiftKeyPressed: ', isShiftKeyPressed); // For Y-axis only movement, maintain original X and Z - console.log('initialPositionRef: ', initialPositionRef); - console.log('intersection.y: ', intersection); - targetPosition.set( - initialPositionRef.current.x, - intersection.y, - initialPositionRef.current.z - ); + targetPosition.set(initialPositionRef.current.x, intersection.y, initialPositionRef.current.z); } else { // For free movement targetPosition.copy(intersection); @@ -126,6 +116,3 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) { return { handlePointerDown }; } - - - diff --git a/app/src/store/builder/useZoneStore.ts b/app/src/store/builder/useZoneStore.ts index 17134c7..afa934b 100644 --- a/app/src/store/builder/useZoneStore.ts +++ b/app/src/store/builder/useZoneStore.ts @@ -1,5 +1,5 @@ -import { create } from 'zustand'; -import { immer } from 'zustand/middleware/immer'; +import { create } from "zustand"; +import { immer } from "zustand/middleware/immer"; interface ZoneStore { zones: Zone[]; @@ -10,13 +10,12 @@ interface ZoneStore { setZoneHeight: (uuid: string, height: number) => void; setZoneColor: (uuid: string, color: string) => void; removeZone: (uuid: string) => void; - removePoint: (pointUuid: string) => { removedZones: Zone[], updatedZones: Zone[] }; - removeZoneByPoints: (points: Point[]) => { removedZones: Zone[], updatedZones: Zone[] }; + removePoint: (pointUuid: string) => { removedZones: Zone[]; updatedZones: Zone[] }; + peekRemovePoint: (pointUuid: string) => { removedZones: Zone[]; updatedZones: Zone[] }; + removeZoneByPoints: (points: Point[]) => { removedZones: Zone[]; updatedZones: Zone[] }; + peekRemoveZoneByPoints: (points: Point[]) => { removedZones: Zone[]; updatedZones: Zone[] }; clearZones: () => void; - setPosition: ( - pointUuid: string, - position: [number, number, number] - ) => Zone[] | []; + setPosition: (pointUuid: string, position: [number, number, number]) => Zone[] | []; setViewPort: (uuid: string, position: [number, number, number], target: [number, number, number]) => void; getZoneById: (uuid: string) => Zone | undefined; @@ -31,62 +30,69 @@ export const createZoneStore = () => { immer((set, get) => ({ zones: [], - setZones: (zones) => set(state => { - state.zones = zones; - }), + setZones: (zones) => + set((state) => { + state.zones = zones; + }), - addZone: (zone) => set(state => { - state.zones.push(zone); - }), + addZone: (zone) => + set((state) => { + state.zones.push(zone); + }), - updateZone: (uuid, updated) => set(state => { - const zone = state.zones.find(z => z.zoneUuid === uuid); - if (zone) { - Object.assign(zone, updated); - } - }), + updateZone: (uuid, updated) => + set((state) => { + const zone = state.zones.find((z) => z.zoneUuid === uuid); + if (zone) { + Object.assign(zone, updated); + } + }), - setZoneName: (uuid, name) => set(state => { - const zone = state.zones.find(z => z.zoneUuid === uuid); - if (zone) { - zone.zoneName = name; - } - }), + setZoneName: (uuid, name) => + set((state) => { + const zone = state.zones.find((z) => z.zoneUuid === uuid); + if (zone) { + zone.zoneName = name; + } + }), - setZoneHeight: (uuid, height) => set(state => { - const zone = state.zones.find(z => z.zoneUuid === uuid); - if (zone) { - zone.zoneHeight = height; - } - }), + setZoneHeight: (uuid, height) => + set((state) => { + const zone = state.zones.find((z) => z.zoneUuid === uuid); + if (zone) { + zone.zoneHeight = height; + } + }), - setZoneColor: (uuid, color) => set(state => { - const zone = state.zones.find(z => z.zoneUuid === uuid); - if (zone) { - zone.zoneColor = color; - } - }), + setZoneColor: (uuid, color) => + set((state) => { + const zone = state.zones.find((z) => z.zoneUuid === uuid); + if (zone) { + zone.zoneColor = color; + } + }), - removeZone: (uuid) => set(state => { - state.zones = state.zones.filter(z => z.zoneUuid !== uuid); - }), + removeZone: (uuid) => + set((state) => { + state.zones = state.zones.filter((z) => z.zoneUuid !== uuid); + }), removePoint: (pointUuid) => { const removedZones: Zone[] = []; const updatedZones: Zone[] = []; - set(state => { + set((state) => { const newZones: Zone[] = []; for (const zone of state.zones) { - const pointIndex = zone.points.findIndex(p => p.pointUuid === pointUuid); + const pointIndex = zone.points.findIndex((p) => p.pointUuid === pointUuid); if (pointIndex === -1) { newZones.push(zone); continue; } - const remainingPoints = zone.points.filter(p => p.pointUuid !== pointUuid); + const remainingPoints = zone.points.filter((p) => p.pointUuid !== pointUuid); if (remainingPoints.length <= 2) { removedZones.push(JSON.parse(JSON.stringify(zone))); @@ -104,37 +110,56 @@ export const createZoneStore = () => { return { removedZones, updatedZones }; }, + peekRemovePoint: (pointUuid: string) => { + const removedZones: Zone[] = []; + const updatedZones: Zone[] = []; + + const zones = get().zones; + + for (const zone of zones) { + const pointIndex = zone.points.findIndex((p) => p.pointUuid === pointUuid); + + if (pointIndex === -1) continue; + + const remainingPoints = zone.points.filter((p) => p.pointUuid !== pointUuid); + + if (remainingPoints.length <= 2) { + removedZones.push(JSON.parse(JSON.stringify(zone))); + } else { + const updatedZone = { ...zone, points: remainingPoints }; + updatedZones.push(JSON.parse(JSON.stringify(updatedZone))); + } + } + + return { removedZones, updatedZones }; + }, + removeZoneByPoints: ([pointA, pointB]) => { const removedZones: Zone[] = []; const updatedZones: Zone[] = []; - set(state => { + set((state) => { const newZones: Zone[] = []; for (const zone of state.zones) { const indices = zone.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); - const idxA = indices.find(i => i.uuid === pointA.pointUuid)?.index ?? -1; - const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; + const idxA = indices.find((i) => i.uuid === pointA.pointUuid)?.index ?? -1; + const idxB = indices.find((i) => i.uuid === pointB.pointUuid)?.index ?? -1; if (idxA === -1 || idxB === -1) { newZones.push(zone); continue; } - const areAdjacent = - Math.abs(idxA - idxB) === 1 || - (idxA === 0 && idxB === zone.points.length - 1) || - (idxB === 0 && idxA === zone.points.length - 1); + const areAdjacent = Math.abs(idxA - idxB) === 1 || (idxA === 0 && idxB === zone.points.length - 1) || (idxB === 0 && idxA === zone.points.length - 1); if (!areAdjacent) { newZones.push(zone); continue; } - const remainingPoints = zone.points.filter( - p => p.pointUuid !== pointA.pointUuid && p.pointUuid !== pointB.pointUuid - ); + const remainingPoints = zone.points.filter((p) => p.pointUuid !== pointA.pointUuid && p.pointUuid !== pointB.pointUuid); if (remainingPoints.length > 2) { const updatedZone = { ...zone, points: remainingPoints }; @@ -151,9 +176,45 @@ export const createZoneStore = () => { return { removedZones, updatedZones }; }, - clearZones: () => set(state => { - state.zones = []; - }), + peekRemoveZoneByPoints: ([pointA, pointB]) => { + const removedZones: Zone[] = []; + const updatedZones: Zone[] = []; + + const zones = get().zones; + + for (const zone of zones) { + const indices = zone.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); + + const idxA = indices.find((i) => i.uuid === pointA.pointUuid)?.index ?? -1; + const idxB = indices.find((i) => i.uuid === pointB.pointUuid)?.index ?? -1; + + if (idxA === -1 || idxB === -1) { + continue; + } + + const areAdjacent = Math.abs(idxA - idxB) === 1 || (idxA === 0 && idxB === zone.points.length - 1) || (idxB === 0 && idxA === zone.points.length - 1); + + if (!areAdjacent) { + continue; + } + + const remainingPoints = zone.points.filter((p) => p.pointUuid !== pointA.pointUuid && p.pointUuid !== pointB.pointUuid); + + if (remainingPoints.length > 2) { + const updatedZone = { ...zone, points: remainingPoints }; + updatedZones.push(JSON.parse(JSON.stringify(updatedZone))); + } else { + removedZones.push(JSON.parse(JSON.stringify(zone))); + } + } + + return { removedZones, updatedZones }; + }, + + clearZones: () => + set((state) => { + state.zones = []; + }), setPosition: (pointUuid, position) => { let updatedZone: Zone[] = []; @@ -169,21 +230,22 @@ export const createZoneStore = () => { return updatedZone; }, - setViewPort: (uuid, position, target) => set(state => { - const zone = state.zones.find(z => z.zoneUuid === uuid); - if (zone) { - zone.viewPortPosition = position; - zone.viewPortTarget = target; - } - }), + setViewPort: (uuid, position, target) => + set((state) => { + const zone = state.zones.find((z) => z.zoneUuid === uuid); + if (zone) { + zone.viewPortPosition = position; + zone.viewPortTarget = target; + } + }), getZoneById: (uuid) => { - return get().zones.find(z => z.zoneUuid === uuid); + return get().zones.find((z) => z.zoneUuid === uuid); }, getZonesByPointId: (pointUuid) => { - return get().zones.filter(zone => { - return zone.points.some(p => p.pointUuid === pointUuid); + return get().zones.filter((zone) => { + return zone.points.some((p) => p.pointUuid === pointUuid); }); }, @@ -193,17 +255,14 @@ export const createZoneStore = () => { for (const zone of get().zones) { const indices = zone.points.map((p, i) => ({ uuid: p.pointUuid, index: i })); - const idxA = indices.find(i => i.uuid === pointA.pointUuid)?.index ?? -1; - const idxB = indices.find(i => i.uuid === pointB.pointUuid)?.index ?? -1; + const idxA = indices.find((i) => i.uuid === pointA.pointUuid)?.index ?? -1; + const idxB = indices.find((i) => i.uuid === pointB.pointUuid)?.index ?? -1; if (idxA === -1 || idxB === -1) { continue; } - const areAdjacent = - Math.abs(idxA - idxB) === 1 || - (idxA === 0 && idxB === zone.points.length - 1) || - (idxB === 0 && idxA === zone.points.length - 1); + const areAdjacent = Math.abs(idxA - idxB) === 1 || (idxA === 0 && idxB === zone.points.length - 1) || (idxB === 0 && idxA === zone.points.length - 1); if (!areAdjacent) { continue; @@ -217,7 +276,7 @@ export const createZoneStore = () => { getZonePointById: (pointUuid) => { for (const zone of get().zones) { - const point = zone.points.find(p => p.pointUuid === pointUuid); + const point = zone.points.find((p) => p.pointUuid === pointUuid); if (point) return point; } return undefined; @@ -226,15 +285,14 @@ export const createZoneStore = () => { getConnectedPoints: (pointUuid) => { const connected: Point[] = []; for (const zone of get().zones) { - if (zone.points.some(p => p.pointUuid === pointUuid)) { - connected.push(...zone.points.filter(p => p.pointUuid !== pointUuid)); + if (zone.points.some((p) => p.pointUuid === pointUuid)) { + connected.push(...zone.points.filter((p) => p.pointUuid !== pointUuid)); } } return connected; - } - + }, })) ); }; -export type ZoneStoreType = ReturnType; \ No newline at end of file +export type ZoneStoreType = ReturnType; diff --git a/app/src/types/builderTypes.d.ts b/app/src/types/builderTypes.d.ts index 196afc2..bf089e0 100644 --- a/app/src/types/builderTypes.d.ts +++ b/app/src/types/builderTypes.d.ts @@ -135,8 +135,8 @@ interface Zone { zoneHeight: number; zoneColor: string; points: Point[]; - viewPortTarget: [number, number, number]; viewPortPosition: [number, number, number]; + viewPortTarget: [number, number, number]; } type Zones = Zone[];