added usePointEventHandler
This commit is contained in:
@@ -610,7 +610,7 @@ function Line({ points }: Readonly<LineProps>) {
|
|||||||
onPointerOut={() => {
|
onPointerOut={() => {
|
||||||
if (hoveredLine && isHovered) {
|
if (hoveredLine && isHovered) {
|
||||||
setHoveredLine(null);
|
setHoveredLine(null);
|
||||||
if (!hoveredPoint) {
|
if (!hoveredPoint && toolMode === "move") {
|
||||||
handleCanvasCursors("default");
|
handleCanvasCursors("default");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,672 @@
|
|||||||
|
import * as THREE from "three";
|
||||||
|
import { useState, useEffect, useMemo, useCallback } from "react";
|
||||||
|
import { useSocketStore, useToolMode } from "../../../../store/builder/store";
|
||||||
|
import { ThreeEvent, useThree } from "@react-three/fiber";
|
||||||
|
import { useBuilderStore } from "../../../../store/builder/useBuilderStore";
|
||||||
|
import { useSelectedPoints } from "../../../../store/simulation/useSimulationStore";
|
||||||
|
import { usePointSnapping } from "../helpers/usePointSnapping";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { useSceneContext } from "../../../scene/sceneContext";
|
||||||
|
|
||||||
|
import { upsertAisleApi } from "../../../../services/factoryBuilder/aisle/upsertAisleApi";
|
||||||
|
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 { deleteFloorApi } from "../../../../services/factoryBuilder/floor/deleteFloorApi";
|
||||||
|
import { upsertZoneApi } from "../../../../services/factoryBuilder/zone/upsertZoneApi";
|
||||||
|
import { deleteZoneApi } from "../../../../services/factoryBuilder/zone/deleteZoneApi";
|
||||||
|
import { upsertWallAssetApi } from "../../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi";
|
||||||
|
import { deleteWallAssetApi } from "../../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi";
|
||||||
|
|
||||||
|
import { getUserData } from "../../../../functions/getUserData";
|
||||||
|
import { handleCanvasCursors } from "../../../../utils/mouseUtils/handleCanvasCursors";
|
||||||
|
import { calculateAssetTransformationOnWall } from "../../wallAsset/Instances/Instance/functions/calculateAssetTransformationOnWall";
|
||||||
|
|
||||||
|
export function usePointEventHandler({ point }: { point: Point }) {
|
||||||
|
const { raycaster, camera, pointer } = useThree();
|
||||||
|
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
||||||
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
const [isDeleteHovered, setIsDeleteHovered] = useState(false);
|
||||||
|
const [isSelected, setIsSelected] = useState(false);
|
||||||
|
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
||||||
|
const { socket } = useSocketStore();
|
||||||
|
const { toolMode } = useToolMode();
|
||||||
|
const { aisleStore, wallStore, floorStore, zoneStore, undoRedo2DStore, wallAssetStore, versionStore } = useSceneContext();
|
||||||
|
const { push2D } = undoRedo2DStore();
|
||||||
|
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
||||||
|
const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore();
|
||||||
|
const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore();
|
||||||
|
const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore();
|
||||||
|
const { getWallAssetsByWall, updateWallAsset, removeWallAsset } = wallAssetStore();
|
||||||
|
const { selectedVersion } = versionStore();
|
||||||
|
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({
|
||||||
|
uuid: point.pointUuid,
|
||||||
|
pointType: point.pointType,
|
||||||
|
position: point.position,
|
||||||
|
});
|
||||||
|
const { hoveredPoint, hoveredLine, setHoveredPoint } = useBuilderStore();
|
||||||
|
const { selectedPoints } = useSelectedPoints();
|
||||||
|
const { userId, organization } = getUserData();
|
||||||
|
const { projectId } = useParams();
|
||||||
|
|
||||||
|
const [initialStates, setInitialStates] = useState<{
|
||||||
|
aisles?: Aisle[];
|
||||||
|
walls?: Wall[];
|
||||||
|
floors?: Floor[];
|
||||||
|
zones?: Zone[];
|
||||||
|
}>({});
|
||||||
|
|
||||||
|
const handleDrag = useCallback(() => {
|
||||||
|
if (toolMode === "move" && isHovered && dragOffset) {
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (hit) {
|
||||||
|
handleCanvasCursors("grabbing");
|
||||||
|
const positionWithOffset = new THREE.Vector3().addVectors(hit, dragOffset);
|
||||||
|
const newPosition: [number, number, number] = [positionWithOffset.x, positionWithOffset.y, positionWithOffset.z];
|
||||||
|
|
||||||
|
if (point.pointType === "Aisle") {
|
||||||
|
const aisleSnapped = snapAisleAngle(newPosition);
|
||||||
|
const finalSnapped = snapAislePoint(aisleSnapped.position);
|
||||||
|
setAislePosition(point.pointUuid, finalSnapped.position);
|
||||||
|
} else if (point.pointType === "Wall") {
|
||||||
|
const wallSnapped = snapWallAngle(newPosition);
|
||||||
|
const finalSnapped = snapWallPoint(wallSnapped.position);
|
||||||
|
setWallPosition(point.pointUuid, finalSnapped.position);
|
||||||
|
} else if (point.pointType === "Floor") {
|
||||||
|
const floorSnapped = snapFloorAngle(newPosition);
|
||||||
|
const finalSnapped = snapFloorPoint(floorSnapped.position);
|
||||||
|
setFloorPosition(point.pointUuid, finalSnapped.position);
|
||||||
|
} else if (point.pointType === "Zone") {
|
||||||
|
const zoneSnapped = snapZoneAngle(newPosition);
|
||||||
|
const finalSnapped = snapZonePoint(zoneSnapped.position);
|
||||||
|
setZonePosition(point.pointUuid, finalSnapped.position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [toolMode, isHovered, dragOffset, camera, raycaster, plane, point]);
|
||||||
|
|
||||||
|
const handleDragStart = useCallback(() => {
|
||||||
|
raycaster.setFromCamera(pointer, camera);
|
||||||
|
const intersectionPoint = new THREE.Vector3();
|
||||||
|
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
||||||
|
|
||||||
|
if (hit) {
|
||||||
|
const currentPosition = new THREE.Vector3(...point.position);
|
||||||
|
const offset = new THREE.Vector3().subVectors(currentPosition, hit);
|
||||||
|
setDragOffset(offset);
|
||||||
|
|
||||||
|
if (point.pointType === "Aisle") {
|
||||||
|
const aisles = getAislesByPointId(point.pointUuid);
|
||||||
|
setInitialStates({ aisles });
|
||||||
|
} else if (point.pointType === "Wall") {
|
||||||
|
const walls = getWallsByPointId(point.pointUuid);
|
||||||
|
setInitialStates({ walls });
|
||||||
|
} else if (point.pointType === "Floor") {
|
||||||
|
const floors = getFloorsByPointId(point.pointUuid);
|
||||||
|
setInitialStates({ floors });
|
||||||
|
} else if (point.pointType === "Zone") {
|
||||||
|
const zones = getZonesByPointId(point.pointUuid);
|
||||||
|
setInitialStates({ zones });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [raycaster, camera, plane, point]);
|
||||||
|
|
||||||
|
const handleDragEnd = useCallback(() => {
|
||||||
|
handleCanvasCursors("default");
|
||||||
|
setDragOffset(null);
|
||||||
|
if (toolMode !== "move") return;
|
||||||
|
|
||||||
|
if (point.pointType === "Aisle") {
|
||||||
|
const updatedAisles = getAislesByPointId(point.pointUuid);
|
||||||
|
if (updatedAisles.length > 0 && projectId) {
|
||||||
|
updatedAisles.forEach((updatedAisle) => {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || "");
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
socket.emit("v1:model-aisle:add", {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: updatedAisle.aisleUuid,
|
||||||
|
points: updatedAisle.points,
|
||||||
|
type: updatedAisle.type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (initialStates.aisles && initialStates.aisles.length > 0) {
|
||||||
|
const updatedPoints = initialStates.aisles.map((aisle) => ({
|
||||||
|
type: "Aisle" as const,
|
||||||
|
lineData: aisle,
|
||||||
|
newData: updatedAisles.find((a) => a.aisleUuid === aisle.aisleUuid),
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: "Draw",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "Lines-Update",
|
||||||
|
points: updatedPoints,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (point.pointType === "Wall") {
|
||||||
|
const updatedWalls = getWallsByPointId(point.pointUuid);
|
||||||
|
if (updatedWalls && updatedWalls.length > 0 && projectId) {
|
||||||
|
updatedWalls.forEach((updatedWall) => {
|
||||||
|
const initialWall = initialStates.walls?.find((w) => w.wallUuid === updatedWall.wallUuid);
|
||||||
|
|
||||||
|
if (initialWall) {
|
||||||
|
const assetsOnWall = getWallAssetsByWall(updatedWall.wallUuid);
|
||||||
|
|
||||||
|
assetsOnWall.forEach((asset) => {
|
||||||
|
const { position, rotation } = calculateAssetTransformationOnWall(asset, initialWall, updatedWall);
|
||||||
|
|
||||||
|
const updatedWallAsset = updateWallAsset(asset.modelUuid, {
|
||||||
|
position: [position[0], asset.position[1], position[2]],
|
||||||
|
rotation: rotation,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (projectId && updatedWallAsset) {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
upsertWallAssetApi(projectId, selectedVersion?.versionId || "", updatedWallAsset);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallAssetData: updatedWallAsset,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:wall-asset:add", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
upsertWallApi(projectId, selectedVersion?.versionId || "", updatedWall);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallData: updatedWall,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:model-Wall:add", data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialStates.walls && initialStates.walls.length > 0) {
|
||||||
|
const updatedPoints = initialStates.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 (point.pointType === "Floor") {
|
||||||
|
const updatedFloors = getFloorsByPointId(point.pointUuid);
|
||||||
|
if (updatedFloors && updatedFloors.length > 0 && projectId) {
|
||||||
|
updatedFloors.forEach((updatedFloor) => {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
upsertFloorApi(projectId, selectedVersion?.versionId || "", updatedFloor);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: updatedFloor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:model-Floor:add", data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialStates.floors && initialStates.floors.length > 0) {
|
||||||
|
const updatedPoints = initialStates.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 (point.pointType === "Zone") {
|
||||||
|
const updatedZones = getZonesByPointId(point.pointUuid);
|
||||||
|
if (updatedZones && updatedZones.length > 0 && projectId) {
|
||||||
|
updatedZones.forEach((updatedZone) => {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: updatedZone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:zone:add", data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialStates.zones && initialStates.zones.length > 0) {
|
||||||
|
const updatedPoints = initialStates.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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInitialStates({});
|
||||||
|
}, [toolMode, projectId, socket, selectedVersion, userId, organization, initialStates, point]);
|
||||||
|
|
||||||
|
const handlePointClick = useCallback(
|
||||||
|
(e: ThreeEvent<MouseEvent>) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (toolMode === "2D-Delete") {
|
||||||
|
if (point.pointType === "Aisle") {
|
||||||
|
const removedAisles = removeAislePoint(point.pointUuid);
|
||||||
|
setHoveredPoint(null);
|
||||||
|
if (removedAisles.length > 0) {
|
||||||
|
removedAisles.forEach((aisle) => {
|
||||||
|
if (projectId) {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || "");
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
aisleUuid: aisle.aisleUuid,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:model-aisle:delete", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const removedAislesData = removedAisles.map((aisle) => ({
|
||||||
|
type: "Aisle" as const,
|
||||||
|
lineData: aisle,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: "Draw",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "Lines-Delete",
|
||||||
|
points: removedAislesData,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (point.pointType === "Wall") {
|
||||||
|
const removedWalls = removeWallPoint(point.pointUuid);
|
||||||
|
if (removedWalls.length > 0) {
|
||||||
|
setHoveredPoint(null);
|
||||||
|
removedWalls.forEach((wall) => {
|
||||||
|
const assetsOnWall = getWallAssetsByWall(wall.wallUuid);
|
||||||
|
|
||||||
|
assetsOnWall.forEach((asset) => {
|
||||||
|
if (projectId && asset) {
|
||||||
|
removeWallAsset(asset.modelUuid);
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
deleteWallAssetApi(projectId, selectedVersion?.versionId || "", asset.modelUuid, asset.wallUuid);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
modelUuid: asset.modelUuid,
|
||||||
|
wallUuid: asset.wallUuid,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:wall-asset:delete", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (projectId) {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
deleteWallApi(projectId, selectedVersion?.versionId || "", wall.wallUuid);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
wallUuid: wall.wallUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:model-Wall:delete", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const removedWallsData = removedWalls.map((wall) => ({
|
||||||
|
type: "Wall" as const,
|
||||||
|
lineData: wall,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: "Draw",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "Lines-Delete",
|
||||||
|
points: removedWallsData,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (point.pointType === "Floor") {
|
||||||
|
const Floors = getFloorsByPointId(point.pointUuid);
|
||||||
|
const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid);
|
||||||
|
setHoveredPoint(null);
|
||||||
|
if (removedFloors.length > 0) {
|
||||||
|
removedFloors.forEach((floor) => {
|
||||||
|
if (projectId) {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
deleteFloorApi(projectId, selectedVersion?.versionId || "", floor.floorUuid);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorUuid: floor.floorUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:model-Floor:delete", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const removedFloorsData = removedFloors.map((floor) => ({
|
||||||
|
type: "Floor" as const,
|
||||||
|
lineData: floor,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: "Draw",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "Lines-Delete",
|
||||||
|
points: removedFloorsData,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (updatedFloors.length > 0) {
|
||||||
|
updatedFloors.forEach((floor) => {
|
||||||
|
if (projectId) {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
upsertFloorApi(projectId, selectedVersion?.versionId || "", floor);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
floorData: floor,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
};
|
||||||
|
|
||||||
|
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(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: "Draw",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "Lines-Update",
|
||||||
|
points: updatedFloorsData,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (point.pointType === "Zone") {
|
||||||
|
const Zones = getZonesByPointId(point.pointUuid);
|
||||||
|
const { removedZones, updatedZones } = removeZonePoint(point.pointUuid);
|
||||||
|
setHoveredPoint(null);
|
||||||
|
if (removedZones.length > 0) {
|
||||||
|
removedZones.forEach((zone) => {
|
||||||
|
if (projectId) {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
deleteZoneApi(projectId, selectedVersion?.versionId || "", zone.zoneUuid);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneUuid: zone.zoneUuid,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.emit("v1:zone:delete", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const removedZonesData = removedZones.map((zone) => ({
|
||||||
|
type: "Zone" as const,
|
||||||
|
lineData: zone,
|
||||||
|
timeStamp: new Date().toISOString(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: "Draw",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "Lines-Delete",
|
||||||
|
points: removedZonesData,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (updatedZones.length > 0) {
|
||||||
|
updatedZones.forEach((zone) => {
|
||||||
|
if (projectId) {
|
||||||
|
if (!socket?.connected) {
|
||||||
|
// API
|
||||||
|
|
||||||
|
upsertZoneApi(projectId, selectedVersion?.versionId || "", zone);
|
||||||
|
} else {
|
||||||
|
// SOCKET
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
zoneData: zone,
|
||||||
|
projectId: projectId,
|
||||||
|
versionId: selectedVersion?.versionId || "",
|
||||||
|
userId: userId,
|
||||||
|
organization: organization,
|
||||||
|
};
|
||||||
|
|
||||||
|
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(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
push2D({
|
||||||
|
type: "Draw",
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
actionType: "Lines-Update",
|
||||||
|
points: updatedZonesData,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleCanvasCursors("default");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[toolMode, projectId, socket, selectedVersion, userId, organization, point]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handlePointerOver = useCallback(
|
||||||
|
(e: ThreeEvent<MouseEvent>) => {
|
||||||
|
if (!hoveredPoint && selectedPoints.length === 0 && e.buttons === 0 && !e.ctrlKey) {
|
||||||
|
setHoveredPoint(point);
|
||||||
|
if (toolMode === "move") {
|
||||||
|
setIsHovered(true);
|
||||||
|
handleCanvasCursors("grab");
|
||||||
|
} else if (toolMode === "2D-Delete") {
|
||||||
|
setIsDeleteHovered(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[hoveredPoint, selectedPoints, toolMode, point, setHoveredPoint]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handlePointerOut = useCallback(() => {
|
||||||
|
if (hoveredPoint) {
|
||||||
|
setHoveredPoint(null);
|
||||||
|
if (!hoveredLine && toolMode === "move") {
|
||||||
|
handleCanvasCursors("default");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setIsHovered(false);
|
||||||
|
setIsDeleteHovered(false);
|
||||||
|
}, [hoveredPoint, hoveredLine, setHoveredPoint]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (hoveredPoint && hoveredPoint.pointUuid !== point.pointUuid) {
|
||||||
|
setIsHovered(false);
|
||||||
|
}
|
||||||
|
}, [hoveredPoint]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedPoints.length > 0 && selectedPoints.some((selectedPoint) => selectedPoint.userData.pointUuid && selectedPoint.userData.pointUuid === point.pointUuid)) {
|
||||||
|
setIsSelected(true);
|
||||||
|
} else {
|
||||||
|
setIsSelected(false);
|
||||||
|
}
|
||||||
|
}, [selectedPoints]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
isHovered,
|
||||||
|
isDeleteHovered,
|
||||||
|
isSelected,
|
||||||
|
handleDrag,
|
||||||
|
handleDragStart,
|
||||||
|
handleDragEnd,
|
||||||
|
handlePointClick,
|
||||||
|
handlePointerOver,
|
||||||
|
handlePointerOut,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,72 +1,14 @@
|
|||||||
import * as THREE from "three";
|
|
||||||
import * as Constants from "../../../types/world/worldConstants";
|
|
||||||
import { useState, useEffect, useMemo } from "react";
|
|
||||||
import { useSocketStore, useToolMode } from "../../../store/builder/store";
|
|
||||||
import { DragControls } from "@react-three/drei";
|
import { DragControls } from "@react-three/drei";
|
||||||
import { useThree } from "@react-three/fiber";
|
import * as Constants from "../../../types/world/worldConstants";
|
||||||
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
|
|
||||||
import { useSelectedPoints } from "../../../store/simulation/useSimulationStore";
|
|
||||||
import { usePointSnapping } from "./helpers/usePointSnapping";
|
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
import { useSceneContext } from "../../scene/sceneContext";
|
|
||||||
|
|
||||||
import BoxMaterial from "../wrappers/materials/boxMaterial";
|
import BoxMaterial from "../wrappers/materials/boxMaterial";
|
||||||
|
|
||||||
import { upsertAisleApi } from "../../../services/factoryBuilder/aisle/upsertAisleApi";
|
import { usePointEventHandler } from "./eventHandler/usePointEventHandler";
|
||||||
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 { deleteFloorApi } from "../../../services/factoryBuilder/floor/deleteFloorApi";
|
|
||||||
import { upsertZoneApi } from "../../../services/factoryBuilder/zone/upsertZoneApi";
|
|
||||||
import { deleteZoneApi } from "../../../services/factoryBuilder/zone/deleteZoneApi";
|
|
||||||
import { upsertWallAssetApi } from "../../../services/factoryBuilder/asset/wallAsset/upsertWallAssetApi";
|
|
||||||
import { deleteWallAssetApi } from "../../../services/factoryBuilder/asset/wallAsset/deleteWallAssetApi";
|
|
||||||
|
|
||||||
import { getUserData } from "../../../functions/getUserData";
|
|
||||||
import { handleCanvasCursors } from "../../../utils/mouseUtils/handleCanvasCursors";
|
|
||||||
import { calculateAssetTransformationOnWall } from "../wallAsset/Instances/Instance/functions/calculateAssetTransformationOnWall";
|
|
||||||
|
|
||||||
function Point({ point }: { readonly point: Point }) {
|
function Point({ point }: { readonly point: Point }) {
|
||||||
const { raycaster, camera, pointer } = useThree();
|
|
||||||
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
|
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
|
||||||
const [isDeleteHovered, setIsDeleteHovered] = useState(false);
|
|
||||||
const [isSelected, setIsSelected] = useState(false);
|
|
||||||
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
|
|
||||||
const { socket } = useSocketStore();
|
|
||||||
const { toolMode } = useToolMode();
|
|
||||||
const { aisleStore, wallStore, floorStore, zoneStore, undoRedo2DStore, wallAssetStore, versionStore } = useSceneContext();
|
|
||||||
const { push2D } = undoRedo2DStore();
|
|
||||||
const { setPosition: setAislePosition, removePoint: removeAislePoint, getAislesByPointId } = aisleStore();
|
|
||||||
const { setPosition: setWallPosition, removePoint: removeWallPoint, getWallsByPointId } = wallStore();
|
|
||||||
const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore();
|
|
||||||
const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore();
|
|
||||||
const { getWallAssetsByWall, updateWallAsset, removeWallAsset } = wallAssetStore();
|
|
||||||
const { selectedVersion } = versionStore();
|
|
||||||
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({
|
|
||||||
uuid: point.pointUuid,
|
|
||||||
pointType: point.pointType,
|
|
||||||
position: point.position,
|
|
||||||
});
|
|
||||||
const { hoveredPoint, hoveredLine, setHoveredPoint } = useBuilderStore();
|
|
||||||
const { selectedPoints } = useSelectedPoints();
|
|
||||||
const { userId, organization } = getUserData();
|
|
||||||
const { projectId } = useParams();
|
|
||||||
const boxScale: [number, number, number] = Constants.pointConfig.boxScale;
|
const boxScale: [number, number, number] = Constants.pointConfig.boxScale;
|
||||||
const colors = getColor(point);
|
const colors = getColor(point);
|
||||||
|
|
||||||
const [initialStates, setInitialStates] = useState<{
|
|
||||||
aisles?: Aisle[];
|
|
||||||
walls?: Wall[];
|
|
||||||
floors?: Floor[];
|
|
||||||
zones?: Zone[];
|
|
||||||
}>({});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleCanvasCursors("default");
|
|
||||||
}, [toolMode]);
|
|
||||||
|
|
||||||
function getColor(point: Point) {
|
function getColor(point: Point) {
|
||||||
if (point.pointType === "Aisle") {
|
if (point.pointType === "Aisle") {
|
||||||
return {
|
return {
|
||||||
@@ -101,612 +43,20 @@ function Point({ point }: { readonly point: Point }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDrag = (point: Point) => {
|
const { isHovered, isSelected, isDeleteHovered, handleDrag, handleDragStart, handleDragEnd, handlePointClick, handlePointerOver, handlePointerOut } = usePointEventHandler({ point });
|
||||||
if (toolMode === "move" && isHovered && dragOffset) {
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
|
|
||||||
if (hit) {
|
|
||||||
handleCanvasCursors("grabbing");
|
|
||||||
const positionWithOffset = new THREE.Vector3().addVectors(hit, dragOffset);
|
|
||||||
const newPosition: [number, number, number] = [positionWithOffset.x, positionWithOffset.y, positionWithOffset.z];
|
|
||||||
|
|
||||||
if (point.pointType === "Aisle") {
|
|
||||||
const aisleSnapped = snapAisleAngle(newPosition);
|
|
||||||
const finalSnapped = snapAislePoint(aisleSnapped.position);
|
|
||||||
setAislePosition(point.pointUuid, finalSnapped.position);
|
|
||||||
} else if (point.pointType === "Wall") {
|
|
||||||
const wallSnapped = snapWallAngle(newPosition);
|
|
||||||
const finalSnapped = snapWallPoint(wallSnapped.position);
|
|
||||||
setWallPosition(point.pointUuid, finalSnapped.position);
|
|
||||||
} else if (point.pointType === "Floor") {
|
|
||||||
const floorSnapped = snapFloorAngle(newPosition);
|
|
||||||
const finalSnapped = snapFloorPoint(floorSnapped.position);
|
|
||||||
setFloorPosition(point.pointUuid, finalSnapped.position);
|
|
||||||
} else if (point.pointType === "Zone") {
|
|
||||||
const zoneSnapped = snapZoneAngle(newPosition);
|
|
||||||
const finalSnapped = snapZonePoint(zoneSnapped.position);
|
|
||||||
setZonePosition(point.pointUuid, finalSnapped.position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDragStart = (point: Point) => {
|
|
||||||
raycaster.setFromCamera(pointer, camera);
|
|
||||||
const intersectionPoint = new THREE.Vector3();
|
|
||||||
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
|
|
||||||
|
|
||||||
if (hit) {
|
|
||||||
const currentPosition = new THREE.Vector3(...point.position);
|
|
||||||
const offset = new THREE.Vector3().subVectors(currentPosition, hit);
|
|
||||||
setDragOffset(offset);
|
|
||||||
|
|
||||||
if (point.pointType === "Aisle") {
|
|
||||||
const aisles = getAislesByPointId(point.pointUuid);
|
|
||||||
setInitialStates({ aisles });
|
|
||||||
} else if (point.pointType === "Wall") {
|
|
||||||
const walls = getWallsByPointId(point.pointUuid);
|
|
||||||
setInitialStates({ walls });
|
|
||||||
} else if (point.pointType === "Floor") {
|
|
||||||
const floors = getFloorsByPointId(point.pointUuid);
|
|
||||||
setInitialStates({ floors });
|
|
||||||
} else if (point.pointType === "Zone") {
|
|
||||||
const zones = getZonesByPointId(point.pointUuid);
|
|
||||||
setInitialStates({ zones });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDragEnd = (point: Point) => {
|
|
||||||
handleCanvasCursors("default");
|
|
||||||
setDragOffset(null);
|
|
||||||
if (toolMode !== "move") return;
|
|
||||||
|
|
||||||
if (point.pointType === "Aisle") {
|
|
||||||
const updatedAisles = getAislesByPointId(point.pointUuid);
|
|
||||||
if (updatedAisles.length > 0 && projectId) {
|
|
||||||
updatedAisles.forEach((updatedAisle) => {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || "");
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
socket.emit("v1:model-aisle:add", {
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
aisleUuid: updatedAisle.aisleUuid,
|
|
||||||
points: updatedAisle.points,
|
|
||||||
type: updatedAisle.type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (initialStates.aisles && initialStates.aisles.length > 0) {
|
|
||||||
const updatedPoints = initialStates.aisles.map((aisle) => ({
|
|
||||||
type: "Aisle" as const,
|
|
||||||
lineData: aisle,
|
|
||||||
newData: updatedAisles.find((a) => a.aisleUuid === aisle.aisleUuid),
|
|
||||||
timeStamp: new Date().toISOString(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
push2D({
|
|
||||||
type: "Draw",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "Lines-Update",
|
|
||||||
points: updatedPoints,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (point.pointType === "Wall") {
|
|
||||||
const updatedWalls = getWallsByPointId(point.pointUuid);
|
|
||||||
if (updatedWalls && updatedWalls.length > 0 && projectId) {
|
|
||||||
updatedWalls.forEach((updatedWall) => {
|
|
||||||
const initialWall = initialStates.walls?.find((w) => w.wallUuid === updatedWall.wallUuid);
|
|
||||||
|
|
||||||
if (initialWall) {
|
|
||||||
const assetsOnWall = getWallAssetsByWall(updatedWall.wallUuid);
|
|
||||||
|
|
||||||
assetsOnWall.forEach((asset) => {
|
|
||||||
const { position, rotation } = calculateAssetTransformationOnWall(asset, initialWall, updatedWall);
|
|
||||||
|
|
||||||
const updatedWallAsset = updateWallAsset(asset.modelUuid, {
|
|
||||||
position: [position[0], asset.position[1], position[2]],
|
|
||||||
rotation: rotation,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (projectId && updatedWallAsset) {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
upsertWallAssetApi(projectId, selectedVersion?.versionId || "", updatedWallAsset);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
wallAssetData: updatedWallAsset,
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:wall-asset:add", data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
upsertWallApi(projectId, selectedVersion?.versionId || "", updatedWall);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
wallData: updatedWall,
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:model-Wall:add", data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialStates.walls && initialStates.walls.length > 0) {
|
|
||||||
const updatedPoints = initialStates.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 (point.pointType === "Floor") {
|
|
||||||
const updatedFloors = getFloorsByPointId(point.pointUuid);
|
|
||||||
if (updatedFloors && updatedFloors.length > 0 && projectId) {
|
|
||||||
updatedFloors.forEach((updatedFloor) => {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
upsertFloorApi(projectId, selectedVersion?.versionId || "", updatedFloor);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
floorData: updatedFloor,
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:model-Floor:add", data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialStates.floors && initialStates.floors.length > 0) {
|
|
||||||
const updatedPoints = initialStates.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 (point.pointType === "Zone") {
|
|
||||||
const updatedZones = getZonesByPointId(point.pointUuid);
|
|
||||||
if (updatedZones && updatedZones.length > 0 && projectId) {
|
|
||||||
updatedZones.forEach((updatedZone) => {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
upsertZoneApi(projectId, selectedVersion?.versionId || "", updatedZone);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
zoneData: updatedZone,
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:zone:add", data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialStates.zones && initialStates.zones.length > 0) {
|
|
||||||
const updatedPoints = initialStates.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,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setInitialStates({});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePointClick = (point: Point) => {
|
|
||||||
if (toolMode === "2D-Delete") {
|
|
||||||
if (point.pointType === "Aisle") {
|
|
||||||
const removedAisles = removeAislePoint(point.pointUuid);
|
|
||||||
setHoveredPoint(null);
|
|
||||||
if (removedAisles.length > 0) {
|
|
||||||
removedAisles.forEach((aisle) => {
|
|
||||||
if (projectId) {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || "");
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
aisleUuid: aisle.aisleUuid,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:model-aisle:delete", data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const removedAislesData = removedAisles.map((aisle) => ({
|
|
||||||
type: "Aisle" as const,
|
|
||||||
lineData: aisle,
|
|
||||||
timeStamp: new Date().toISOString(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
push2D({
|
|
||||||
type: "Draw",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "Lines-Delete",
|
|
||||||
points: removedAislesData,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (point.pointType === "Wall") {
|
|
||||||
const removedWalls = removeWallPoint(point.pointUuid);
|
|
||||||
if (removedWalls.length > 0) {
|
|
||||||
setHoveredPoint(null);
|
|
||||||
removedWalls.forEach((wall) => {
|
|
||||||
const assetsOnWall = getWallAssetsByWall(wall.wallUuid);
|
|
||||||
|
|
||||||
assetsOnWall.forEach((asset) => {
|
|
||||||
if (projectId && asset) {
|
|
||||||
removeWallAsset(asset.modelUuid);
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
deleteWallAssetApi(projectId, selectedVersion?.versionId || "", asset.modelUuid, asset.wallUuid);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
modelUuid: asset.modelUuid,
|
|
||||||
wallUuid: asset.wallUuid,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:wall-asset:delete", data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (projectId) {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
deleteWallApi(projectId, selectedVersion?.versionId || "", wall.wallUuid);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
wallUuid: wall.wallUuid,
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:model-Wall:delete", data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const removedWallsData = removedWalls.map((wall) => ({
|
|
||||||
type: "Wall" as const,
|
|
||||||
lineData: wall,
|
|
||||||
timeStamp: new Date().toISOString(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
push2D({
|
|
||||||
type: "Draw",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "Lines-Delete",
|
|
||||||
points: removedWallsData,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (point.pointType === "Floor") {
|
|
||||||
const Floors = getFloorsByPointId(point.pointUuid);
|
|
||||||
const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid);
|
|
||||||
setHoveredPoint(null);
|
|
||||||
if (removedFloors.length > 0) {
|
|
||||||
removedFloors.forEach((floor) => {
|
|
||||||
if (projectId) {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
deleteFloorApi(projectId, selectedVersion?.versionId || "", floor.floorUuid);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
floorUuid: floor.floorUuid,
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:model-Floor:delete", data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const removedFloorsData = removedFloors.map((floor) => ({
|
|
||||||
type: "Floor" as const,
|
|
||||||
lineData: floor,
|
|
||||||
timeStamp: new Date().toISOString(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
push2D({
|
|
||||||
type: "Draw",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "Lines-Delete",
|
|
||||||
points: removedFloorsData,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (updatedFloors.length > 0) {
|
|
||||||
updatedFloors.forEach((floor) => {
|
|
||||||
if (projectId) {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
upsertFloorApi(projectId, selectedVersion?.versionId || "", floor);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
floorData: floor,
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
};
|
|
||||||
|
|
||||||
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(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
push2D({
|
|
||||||
type: "Draw",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "Lines-Update",
|
|
||||||
points: updatedFloorsData,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (point.pointType === "Zone") {
|
|
||||||
const Zones = getZonesByPointId(point.pointUuid);
|
|
||||||
const { removedZones, updatedZones } = removeZonePoint(point.pointUuid);
|
|
||||||
setHoveredPoint(null);
|
|
||||||
if (removedZones.length > 0) {
|
|
||||||
removedZones.forEach((zone) => {
|
|
||||||
if (projectId) {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
deleteZoneApi(projectId, selectedVersion?.versionId || "", zone.zoneUuid);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
zoneUuid: zone.zoneUuid,
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
};
|
|
||||||
|
|
||||||
socket.emit("v1:zone:delete", data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const removedZonesData = removedZones.map((zone) => ({
|
|
||||||
type: "Zone" as const,
|
|
||||||
lineData: zone,
|
|
||||||
timeStamp: new Date().toISOString(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
push2D({
|
|
||||||
type: "Draw",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "Lines-Delete",
|
|
||||||
points: removedZonesData,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (updatedZones.length > 0) {
|
|
||||||
updatedZones.forEach((zone) => {
|
|
||||||
if (projectId) {
|
|
||||||
if (!socket?.connected) {
|
|
||||||
// API
|
|
||||||
|
|
||||||
upsertZoneApi(projectId, selectedVersion?.versionId || "", zone);
|
|
||||||
} else {
|
|
||||||
// SOCKET
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
zoneData: zone,
|
|
||||||
projectId: projectId,
|
|
||||||
versionId: selectedVersion?.versionId || "",
|
|
||||||
userId: userId,
|
|
||||||
organization: organization,
|
|
||||||
};
|
|
||||||
|
|
||||||
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(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
push2D({
|
|
||||||
type: "Draw",
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
actionType: "Lines-Update",
|
|
||||||
points: updatedZonesData,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handleCanvasCursors("default");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (hoveredPoint && hoveredPoint.pointUuid !== point.pointUuid) {
|
|
||||||
setIsHovered(false);
|
|
||||||
}
|
|
||||||
}, [hoveredPoint]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (selectedPoints.length > 0 && selectedPoints.some((selectedPoint) => selectedPoint.userData.pointUuid && selectedPoint.userData.pointUuid === point.pointUuid)) {
|
|
||||||
setIsSelected(true);
|
|
||||||
} else {
|
|
||||||
setIsSelected(false);
|
|
||||||
}
|
|
||||||
}, [selectedPoints]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!isSelected ? (
|
{!isSelected ? (
|
||||||
<DragControls axisLock="y" autoTransform={false} onDragStart={() => handleDragStart(point)} onDrag={() => handleDrag(point)} onDragEnd={() => handleDragEnd(point)}>
|
<DragControls axisLock="y" autoTransform={false} onDragStart={handleDragStart} onDrag={handleDrag} onDragEnd={handleDragEnd}>
|
||||||
<mesh
|
<mesh
|
||||||
key={point.pointUuid}
|
key={point.pointUuid}
|
||||||
uuid={point.pointUuid}
|
uuid={point.pointUuid}
|
||||||
name={`${point.pointType}-Point`}
|
name={`${point.pointType}-Point`}
|
||||||
position={[...point.position]}
|
position={[...point.position]}
|
||||||
onClick={(e) => {
|
onClick={handlePointClick}
|
||||||
e.stopPropagation();
|
onPointerOver={handlePointerOver}
|
||||||
handlePointClick(point);
|
onPointerOut={handlePointerOut}
|
||||||
}}
|
|
||||||
onPointerOver={(e) => {
|
|
||||||
if (!hoveredPoint && selectedPoints.length === 0 && e.buttons === 0 && !e.ctrlKey) {
|
|
||||||
setHoveredPoint(point);
|
|
||||||
if (toolMode === "move") {
|
|
||||||
setIsHovered(true);
|
|
||||||
handleCanvasCursors("grab");
|
|
||||||
} else if (toolMode === "2D-Delete") {
|
|
||||||
setIsDeleteHovered(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onPointerOut={() => {
|
|
||||||
if (hoveredPoint) {
|
|
||||||
handleCanvasCursors("default");
|
|
||||||
setHoveredPoint(null);
|
|
||||||
if (!hoveredLine) {
|
|
||||||
handleCanvasCursors("default");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setIsHovered(false);
|
|
||||||
setIsDeleteHovered(false);
|
|
||||||
}}
|
|
||||||
userData={point}
|
userData={point}
|
||||||
>
|
>
|
||||||
<boxGeometry args={boxScale} />
|
<boxGeometry args={boxScale} />
|
||||||
|
|||||||
Reference in New Issue
Block a user