From d6f8a29b839c1f32ac1bf316769fd88f95dc35c0 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 31 Jul 2025 09:53:49 +0530 Subject: [PATCH] feat: Enhance undo/redo functionality in MoveControls2D and SelectionControls2D; process deleted and updated aisles, walls, floors, and zones for better state management --- .../selection2D/moveControls2D.tsx | 210 ++++++++++++++---- .../selection2D/selectionControls2D.tsx | 51 ++++- 2 files changed, 212 insertions(+), 49 deletions(-) diff --git a/app/src/modules/scene/controls/selectionControls/selection2D/moveControls2D.tsx b/app/src/modules/scene/controls/selectionControls/selection2D/moveControls2D.tsx index 8f800f0..f6d04f0 100644 --- a/app/src/modules/scene/controls/selectionControls/selection2D/moveControls2D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection2D/moveControls2D.tsx @@ -38,10 +38,10 @@ function MoveControls2D({ const { selectedVersion } = selectedVersionStore(); const { aisleStore, wallStore, floorStore, zoneStore, undoRedo2DStore } = useSceneContext(); const { push2D } = undoRedo2DStore(); - const { setPosition: setAislePosition, getAislesByPointId } = aisleStore(); - const { setPosition: setWallPosition, getWallsByPointId } = wallStore(); - const { setPosition: setFloorPosition, getFloorsByPointId } = floorStore(); - const { setPosition: setZonePosition, getZonesByPointId } = zoneStore(); + const { setPosition: setAislePosition, getAislesByPointId, getAisleById } = aisleStore(); + const { setPosition: setWallPosition, getWallsByPointId, getWallById } = wallStore(); + const { setPosition: setFloorPosition, getFloorsByPointId, getFloorById } = floorStore(); + const { setPosition: setZonePosition, getZonesByPointId, getZoneById } = zoneStore(); const [dragOffset, setDragOffset] = useState(null); const [initialPositions, setInitialPositions] = useState>({}); const [initialStates, setInitialStates] = useState>({}); @@ -225,6 +225,10 @@ function MoveControls2D({ if (movedObjects.length === 0) return; const undoPoints: UndoRedo2DDataTypeSchema[] = []; + const processedAisles: UndoRedo2DDataTypeSchema[] = []; + const processedWalls: UndoRedo2DDataTypeSchema[] = []; + const processedFloors: UndoRedo2DDataTypeSchema[] = []; + const processedZones: UndoRedo2DDataTypeSchema[] = []; movedObjects.forEach((movedObject: THREE.Object3D) => { if (movedObject.userData.pointUuid) { @@ -253,7 +257,7 @@ function MoveControls2D({ const old = initialStates[movedObject.uuid]; if (old) { - undoPoints.push({ + processedAisles.push({ type: 'Aisle', lineData: { ...updatedAisle, @@ -293,7 +297,7 @@ function MoveControls2D({ const old = initialStates[movedObject.uuid]; if (old) { - undoPoints.push({ + processedWalls.push({ type: 'Wall', lineData: { ...updatedWall, @@ -313,6 +317,7 @@ function MoveControls2D({ }); } } else if (point.pointType === 'Floor') { + const Floors = getFloorsByPointId(point.pointUuid); const updatedFloors = getFloorsByPointId(point.pointUuid); if (updatedFloors?.length && projectId) { updatedFloors.forEach(updatedFloor => { @@ -331,25 +336,27 @@ function MoveControls2D({ organization }); - const old = initialStates[movedObject.uuid]; - if (old) { - undoPoints.push({ - type: 'Floor', - lineData: { - ...updatedFloor, - points: updatedFloor.points.map(p => - p.pointUuid === point.pointUuid - ? { ...p, position: [old.position.x, old.position.y, old.position.z] } - : p - ), - }, - newData: updatedFloor, + const updatedFloorsData = updatedFloors.map((floor) => { + const originalFloor = Floors.find(f => f.floorUuid === floor.floorUuid) || floor; + + const updatedPoints = originalFloor.points.map((pt: Point) => { + const init = initialStates[pt.pointUuid]; + return init ? { ...pt, position: [init.position.x, init.position.y, init.position.z] } : pt; + }) as [Point, Point]; + + return { + type: "Floor" as const, + lineData: { ...originalFloor, points: updatedPoints }, + newData: floor, timeStamp: new Date().toISOString(), - }); - } + }; + }); + + processedFloors.push(...updatedFloorsData); }); } } else if (point.pointType === 'Zone') { + const Zones = getZonesByPointId(point.pointUuid); const updatedZones = getZonesByPointId(point.pointUuid); if (updatedZones?.length && projectId) { updatedZones.forEach(updatedZone => { @@ -368,39 +375,150 @@ function MoveControls2D({ organization }); - const old = initialStates[movedObject.uuid]; - if (old) { - undoPoints.push({ - type: 'Zone', - lineData: { - ...updatedZone, - points: updatedZone.points.map(p => - p.pointUuid === point.pointUuid - ? { ...p, position: [old.position.x, old.position.y, old.position.z] } - : p - ), - }, - newData: updatedZone, + const updatedZonesData = updatedZones.map((zone) => { + const originalZone = Zones.find(z => z.zoneUuid === zone.zoneUuid) || zone; + + const updatedPoints = originalZone.points.map((pt: Point) => { + const init = initialStates[pt.pointUuid]; + return init ? { ...pt, position: [init.position.x, init.position.y, init.position.z] } : pt; + }) as [Point, Point]; + + return { + type: "Zone" as const, + lineData: { ...originalZone, points: updatedPoints }, + newData: zone, timeStamp: new Date().toISOString(), - }); - } + }; + }); + + processedZones.push(...updatedZonesData); }); } } } }); - if (undoPoints.length > 0) { - push2D({ - type: 'Draw', - actions: [ - { - actionType: 'Lines-Update', - points: undoPoints + setTimeout(() => { + if (processedWalls.length > 0) { + const wallMap = new Map(); + + for (const wall of processedWalls) { + if (wall.type !== 'Wall' || !wall.lineData.wallUuid) continue; + const uuid = wall.lineData.wallUuid; + if (!wallMap.has(uuid)) wallMap.set(uuid, []); + wallMap.get(uuid)!.push(wall); + } + + wallMap.forEach((actions, uuid) => { + const hasUpdate = actions.some(action => 'newData' in action); + if (hasUpdate) { + const wallData = getWallById(uuid); + if (wallData) { + undoPoints.push({ + type: 'Wall', + lineData: actions[0].lineData as Wall, + newData: wallData as Wall, + timeStamp: new Date().toISOString() + }); + } } - ] - }); - } + }); + } + + if (processedAisles.length > 0) { + const aisleMap = new Map(); + + for (const aisle of processedAisles) { + if (aisle.type !== 'Aisle' || !aisle.lineData.aisleUuid) continue; + const uuid = aisle.lineData.aisleUuid; + if (!aisleMap.has(uuid)) aisleMap.set(uuid, []); + aisleMap.get(uuid)!.push(aisle); + } + + aisleMap.forEach((actions, uuid) => { + const hasUpdate = actions.some(action => 'newData' in action); + if (hasUpdate) { + const aisleData = getAisleById(uuid); + if (aisleData) { + undoPoints.push({ + type: 'Aisle', + lineData: actions[0].lineData as Aisle, + newData: aisleData as Aisle, + timeStamp: new Date().toISOString() + }); + } + } + }); + } + + if (processedFloors.length > 0) { + const floorMap = new Map(); + + for (const floor of processedFloors) { + if (floor.type !== 'Floor' || !floor.lineData.floorUuid) continue; + const uuid = floor.lineData.floorUuid; + if (!floorMap.has(uuid)) { + floorMap.set(uuid, []); + } + floorMap.get(uuid)!.push(floor); + } + + floorMap.forEach((actions, uuid) => { + const hasUpdate = actions.some(action => 'newData' in action); + if (hasUpdate) { + const floorData = getFloorById(uuid); + if (floorData) { + undoPoints.push({ + type: 'Floor', + lineData: actions[0].lineData as Floor, + newData: floorData as Floor, + timeStamp: new Date().toISOString() + }); + } + } + }); + } + + if (processedZones.length > 0) { + const zoneMap = new Map(); + + for (const zone of processedZones) { + if (zone.type !== 'Zone' || !zone.lineData.zoneUuid) continue; + const uuid = zone.lineData.zoneUuid; + if (!zoneMap.has(uuid)) { + zoneMap.set(uuid, []); + } + zoneMap.get(uuid)!.push(zone); + } + + zoneMap.forEach((actions, uuid) => { + const hasUpdate = actions.some(action => 'newData' in action); + if (hasUpdate) { + const zoneData = getZoneById(uuid); + if (zoneData) { + undoPoints.push({ + type: 'Zone', + lineData: actions[0].lineData as Zone, + newData: zoneData as Zone, + timeStamp: new Date().toISOString() + }); + } + } + }); + } + + if (undoPoints.length > 0) { + push2D({ + type: 'Draw', + actions: [ + { + actionType: 'Lines-Update', + points: undoPoints + } + ] + }); + } + }, 0); echo.success("Object moved!"); clearSelection(); diff --git a/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx b/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx index a823e55..3ca6f99 100644 --- a/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection2D/selectionControls2D.tsx @@ -226,7 +226,8 @@ const SelectionControls2D: React.FC = () => { const deletedPoints: UndoRedo2DDataTypeSchema[] = []; const updatedPoints: UndoRedo2DDataTypeSchema[] = []; - + const processedAisles: UndoRedo2DDataTypeSchema[] = []; + const processedWalls: UndoRedo2DDataTypeSchema[] = []; const processedFloors: UndoRedo2DDataTypeSchema[] = []; const processedZones: UndoRedo2DDataTypeSchema[] = []; @@ -263,7 +264,7 @@ const SelectionControls2D: React.FC = () => { timeStamp: new Date().toISOString(), })); - deletedPoints.push(...removedAislesData); + processedAisles.push(...removedAislesData); } } if (point.pointType === 'Wall') { @@ -296,7 +297,7 @@ const SelectionControls2D: React.FC = () => { timeStamp: new Date().toISOString(), })); - deletedPoints.push(...removedWallsData); + processedWalls.push(...removedWallsData); } } if (point.pointType === 'Floor') { @@ -433,6 +434,50 @@ const SelectionControls2D: React.FC = () => { }) setTimeout(() => { + if (processedWalls.length > 0) { + const wallMap = new Map(); + + for (const wall of processedWalls) { + if (wall.type !== 'Wall' || !wall.lineData.wallUuid) continue; + const uuid = wall.lineData.wallUuid; + if (!wallMap.has(uuid)) wallMap.set(uuid, []); + wallMap.get(uuid)!.push(wall); + } + + wallMap.forEach((actions) => { + const hasDelete = actions.some(action => !('newData' in action)); + if (hasDelete) { + deletedPoints.push({ + type: 'Wall', + lineData: actions[0].lineData as Wall, + timeStamp: new Date().toISOString() + }); + } + }); + } + + if (processedAisles.length > 0) { + const aisleMap = new Map(); + + for (const aisle of processedAisles) { + if (aisle.type !== 'Aisle' || !aisle.lineData.aisleUuid) continue; + const uuid = aisle.lineData.aisleUuid; + if (!aisleMap.has(uuid)) aisleMap.set(uuid, []); + aisleMap.get(uuid)!.push(aisle); + } + + aisleMap.forEach((actions) => { + const hasDelete = actions.some(action => !('newData' in action)); + if (hasDelete) { + deletedPoints.push({ + type: 'Aisle', + lineData: actions[0].lineData as Aisle, + timeStamp: new Date().toISOString() + }); + } + }); + } + if (processedFloors.length > 0) { const floorMap = new Map();