From 04c302ea4c600069b4bcd940ab86945dd624e866 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 27 Jun 2025 10:48:48 +0530 Subject: [PATCH] Refactor floor management components and APIs: enhance FloorInstance for shape creation, update FloorInstances to handle floor rendering and UUID tracking, and improve FloorCreator with project and version context. Modify floor store methods for better floor management and integrate API calls for floor upsert and deletion. Adjust wall and point components to support new floor functionalities. --- .../Instances/Instance/floorInstance.tsx | 31 ++++++- .../floor/Instances/floorInstances.tsx | 9 +- .../floor/floorCreator/floorCreator.tsx | 57 +++++++++++-- app/src/modules/builder/floor/floorGroup.tsx | 26 +++++- app/src/modules/builder/line/line.tsx | 83 +++++++++++++++++-- app/src/modules/builder/point/point.tsx | 72 +++++++++++++++- app/src/modules/builder/wall/wallGroup.tsx | 9 +- .../factoryBuilder/floor/upsertFloorApi.ts | 2 +- app/src/store/builder/useBuilderStore.ts | 2 +- app/src/store/builder/useFloorStore.ts | 49 ++++++----- 10 files changed, 287 insertions(+), 53 deletions(-) diff --git a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx index 1b6dcb7..6c9016e 100644 --- a/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx +++ b/app/src/modules/builder/floor/Instances/Instance/floorInstance.tsx @@ -1,10 +1,33 @@ -import React from 'react' +import { useMemo } from 'react' +import { Shape, Vector2, DoubleSide } from 'three'; +import { useLoader } from '@react-three/fiber'; +import { Extrude } from '@react-three/drei'; +import * as Constants from '../../../../../types/world/worldConstants'; function FloorInstance({ floor }: { floor: Floor }) { + + const shape = useMemo(() => { + const shape = new Shape(); + const points = floor.points.map(p => new Vector2(p.position[0], p.position[2])); + if (points.length < 3) return null; + shape.moveTo(points[0].x, points[0].y); + points.forEach((pt) => { shape.lineTo(pt.x, pt.y); }); + return shape; + }, [floor]); + + if (!shape) return null; + return ( - <> - - ) + + + + + + ); } export default FloorInstance \ No newline at end of file diff --git a/app/src/modules/builder/floor/Instances/floorInstances.tsx b/app/src/modules/builder/floor/Instances/floorInstances.tsx index 75fd359..a5969eb 100644 --- a/app/src/modules/builder/floor/Instances/floorInstances.tsx +++ b/app/src/modules/builder/floor/Instances/floorInstances.tsx @@ -34,6 +34,7 @@ function FloorInstances() { const allLines = useMemo(() => { const lines: { start: Point; end: Point; key: string }[] = []; + const seenUuids = new Set(); floors.forEach((floor) => { const points = floor.points; @@ -42,11 +43,13 @@ function FloorInstances() { for (let i = 0; i < points.length; i++) { const current = points[i]; const next = points[(i + 1) % points.length]; - if (current.pointUuid !== next.pointUuid) { + const lineKey = `${current.pointUuid}-${next.pointUuid}`; + if (current.pointUuid !== next.pointUuid && !seenUuids.has(lineKey)) { + seenUuids.add(lineKey); lines.push({ start: current, end: next, - key: `${current.pointUuid}-${next.pointUuid}` + key: lineKey }); } } @@ -58,7 +61,7 @@ function FloorInstances() { return ( <> - {!toggleView && floors.length > 1 && ( + {!toggleView && floors.length > 0 && ( {floors.map((floor) => ( diff --git a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx index 2d09ff9..aaeb0f3 100644 --- a/app/src/modules/builder/floor/floorCreator/floorCreator.tsx +++ b/app/src/modules/builder/floor/floorCreator/floorCreator.tsx @@ -4,9 +4,14 @@ import { useThree } from '@react-three/fiber'; import { useActiveLayer, useSocketStore, useToggleView, useToolMode } from '../../../../store/builder/store'; import { useSceneContext } from '../../../scene/sceneContext'; import { useBuilderStore } from '../../../../store/builder/useBuilderStore'; +import { useParams } from 'react-router-dom'; +import { useVersionContext } from '../../version/versionContext'; +import { getUserData } from '../../../../functions/getUserData'; import ReferencePoint from '../../point/reference/referencePoint'; import ReferenceFloor from './referenceFloor'; +// import { upsertFloorApi } from '../../../../services/factoryBuilder/floor/upsertFloorApi'; + function FloorCreator() { const { scene, camera, raycaster, gl, pointer } = useThree(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); @@ -15,9 +20,13 @@ function FloorCreator() { const { activeLayer } = useActiveLayer(); const { socket } = useSocketStore(); const { floorStore } = useSceneContext(); - const { addFloor, removeDecal, getFloorPointById, getFloorByPoints } = floorStore(); + const { addFloor, getFloorPointById, getFloorByPoints } = floorStore(); const drag = useRef(false); const isLeftMouseDown = useRef(false); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { userId, organization } = getUserData(); + const { projectId } = useParams(); const [tempPoints, setTempPoints] = useState([]); const [isCreating, setIsCreating] = useState(false); @@ -94,14 +103,33 @@ function FloorCreator() { }; addFloor(floor); + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: floor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + + } setTempPoints([]); setIsCreating(false); - } else if (tempPoints.length === 0) { + } else if (tempPoints.length === 0 || (tempPoints.length > 1 && pointIntersects.object.uuid !== tempPoints[tempPoints.length - 2].pointUuid)) { tempPoints.push(pointIntersects.object.userData as Point); setIsCreating(true); } else { - setTempPoints([]); - setIsCreating(false); + tempPoints.push(pointIntersects.object.userData as Point); + setIsCreating(true); } } else { setTempPoints(prev => [...prev, newPoint]); @@ -126,6 +154,25 @@ function FloorCreator() { }; addFloor(floor); + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: floor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + + } } setTempPoints([]); setIsCreating(false); @@ -155,7 +202,7 @@ function FloorCreator() { canvasElement.removeEventListener("click", onMouseClick); canvasElement.removeEventListener("contextmenu", onContext); }; - }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addFloor, removeDecal, getFloorPointById, getFloorByPoints, floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint]); + }, [gl, camera, scene, raycaster, pointer, plane, toggleView, toolMode, activeLayer, socket, tempPoints, isCreating, addFloor, getFloorPointById, getFloorByPoints, floorDepth, isBeveled, bevelStrength, sideMaterial, topMaterial, snappedPosition, snappedPoint]); return ( <> diff --git a/app/src/modules/builder/floor/floorGroup.tsx b/app/src/modules/builder/floor/floorGroup.tsx index fdcf37c..53a81f4 100644 --- a/app/src/modules/builder/floor/floorGroup.tsx +++ b/app/src/modules/builder/floor/floorGroup.tsx @@ -1,14 +1,23 @@ import { useEffect } from 'react'; import { useToggleView } from '../../../store/builder/store' import { useBuilderStore } from '../../../store/builder/useBuilderStore'; +import { useVersionContext } from '../version/versionContext'; +import { useSceneContext } from '../../scene/sceneContext'; +import { useParams } from 'react-router-dom'; +import useModuleStore from '../../../store/useModuleStore'; import FloorCreator from './floorCreator/floorCreator'; import FloorInstances from './Instances/floorInstances'; -import useModuleStore from '../../../store/useModuleStore'; +import { getFloorsApi } from '../../../services/factoryBuilder/floor/getFloorsApi'; function FloorGroup() { const { togglView } = useToggleView(); const { setSelectedFloor, setSelectedDecal } = useBuilderStore(); const { activeModule } = useModuleStore(); + const { selectedVersionStore } = useVersionContext(); + const { selectedVersion } = selectedVersionStore(); + const { floorStore } = useSceneContext(); + const { setFloors } = floorStore(); + const { projectId } = useParams(); useEffect(() => { if (togglView || activeModule !== 'builder') { @@ -17,6 +26,21 @@ function FloorGroup() { } }, [togglView, activeModule]) + useEffect(() => { + if (projectId && selectedVersion) { + getFloorsApi(projectId, selectedVersion?.versionId || '').then((floors) => { + console.log('floors: ', floors); + if (floors && floors.length > 0) { + setFloors(floors); + } else { + setFloors([]); + } + }).catch((err) => { + console.log(err); + }) + } + }, [projectId, selectedVersion?.versionId]) + return ( <> diff --git a/app/src/modules/builder/line/line.tsx b/app/src/modules/builder/line/line.tsx index 42aa5c2..f75be5d 100644 --- a/app/src/modules/builder/line/line.tsx +++ b/app/src/modules/builder/line/line.tsx @@ -6,12 +6,15 @@ import { useSocketStore, useToolMode } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; import { useSceneContext } from '../../scene/sceneContext'; import * as Constants from '../../../types/world/worldConstants'; -import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; import { useVersionContext } from '../version/versionContext'; import { useParams } from 'react-router-dom'; -import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; import { getUserData } from '../../../functions/getUserData'; +// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; +// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; +import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; +import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi'; + interface LineProps { points: [Point, Point]; } @@ -25,7 +28,7 @@ function Line({ points }: Readonly) { const { toolMode } = useToolMode(); const { wallStore, floorStore } = useSceneContext(); const { removeWallByPoints, setPosition: setWallPosition, getWallsByPointId } = wallStore(); - const { removeFloorByPoints, setPosition: setFloorPosition } = floorStore(); + const { removeFloorByPoints, setPosition: setFloorPosition, getFloorsByPointId } = floorStore(); const { userId, organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); @@ -112,7 +115,52 @@ function Line({ points }: Readonly) { setHoveredLine(null); } if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') { - removeFloorByPoints(points); + const { removedFloors, updatedFloors } = removeFloorByPoints(points); + if (removedFloors.length > 0) { + removedFloors.forEach(floor => { + if (projectId) { + + // API + + // deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid); + + // SOCKET + + const data = { + floorUuid: floor.floorUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:delete', data); + } + }); + } + if (updatedFloors.length > 0) { + updatedFloors.forEach(floor => { + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: floor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + }); + } + setHoveredLine(null); } gl.domElement.style.cursor = 'default'; @@ -197,7 +245,32 @@ function Line({ points }: Readonly) { }) } } else if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') { - // Handle floor update logic here if needed + const updatedFloors1 = getFloorsByPointId(points[0].pointUuid); + const updatedFloors2 = getFloorsByPointId(points[1].pointUuid); + const updatedFloors = [...updatedFloors1, ...updatedFloors2].filter((floor, index, self) => index === self.findIndex((f) => f.floorUuid === floor.floorUuid)); + + if (updatedFloors.length > 0 && projectId) { + updatedFloors.forEach(updatedFloor => { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor).catch((error) => { + // console.error('Error updating floor:', error); + // }); + + // SOCKET + + const data = { + floorData: updatedFloor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + }) + } } } diff --git a/app/src/modules/builder/point/point.tsx b/app/src/modules/builder/point/point.tsx index 504617d..fe2dd6e 100644 --- a/app/src/modules/builder/point/point.tsx +++ b/app/src/modules/builder/point/point.tsx @@ -14,7 +14,10 @@ import { upsertAisleApi } from '../../../services/factoryBuilder/aisle/upsertAis import { deleteAisleApi } from '../../../services/factoryBuilder/aisle/deleteAisleApi'; // import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi'; // import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi'; +import { upsertFloorApi } from '../../../services/factoryBuilder/floor/upsertFloorApi'; + import { getUserData } from '../../../functions/getUserData'; +import { deleteFloorApi } from '../../../services/factoryBuilder/floor/deleteFloorApi'; function Point({ point }: { readonly point: Point }) { const materialRef = useRef(null); @@ -27,7 +30,7 @@ function Point({ point }: { readonly point: Point }) { const { aisleStore, wallStore, floorStore } = useSceneContext(); const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore(); const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore(); - const { setPosition: setFloorPosition, removePoint: removeFloorPoint } = floorStore(); + const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore(); const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position }); const { hoveredPoint, setHoveredPoint } = useBuilderStore(); const { userId, organization } = getUserData(); @@ -174,9 +177,28 @@ function Point({ point }: { readonly point: Point }) { socket.emit('v1:model-Wall:add', data); }); } - // console.log('Wall after drag: ', point); } else if (point.pointType === 'Floor') { - // console.log('Floor after drag: ', point); + const updatedFloors = getFloorsByPointId(point.pointUuid); + if (updatedFloors && updatedFloors.length > 0 && projectId) { + updatedFloors.forEach((updatedFloor) => { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor); + + // SOCKET + + const data = { + floorData: updatedFloor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + }); + } } } @@ -220,9 +242,51 @@ function Point({ point }: { readonly point: Point }) { } } if (point.pointType === 'Floor') { - const removedFloors = removeFloorPoint(point.pointUuid); + const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid); setHoveredPoint(null); if (removedFloors.length > 0) { + removedFloors.forEach(floor => { + if (projectId) { + + // API + + // deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid); + + // SOCKET + + const data = { + floorUuid: floor.floorUuid, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:delete', data); + } + }); + } + if (updatedFloors.length > 0) { + updatedFloors.forEach(floor => { + if (projectId) { + + // API + + // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor); + + // SOCKET + + const data = { + floorData: floor, + projectId: projectId, + versionId: selectedVersion?.versionId || '', + userId: userId, + organization: organization + } + + socket.emit('v1:model-Floor:add', data); + } + }); } } gl.domElement.style.cursor = 'default'; diff --git a/app/src/modules/builder/wall/wallGroup.tsx b/app/src/modules/builder/wall/wallGroup.tsx index 0722d56..bd8bad1 100644 --- a/app/src/modules/builder/wall/wallGroup.tsx +++ b/app/src/modules/builder/wall/wallGroup.tsx @@ -1,12 +1,13 @@ import { useEffect } from 'react'; import { useToggleView } from '../../../store/builder/store'; import { useBuilderStore } from '../../../store/builder/useBuilderStore'; +import { useVersionContext } from '../version/versionContext'; +import { useSceneContext } from '../../scene/sceneContext'; +import { useParams } from 'react-router-dom'; +import useModuleStore from '../../../store/useModuleStore'; import WallCreator from './wallCreator/wallCreator'; import WallInstances from './Instances/wallInstances'; -import useModuleStore from '../../../store/useModuleStore'; -import { useVersionContext } from '../version/versionContext'; -import { useParams } from 'react-router-dom'; -import { useSceneContext } from '../../scene/sceneContext'; + import { getWallsApi } from '../../../services/factoryBuilder/wall/getWallsApi'; function WallGroup() { diff --git a/app/src/services/factoryBuilder/floor/upsertFloorApi.ts b/app/src/services/factoryBuilder/floor/upsertFloorApi.ts index a00d8f7..45590c1 100644 --- a/app/src/services/factoryBuilder/floor/upsertFloorApi.ts +++ b/app/src/services/factoryBuilder/floor/upsertFloorApi.ts @@ -3,7 +3,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const upsertFloorApi = async ( projectId: string, versionId: string, - floorData: Wall + floorData: Floor ) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/V1/UpsertFloor`, { diff --git a/app/src/store/builder/useBuilderStore.ts b/app/src/store/builder/useBuilderStore.ts index 18facd9..e35db75 100644 --- a/app/src/store/builder/useBuilderStore.ts +++ b/app/src/store/builder/useBuilderStore.ts @@ -97,7 +97,7 @@ export const useBuilderStore = create()( insideMaterial: 'Material 1', selectedFloor: null, - floorDepth: 0.3, + floorDepth: 0.1, isBeveled: false, bevelStrength: 0.05, sideMaterial: 'Default Side', diff --git a/app/src/store/builder/useFloorStore.ts b/app/src/store/builder/useFloorStore.ts index c3ddf7d..7d425eb 100644 --- a/app/src/store/builder/useFloorStore.ts +++ b/app/src/store/builder/useFloorStore.ts @@ -7,8 +7,8 @@ interface FloorStore { addFloor: (floor: Floor) => void; updateFloor: (uuid: string, updated: Partial) => void; removeFloor: (uuid: string) => void; - removePoint: (pointUuid: string) => Floor[]; - removeFloorByPoints: (Points: [Point, Point]) => Floor[]; + removePoint: (pointUuid: string) => { removedFloors: Floor[], updatedFloors: Floor[] }; + removeFloorByPoints: (Points: [Point, Point]) => { removedFloors: Floor[], updatedFloors: Floor[] }; clearFloors: () => void; setPosition: ( pointUuid: string, @@ -26,7 +26,7 @@ interface FloorStore { updateDecalScale: (decalUuid: string, scale: number) => void; getFloorById: (uuid: string) => Floor | undefined; - getFloorsByPointId: (uuid: string) => Floor | undefined; + getFloorsByPointId: (uuid: string) => Floor[] | []; getFloorByPoints: (points: Point[]) => Floor | undefined; getFloorPointById: (uuid: string) => Point | undefined; getConnectedPoints: (uuid: string) => Point[]; @@ -58,47 +58,46 @@ export const createFloorStore = () => { removePoint: (pointUuid) => { const removedFloors: Floor[] = []; + const updatedFloors: Floor[] = []; set(state => { - const updatedFloors: Floor[] = []; - for (const floor of state.floors) { - const hasPoint = floor.points.some(p => p.pointUuid === pointUuid); - if (!hasPoint) { - updatedFloors.push(floor); + const pointIndex = floor.points.findIndex(p => p.pointUuid === pointUuid); + if (pointIndex === -1) { + updatedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } const remainingPoints = floor.points.filter(p => p.pointUuid !== pointUuid); - if (remainingPoints.length > 2) { - floor.points = remainingPoints; - updatedFloors.push(floor); - } else { - removedFloors.push(floor); + + if (remainingPoints.length <= 2) { + removedFloors.push(JSON.parse(JSON.stringify(floor))); + continue; } + floor.points = remainingPoints; + updatedFloors.push(JSON.parse(JSON.stringify(floor))); } state.floors = updatedFloors; }); - return removedFloors; + return { removedFloors, updatedFloors }; }, removeFloorByPoints: ([pointA, pointB]) => { const removedFloors: Floor[] = []; + const updatedFloors: Floor[] = []; set(state => { - const updatedFloors: Floor[] = []; for (const floor of state.floors) { - const indices = floor.points - .map((p, i) => ({ uuid: p.pointUuid, index: i })); + const indices = floor.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) { - updatedFloors.push(floor); + updatedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } @@ -108,7 +107,7 @@ export const createFloorStore = () => { (idxB === 0 && idxA === floor.points.length - 1); if (!areAdjacent) { - updatedFloors.push(floor); + updatedFloors.push(JSON.parse(JSON.stringify(floor))); continue; } @@ -118,16 +117,16 @@ export const createFloorStore = () => { if (remainingPoints.length > 2) { floor.points = remainingPoints; - updatedFloors.push(floor); + updatedFloors.push(JSON.parse(JSON.stringify(floor))); } else { - removedFloors.push(floor); + removedFloors.push(JSON.parse(JSON.stringify(floor))); } } state.floors = updatedFloors; }); - return removedFloors; + return { removedFloors, updatedFloors }; }, clearFloors: () => set(state => { @@ -236,9 +235,9 @@ export const createFloorStore = () => { }, getFloorsByPointId: (pointUuid) => { - return get().floors.find(floor => - floor.points.some(p => p.pointUuid === pointUuid) - ); + return get().floors.filter(floor => { + return floor.points.some(p => p.pointUuid === pointUuid); + }); }, getFloorByPoints: (points) => {