feat: Integrate undo/redo functionality for aisle and line creation; enhance selection controls for better state management
This commit is contained in:
@@ -19,8 +19,9 @@ function AisleCreator() {
|
|||||||
const { toolMode } = useToolMode();
|
const { toolMode } = useToolMode();
|
||||||
const { activeLayer } = useActiveLayer();
|
const { activeLayer } = useActiveLayer();
|
||||||
const { socket } = useSocketStore();
|
const { socket } = useSocketStore();
|
||||||
const { aisleStore } = useSceneContext();
|
const { aisleStore, undoRedo2DStore } = useSceneContext();
|
||||||
const { addAisle, getAislePointById } = aisleStore();
|
const { addAisle, getAislePointById } = aisleStore();
|
||||||
|
const { push2D } = undoRedo2DStore();
|
||||||
const drag = useRef(false);
|
const drag = useRef(false);
|
||||||
const isLeftMouseDown = useRef(false);
|
const isLeftMouseDown = useRef(false);
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
@@ -107,7 +108,23 @@ function AisleCreator() {
|
|||||||
aisleWidth: aisleWidth
|
aisleWidth: aisleWidth
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Line-Create',
|
||||||
|
point: {
|
||||||
|
type: 'Aisle',
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
@@ -145,7 +162,23 @@ function AisleCreator() {
|
|||||||
gapLength: gapLength
|
gapLength: gapLength
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Line-Create',
|
||||||
|
point: {
|
||||||
|
type: 'Aisle',
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
@@ -182,7 +215,23 @@ function AisleCreator() {
|
|||||||
gapLength: gapLength
|
gapLength: gapLength
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Line-Create',
|
||||||
|
point: {
|
||||||
|
type: 'Aisle',
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
@@ -218,7 +267,23 @@ function AisleCreator() {
|
|||||||
aisleWidth: aisleWidth
|
aisleWidth: aisleWidth
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Line-Create',
|
||||||
|
point: {
|
||||||
|
type: 'Aisle',
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
@@ -256,7 +321,23 @@ function AisleCreator() {
|
|||||||
gapLength: gapLength
|
gapLength: gapLength
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Line-Create',
|
||||||
|
point: {
|
||||||
|
type: 'Aisle',
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
@@ -293,7 +374,23 @@ function AisleCreator() {
|
|||||||
isFlipped: isFlipped
|
isFlipped: isFlipped
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Line-Create',
|
||||||
|
point: {
|
||||||
|
type: 'Aisle',
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
@@ -329,7 +426,23 @@ function AisleCreator() {
|
|||||||
aisleWidth: aisleWidth
|
aisleWidth: aisleWidth
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Line-Create',
|
||||||
|
point: {
|
||||||
|
type: 'Aisle',
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
@@ -366,7 +479,23 @@ function AisleCreator() {
|
|||||||
isFlipped: isFlipped
|
isFlipped: isFlipped
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
addAisle(aisle);
|
addAisle(aisle);
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Line-Create',
|
||||||
|
point: {
|
||||||
|
type: 'Aisle',
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore();
|
const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore();
|
||||||
const { selectedPoints } = useSelectedPoints();
|
const { selectedPoints } = useSelectedPoints();
|
||||||
|
|
||||||
|
const [initialPositions, setInitialPositions] = useState<{
|
||||||
|
aisles?: Aisle[],
|
||||||
|
walls?: Wall[],
|
||||||
|
floors?: Floor[],
|
||||||
|
zones?: Zone[]
|
||||||
|
}>({});
|
||||||
|
|
||||||
const path = useMemo(() => {
|
const path = useMemo(() => {
|
||||||
const [start, end] = points.map(p => new THREE.Vector3(...p.position));
|
const [start, end] = points.map(p => new THREE.Vector3(...p.position));
|
||||||
return new THREE.LineCurve3(start, end);
|
return new THREE.LineCurve3(start, end);
|
||||||
@@ -353,6 +360,17 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
|
|
||||||
const offset = new THREE.Vector3().subVectors(midPoint, hit);
|
const offset = new THREE.Vector3().subVectors(midPoint, hit);
|
||||||
setDragOffset(offset);
|
setDragOffset(offset);
|
||||||
|
|
||||||
|
if (points[0].pointType === 'Wall') {
|
||||||
|
const walls = getWallsByPointId(points[0].pointUuid);
|
||||||
|
setInitialPositions({ walls });
|
||||||
|
} else if (points[0].pointType === 'Floor') {
|
||||||
|
const floors = getFloorsByPointId(points[0].pointUuid);
|
||||||
|
setInitialPositions({ floors });
|
||||||
|
} else if (points[0].pointType === 'Zone') {
|
||||||
|
const zones = getZonesByPointId(points[0].pointUuid);
|
||||||
|
setInitialPositions({ zones });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -370,9 +388,7 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall).catch((error) => {
|
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||||
// console.error('Error updating wall:', error);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// SOCKET
|
// SOCKET
|
||||||
|
|
||||||
@@ -386,6 +402,23 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
|
|
||||||
socket.emit('v1:model-Wall:add', data);
|
socket.emit('v1:model-Wall:add', data);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (initialPositions.walls && initialPositions.walls.length > 0) {
|
||||||
|
const updatedPoints = initialPositions.walls.map((wall) => ({
|
||||||
|
type: "Wall" as const,
|
||||||
|
lineData: wall,
|
||||||
|
newData: updatedWalls.find(w => w.wallUuid === wall.wallUuid),
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [{
|
||||||
|
actionType: 'Lines-Update',
|
||||||
|
points: updatedPoints,
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') {
|
} else if (points[0].pointType === 'Floor' && points[1].pointType === 'Floor') {
|
||||||
const updatedFloors1 = getFloorsByPointId(points[0].pointUuid);
|
const updatedFloors1 = getFloorsByPointId(points[0].pointUuid);
|
||||||
@@ -397,9 +430,7 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor).catch((error) => {
|
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
|
||||||
// console.error('Error updating floor:', error);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// SOCKET
|
// SOCKET
|
||||||
|
|
||||||
@@ -413,6 +444,23 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
|
|
||||||
socket.emit('v1:model-Floor:add', data);
|
socket.emit('v1:model-Floor:add', data);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (initialPositions.floors && initialPositions.floors.length > 0) {
|
||||||
|
const updatedPoints = initialPositions.floors.map((floor) => ({
|
||||||
|
type: "Floor" as const,
|
||||||
|
lineData: floor,
|
||||||
|
newData: updatedFloors.find(f => f.floorUuid === floor.floorUuid),
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [{
|
||||||
|
actionType: 'Lines-Update',
|
||||||
|
points: updatedPoints,
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') {
|
} else if (points[0].pointType === 'Zone' && points[1].pointType === 'Zone') {
|
||||||
const updatedZones1 = getZonesByPointId(points[0].pointUuid);
|
const updatedZones1 = getZonesByPointId(points[0].pointUuid);
|
||||||
@@ -424,9 +472,7 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone).catch((error) => {
|
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
|
||||||
// console.error('Error updating zone:', error);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// SOCKET
|
// SOCKET
|
||||||
|
|
||||||
@@ -440,6 +486,23 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
|
|
||||||
socket.emit('v1:zone:add', data);
|
socket.emit('v1:zone:add', data);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (initialPositions.zones && initialPositions.zones.length > 0) {
|
||||||
|
const updatedPoints = initialPositions.zones.map((zone) => ({
|
||||||
|
type: "Zone" as const,
|
||||||
|
lineData: zone,
|
||||||
|
newData: updatedZones.find(z => z.zoneUuid === zone.zoneUuid),
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [{
|
||||||
|
actionType: 'Lines-Update',
|
||||||
|
points: updatedPoints,
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ function MoveControls2D({
|
|||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { selectedVersionStore } = useVersionContext();
|
const { selectedVersionStore } = useVersionContext();
|
||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext();
|
const { aisleStore, wallStore, floorStore, zoneStore, undoRedo2DStore } = useSceneContext();
|
||||||
|
const { push2D } = undoRedo2DStore();
|
||||||
const { setPosition: setAislePosition, getAislesByPointId } = aisleStore();
|
const { setPosition: setAislePosition, getAislesByPointId } = aisleStore();
|
||||||
const { setPosition: setWallPosition, getWallsByPointId } = wallStore();
|
const { setPosition: setWallPosition, getWallsByPointId } = wallStore();
|
||||||
const { setPosition: setFloorPosition, getFloorsByPointId } = floorStore();
|
const { setPosition: setFloorPosition, getFloorsByPointId } = floorStore();
|
||||||
@@ -223,6 +224,8 @@ function MoveControls2D({
|
|||||||
const placeMovedAssets = () => {
|
const placeMovedAssets = () => {
|
||||||
if (movedObjects.length === 0) return;
|
if (movedObjects.length === 0) return;
|
||||||
|
|
||||||
|
const undoPoints: UndoRedo2DDataTypeSchema[] = [];
|
||||||
|
|
||||||
movedObjects.forEach((movedObject: THREE.Object3D) => {
|
movedObjects.forEach((movedObject: THREE.Object3D) => {
|
||||||
if (movedObject.userData.pointUuid) {
|
if (movedObject.userData.pointUuid) {
|
||||||
const point: Point = movedObject.userData as Point;
|
const point: Point = movedObject.userData as Point;
|
||||||
@@ -236,45 +239,83 @@ function MoveControls2D({
|
|||||||
|
|
||||||
// upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
// upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
|
||||||
|
|
||||||
// SOCKET
|
// SOCKET
|
||||||
|
|
||||||
socket.emit('v1:model-aisle:add', {
|
socket.emit('v1:model-aisle:add', {
|
||||||
projectId: projectId,
|
projectId,
|
||||||
versionId: selectedVersion?.versionId || '',
|
versionId: selectedVersion?.versionId || '',
|
||||||
userId: userId,
|
userId,
|
||||||
organization: organization,
|
organization,
|
||||||
aisleUuid: updatedAisle.aisleUuid,
|
aisleUuid: updatedAisle.aisleUuid,
|
||||||
points: updatedAisle.points,
|
points: updatedAisle.points,
|
||||||
type: updatedAisle.type
|
type: updatedAisle.type
|
||||||
})
|
});
|
||||||
})
|
|
||||||
|
const old = initialStates[movedObject.uuid];
|
||||||
|
if (old) {
|
||||||
|
undoPoints.push({
|
||||||
|
type: 'Aisle',
|
||||||
|
lineData: {
|
||||||
|
...updatedAisle,
|
||||||
|
points: [
|
||||||
|
updatedAisle.points[0].pointUuid === point.pointUuid
|
||||||
|
? { ...updatedAisle.points[0], position: [old.position.x, old.position.y, old.position.z] }
|
||||||
|
: updatedAisle.points[0],
|
||||||
|
updatedAisle.points[1].pointUuid === point.pointUuid
|
||||||
|
? { ...updatedAisle.points[1], position: [old.position.x, old.position.y, old.position.z] }
|
||||||
|
: updatedAisle.points[1]
|
||||||
|
] as [Point, Point],
|
||||||
|
},
|
||||||
|
newData: updatedAisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else if (point.pointType === 'Wall') {
|
} else if (point.pointType === 'Wall') {
|
||||||
const updatedWalls = getWallsByPointId(point.pointUuid);
|
const updatedWalls = getWallsByPointId(point.pointUuid);
|
||||||
if (updatedWalls && updatedWalls.length > 0 && projectId) {
|
if (updatedWalls?.length && projectId) {
|
||||||
updatedWalls.forEach((updatedWall) => {
|
updatedWalls.forEach(updatedWall => {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
|
||||||
|
|
||||||
// SOCKET
|
// SOCKET
|
||||||
|
|
||||||
const data = {
|
socket.emit('v1:model-Wall:add', {
|
||||||
wallData: updatedWall,
|
wallData: updatedWall,
|
||||||
projectId: projectId,
|
projectId,
|
||||||
versionId: selectedVersion?.versionId || '',
|
versionId: selectedVersion?.versionId || '',
|
||||||
userId: userId,
|
userId,
|
||||||
organization: organization
|
organization
|
||||||
}
|
});
|
||||||
|
|
||||||
socket.emit('v1:model-Wall:add', data);
|
const old = initialStates[movedObject.uuid];
|
||||||
|
if (old) {
|
||||||
|
undoPoints.push({
|
||||||
|
type: 'Wall',
|
||||||
|
lineData: {
|
||||||
|
...updatedWall,
|
||||||
|
points: [
|
||||||
|
updatedWall.points[0].pointUuid === point.pointUuid
|
||||||
|
? { ...updatedWall.points[0], position: [old.position.x, old.position.y, old.position.z] }
|
||||||
|
: updatedWall.points[0],
|
||||||
|
updatedWall.points[1].pointUuid === point.pointUuid
|
||||||
|
? { ...updatedWall.points[1], position: [old.position.x, old.position.y, old.position.z] }
|
||||||
|
: updatedWall.points[1]
|
||||||
|
] as [Point, Point],
|
||||||
|
},
|
||||||
|
newData: updatedWall,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (point.pointType === 'Floor') {
|
} else if (point.pointType === 'Floor') {
|
||||||
const updatedFloors = getFloorsByPointId(point.pointUuid);
|
const updatedFloors = getFloorsByPointId(point.pointUuid);
|
||||||
if (updatedFloors && updatedFloors.length > 0 && projectId) {
|
if (updatedFloors?.length && projectId) {
|
||||||
updatedFloors.forEach((updatedFloor) => {
|
updatedFloors.forEach(updatedFloor => {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
@@ -282,21 +323,36 @@ function MoveControls2D({
|
|||||||
|
|
||||||
// SOCKET
|
// SOCKET
|
||||||
|
|
||||||
const data = {
|
socket.emit('v1:model-Floor:add', {
|
||||||
floorData: updatedFloor,
|
floorData: updatedFloor,
|
||||||
projectId: projectId,
|
projectId,
|
||||||
versionId: selectedVersion?.versionId || '',
|
versionId: selectedVersion?.versionId || '',
|
||||||
userId: userId,
|
userId,
|
||||||
organization: organization
|
organization
|
||||||
}
|
});
|
||||||
|
|
||||||
socket.emit('v1:model-Floor:add', data);
|
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,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (point.pointType === 'Zone') {
|
} else if (point.pointType === 'Zone') {
|
||||||
const updatedZones = getZonesByPointId(point.pointUuid);
|
const updatedZones = getZonesByPointId(point.pointUuid);
|
||||||
if (updatedZones && updatedZones.length > 0 && projectId) {
|
if (updatedZones?.length && projectId) {
|
||||||
updatedZones.forEach((updatedZone) => {
|
updatedZones.forEach(updatedZone => {
|
||||||
|
|
||||||
// API
|
// API
|
||||||
|
|
||||||
@@ -304,23 +360,49 @@ function MoveControls2D({
|
|||||||
|
|
||||||
// SOCKET
|
// SOCKET
|
||||||
|
|
||||||
const data = {
|
socket.emit('v1:zone:add', {
|
||||||
zoneData: updatedZone,
|
zoneData: updatedZone,
|
||||||
projectId: projectId,
|
projectId,
|
||||||
versionId: selectedVersion?.versionId || '',
|
versionId: selectedVersion?.versionId || '',
|
||||||
userId: userId,
|
userId,
|
||||||
organization: organization
|
organization
|
||||||
}
|
});
|
||||||
|
|
||||||
socket.emit('v1:zone:add', data);
|
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,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
if (undoPoints.length > 0) {
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Lines-Update',
|
||||||
|
points: undoPoints
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
echo.success("Object moved!");
|
echo.success("Object moved!");
|
||||||
|
|
||||||
clearSelection();
|
clearSelection();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import MoveControls2D from "./moveControls2D";
|
|||||||
// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
|
// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
|
||||||
|
|
||||||
const SelectionControls2D: React.FC = () => {
|
const SelectionControls2D: React.FC = () => {
|
||||||
const { camera, controls, gl, scene, raycaster, pointer } = useThree();
|
const { camera, controls, gl, scene, pointer } = useThree();
|
||||||
const { toggleView } = useToggleView();
|
const { toggleView } = useToggleView();
|
||||||
const { selectedPoints, setSelectedPoints, clearSelectedPoints } = useSelectedPoints();
|
const { selectedPoints, setSelectedPoints, clearSelectedPoints } = useSelectedPoints();
|
||||||
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
|
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
|
||||||
@@ -38,11 +38,12 @@ const SelectionControls2D: React.FC = () => {
|
|||||||
const { selectedVersion } = selectedVersionStore();
|
const { selectedVersion } = selectedVersionStore();
|
||||||
const { projectId } = useParams();
|
const { projectId } = useParams();
|
||||||
const { hoveredLine, hoveredPoint } = useBuilderStore();
|
const { hoveredLine, hoveredPoint } = useBuilderStore();
|
||||||
const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext();
|
const { aisleStore, wallStore, floorStore, zoneStore, undoRedo2DStore } = useSceneContext();
|
||||||
|
const { push2D } = undoRedo2DStore();
|
||||||
const { removePoint: removeAislePoint } = aisleStore();
|
const { removePoint: removeAislePoint } = aisleStore();
|
||||||
const { removePoint: removeWallPoint } = wallStore();
|
const { removePoint: removeWallPoint } = wallStore();
|
||||||
const { removePoint: removeFloorPoint } = floorStore();
|
const { removePoint: removeFloorPoint, getFloorsByPointId, getFloorById } = floorStore();
|
||||||
const { removePoint: removeZonePoint } = zoneStore();
|
const { removePoint: removeZonePoint, getZonesByPointId, getZoneById } = zoneStore();
|
||||||
|
|
||||||
const isDragging = useRef(false);
|
const isDragging = useRef(false);
|
||||||
const isLeftMouseDown = useRef(false);
|
const isLeftMouseDown = useRef(false);
|
||||||
@@ -223,6 +224,12 @@ const SelectionControls2D: React.FC = () => {
|
|||||||
const deleteSelection = () => {
|
const deleteSelection = () => {
|
||||||
if (selectedPoints.length > 0 && duplicatedObjects.length === 0) {
|
if (selectedPoints.length > 0 && duplicatedObjects.length === 0) {
|
||||||
|
|
||||||
|
const deletedPoints: UndoRedo2DDataTypeSchema[] = [];
|
||||||
|
const updatedPoints: UndoRedo2DDataTypeSchema[] = [];
|
||||||
|
|
||||||
|
const processedFloors: UndoRedo2DDataTypeSchema[] = [];
|
||||||
|
const processedZones: UndoRedo2DDataTypeSchema[] = [];
|
||||||
|
|
||||||
selectedPoints.forEach((selectedPoint) => {
|
selectedPoints.forEach((selectedPoint) => {
|
||||||
if (selectedPoint.userData.pointUuid) {
|
if (selectedPoint.userData.pointUuid) {
|
||||||
const point: Point = selectedPoint.userData as Point;
|
const point: Point = selectedPoint.userData as Point;
|
||||||
@@ -249,6 +256,14 @@ const SelectionControls2D: React.FC = () => {
|
|||||||
socket.emit('v1:model-aisle:delete', data);
|
socket.emit('v1:model-aisle:delete', data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const removedAislesData = removedAisles.map((aisle) => ({
|
||||||
|
type: "Aisle" as const,
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
deletedPoints.push(...removedAislesData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (point.pointType === 'Wall') {
|
if (point.pointType === 'Wall') {
|
||||||
@@ -274,9 +289,18 @@ const SelectionControls2D: React.FC = () => {
|
|||||||
socket.emit('v1:model-Wall:delete', data);
|
socket.emit('v1:model-Wall:delete', data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const removedWallsData = removedWalls.map((wall) => ({
|
||||||
|
type: "Wall" as const,
|
||||||
|
lineData: wall,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
deletedPoints.push(...removedWallsData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (point.pointType === 'Floor') {
|
if (point.pointType === 'Floor') {
|
||||||
|
const Floors = getFloorsByPointId(point.pointUuid);
|
||||||
const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid);
|
const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid);
|
||||||
if (removedFloors.length > 0) {
|
if (removedFloors.length > 0) {
|
||||||
removedFloors.forEach(floor => {
|
removedFloors.forEach(floor => {
|
||||||
@@ -299,6 +323,14 @@ const SelectionControls2D: React.FC = () => {
|
|||||||
socket.emit('v1:model-Floor:delete', data);
|
socket.emit('v1:model-Floor:delete', data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const removedFloorsData = removedFloors.map((floor) => ({
|
||||||
|
type: "Floor" as const,
|
||||||
|
lineData: floor,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
processedFloors.push(...removedFloorsData);
|
||||||
}
|
}
|
||||||
if (updatedFloors.length > 0) {
|
if (updatedFloors.length > 0) {
|
||||||
updatedFloors.forEach(floor => {
|
updatedFloors.forEach(floor => {
|
||||||
@@ -321,9 +353,19 @@ const SelectionControls2D: React.FC = () => {
|
|||||||
socket.emit('v1:model-Floor:add', data);
|
socket.emit('v1:model-Floor:add', data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const updatedFloorsData = updatedFloors.map((floor) => ({
|
||||||
|
type: "Floor" as const,
|
||||||
|
lineData: Floors.find(f => f.floorUuid === floor.floorUuid) || floor,
|
||||||
|
newData: floor,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
processedFloors.push(...updatedFloorsData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (point.pointType === 'Zone') {
|
if (point.pointType === 'Zone') {
|
||||||
|
const Zones = getZonesByPointId(point.pointUuid);
|
||||||
const { removedZones, updatedZones } = removeZonePoint(point.pointUuid);
|
const { removedZones, updatedZones } = removeZonePoint(point.pointUuid);
|
||||||
if (removedZones.length > 0) {
|
if (removedZones.length > 0) {
|
||||||
removedZones.forEach(zone => {
|
removedZones.forEach(zone => {
|
||||||
@@ -346,6 +388,14 @@ const SelectionControls2D: React.FC = () => {
|
|||||||
socket.emit('v1:zone:delete', data);
|
socket.emit('v1:zone:delete', data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const removedZonesData = removedZones.map((zone) => ({
|
||||||
|
type: "Zone" as const,
|
||||||
|
lineData: zone,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
processedZones.push(...removedZonesData);
|
||||||
}
|
}
|
||||||
if (updatedZones.length > 0) {
|
if (updatedZones.length > 0) {
|
||||||
updatedZones.forEach(zone => {
|
updatedZones.forEach(zone => {
|
||||||
@@ -368,11 +418,129 @@ const SelectionControls2D: React.FC = () => {
|
|||||||
socket.emit('v1:zone:add', data);
|
socket.emit('v1:zone:add', data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const updatedZonesData = updatedZones.map((zone) => ({
|
||||||
|
type: "Zone" as const,
|
||||||
|
lineData: Zones.find(z => z.zoneUuid === zone.zoneUuid) || zone,
|
||||||
|
newData: zone,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
processedZones.push(...updatedZonesData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (processedFloors.length > 0) {
|
||||||
|
const floorMap = new Map<string, UndoRedo2DDataTypeSchema[]>();
|
||||||
|
|
||||||
|
for (const floor of processedFloors) {
|
||||||
|
if (floor.type !== 'Floor' || !floor.lineData.floorUuid) return;
|
||||||
|
const uuid = floor.lineData.floorUuid;
|
||||||
|
if (!floorMap.has(uuid)) {
|
||||||
|
floorMap.set(uuid, []);
|
||||||
|
}
|
||||||
|
floorMap.get(uuid)!.push(floor);
|
||||||
|
}
|
||||||
|
|
||||||
|
floorMap.forEach((actions, uuid) => {
|
||||||
|
const hasDelete = actions.some(action => !('newData' in action));
|
||||||
|
const hasUpdate = actions.some(action => 'newData' in action);
|
||||||
|
|
||||||
|
if (hasDelete) {
|
||||||
|
deletedPoints.push({
|
||||||
|
type: 'Floor',
|
||||||
|
lineData: actions[0].lineData as Floor,
|
||||||
|
timeStamp: new Date().toISOString()
|
||||||
|
});
|
||||||
|
} else if (!hasDelete && hasUpdate) {
|
||||||
|
const floorData = getFloorById(uuid);
|
||||||
|
if (floorData) {
|
||||||
|
updatedPoints.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) return;
|
||||||
|
const uuid = zone.lineData.zoneUuid;
|
||||||
|
if (!zoneMap.has(uuid)) {
|
||||||
|
zoneMap.set(uuid, []);
|
||||||
|
}
|
||||||
|
zoneMap.get(uuid)!.push(zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
zoneMap.forEach((actions, uuid) => {
|
||||||
|
const hasDelete = actions.some(action => !('newData' in action));
|
||||||
|
const hasUpdate = actions.some(action => 'newData' in action);
|
||||||
|
|
||||||
|
if (hasDelete) {
|
||||||
|
deletedPoints.push({
|
||||||
|
type: 'Zone',
|
||||||
|
lineData: actions[0].lineData as Zone,
|
||||||
|
timeStamp: new Date().toISOString()
|
||||||
|
});
|
||||||
|
} else if (!hasDelete && hasUpdate) {
|
||||||
|
const zoneData = getZoneById(uuid);
|
||||||
|
if (zoneData) {
|
||||||
|
updatedPoints.push({
|
||||||
|
type: 'Zone',
|
||||||
|
lineData: actions[0].lineData as Zone,
|
||||||
|
newData: zoneData as Zone,
|
||||||
|
timeStamp: new Date().toISOString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deletedPoints.length > 0 && updatedPoints.length > 0) {
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Lines-Delete',
|
||||||
|
points: deletedPoints
|
||||||
|
},
|
||||||
|
{
|
||||||
|
actionType: 'Lines-Update',
|
||||||
|
points: updatedPoints
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
} else if (deletedPoints.length > 0 && updatedPoints.length === 0) {
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Lines-Delete',
|
||||||
|
points: deletedPoints
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
} else if (updatedPoints.length > 0 && deletedPoints.length === 0) {
|
||||||
|
push2D({
|
||||||
|
type: 'Draw',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: 'Lines-Update',
|
||||||
|
points: updatedPoints
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
echo.success("Selected points removed!");
|
echo.success("Selected points removed!");
|
||||||
clearSelection();
|
clearSelection();
|
||||||
@@ -380,6 +548,7 @@ const SelectionControls2D: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<MoveControls2D movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} />
|
<MoveControls2D movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} />
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ function useRedoHandler() {
|
|||||||
// SOCKET
|
// SOCKET
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
aisleData,
|
...aisleData,
|
||||||
projectId,
|
projectId,
|
||||||
versionId: selectedVersion?.versionId || '',
|
versionId: selectedVersion?.versionId || '',
|
||||||
userId,
|
userId,
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ function useUndoHandler() {
|
|||||||
// SOCKET
|
// SOCKET
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
aisleData,
|
...aisleData,
|
||||||
projectId,
|
projectId,
|
||||||
versionId: selectedVersion?.versionId || '',
|
versionId: selectedVersion?.versionId || '',
|
||||||
userId,
|
userId,
|
||||||
|
|||||||
Reference in New Issue
Block a user