feat: Enhance undo/redo functionality in MoveControls2D and SelectionControls2D; process deleted and updated aisles, walls, floors, and zones for better state management
This commit is contained in:
@@ -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<THREE.Vector3 | null>(null);
|
||||
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
|
||||
const [initialStates, setInitialStates] = useState<Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }>>({});
|
||||
@@ -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<string, UndoRedo2DDataTypeSchema[]>();
|
||||
|
||||
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<string, UndoRedo2DDataTypeSchema[]>();
|
||||
|
||||
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<string, UndoRedo2DDataTypeSchema[]>();
|
||||
|
||||
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<string, UndoRedo2DDataTypeSchema[]>();
|
||||
|
||||
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();
|
||||
|
||||
@@ -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<string, UndoRedo2DDataTypeSchema[]>();
|
||||
|
||||
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<string, UndoRedo2DDataTypeSchema[]>();
|
||||
|
||||
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<string, UndoRedo2DDataTypeSchema[]>();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user