refactor: update VehicleMechanics to use LabledDropdown for start and end point selection; clean up unused MQTT code and improve zone data fetching logic

This commit is contained in:
Jerald-Golden-B 2025-03-29 18:14:29 +05:30
parent d4d4b145c7
commit 5564eecf76
8 changed files with 279 additions and 109 deletions

View File

@ -1,9 +1,9 @@
import React, { useRef, useMemo } from "react";
import { InfoIcon } from "../../../icons/ExportCommonIcons";
import InputWithDropDown from "../../../ui/inputs/InputWithDropDown";
import EyeDropInput from "../../../ui/inputs/EyeDropInput";
import { useSelectedActionSphere, useSimulationPaths } from "../../../../store/store";
import * as Types from '../../../../types/world/worldTypes';
import LabledDropdown from "../../../ui/inputs/LabledDropdown";
const VehicleMechanics: React.FC = () => {
const { selectedActionSphere } = useSelectedActionSphere();
@ -11,17 +11,31 @@ const VehicleMechanics: React.FC = () => {
const propertiesContainerRef = useRef<HTMLDivElement>(null);
const selectedPoint = useMemo(() => {
if (!selectedActionSphere?.point?.uuid) return null;
const { selectedPoint, connectedPointUuids } = useMemo(() => {
if (!selectedActionSphere?.point?.uuid) return { selectedPoint: null, connectedPointUuids: [] };
const vehiclePaths = simulationPaths.filter(
(path): path is Types.VehicleEventsSchema => path.type === "Vehicle"
);
return vehiclePaths.find(
const point = vehiclePaths.find(
(path) => path.point.uuid === selectedActionSphere.point.uuid
)?.point;
}, [selectedActionSphere, simulationPaths, selectedActionSphere?.point?.uuid]);
if (!point) return { selectedPoint: null, connectedPointUuids: [] };
const connectedUuids: string[] = [];
if (point.connections?.targets) {
point.connections.targets.forEach(target => {
connectedUuids.push(target.pointUUID);
});
}
return {
selectedPoint: point,
connectedPointUuids: connectedUuids
};
}, [selectedActionSphere, simulationPaths]);
const handleActionUpdate = React.useCallback((updatedAction: Partial<Types.VehicleEventsSchema['point']['actions']>) => {
if (!selectedActionSphere?.point?.uuid) return;
@ -45,12 +59,12 @@ const VehicleMechanics: React.FC = () => {
setSimulationPaths(updatedPaths);
}, [selectedActionSphere?.point?.uuid, simulationPaths, setSimulationPaths]);
const handleStartPointChange = React.useCallback((position: string) => {
handleActionUpdate({ start: position });
const handleStartPointChange = React.useCallback((uuid: string) => {
handleActionUpdate({ start: uuid });
}, [handleActionUpdate]);
const handleEndPointChange = React.useCallback((position: string) => {
handleActionUpdate({ end: position });
const handleEndPointChange = React.useCallback((uuid: string) => {
handleActionUpdate({ end: uuid });
}, [handleActionUpdate]);
const handleHitCountChange = React.useCallback((hitCount: number) => {
@ -92,18 +106,20 @@ const VehicleMechanics: React.FC = () => {
{selectedPoint && (
<>
<EyeDropInput
<LabledDropdown
key={`start-${selectedPoint.uuid}`}
label="Start Point"
value={selectedPoint.actions.start}
onChange={handleStartPointChange}
defaultOption={selectedPoint.actions.start || "Select start point"}
options={connectedPointUuids}
onSelect={handleStartPointChange}
/>
<EyeDropInput
<LabledDropdown
key={`end-${selectedPoint.uuid}`}
label="End Point"
value={selectedPoint.actions.end}
onChange={handleEndPointChange}
defaultOption={selectedPoint.actions.end || "Select end point"}
options={connectedPointUuids}
onSelect={handleEndPointChange}
/>
<InputWithDropDown
@ -128,7 +144,6 @@ const VehicleMechanics: React.FC = () => {
/>
</>
)}
</div>
<div className="footer">

View File

@ -76,7 +76,7 @@ const RealTimeVisulization: React.FC = () => {
}
GetZoneData();
}, []); // Removed `zones` from dependencies
}, [activeModule]); // Removed `zones` from dependencies
useEffect(() => {
@ -97,7 +97,7 @@ const RealTimeVisulization: React.FC = () => {
};
});
}, [selectedZone]);
useEffect(() => {
}, [floatingWidgets])

View File

@ -1,5 +1,6 @@
import React from "react";
import { EyeDroperIcon } from "../../icons/ExportCommonIcons";
import RegularDropDown from "./RegularDropDown";
interface EyeDropInputProps {
label: string;
@ -23,7 +24,12 @@ const EyeDropInput: React.FC<EyeDropInputProps> = ({
<div className="eye-dropper-input-container">
<div className="label">{label}</div>
<div className="input-container">
<input disabled type="text" />
{/* <input disabled type="text" /> */}
<RegularDropDown
header="select object"
options={[]}
onSelect={() => { }}
/>
<div className="eye-picker-button" onClick={handleEyeDropClick}>
<EyeDroperIcon isActive={false} />
</div>

View File

@ -1,24 +1,17 @@
import PolygonGenerator from "./polygonGenerator";
import { useThree } from "@react-three/fiber";
import { useEffect, useRef, useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import * as THREE from "three";
import * as Types from "../../../types/world/worldTypes";
import PathNavigator from "./pathNavigator";
import NavMeshDetails from "./navMeshDetails";
const Agv = ({
lines,
plane,
}: {
lines: Types.RefLines;
plane: Types.RefMesh;
}) => {
let pathPoints = [
const Agv = ({ lines, plane }: { lines: Types.RefLines; plane: Types.RefMesh; }) => {
const pathPoints = useMemo(() => [
[
{ x: 8.477161935339709, y: 0, z: 17.41343083550102 },
{ x: 9.175416491482693, y: 0, z: -12.361001232663693 },
],
,
// [
// { x: 13.508213355232144, y: 0, z: -15.456970649652018 },
// { x: -30.464866520869617, y: 0, z: 9.779806557688929 },
@ -27,7 +20,8 @@ const Agv = ({
{ x: 16.792040856420844, y: 0, z: 15.86281907549489 },
{ x: -42.77173264503395, y: 0, z: -15.821322764400804 },
],
];
], []);
let groupRef = useRef() as Types.RefGroup;
const [navMesh, setNavMesh] = useState();

View File

@ -22,7 +22,8 @@ function hideRoof(
if (roofChild.material) {
const materials = Array.isArray(roofChild.material) ? roofChild.material : [roofChild.material];
materials.forEach(material => {
material.visible = v.dot(u) < 0.25;
// material.visible = v.dot(u) < 0.25;
material.visible = true;
});
}
}

View File

@ -86,6 +86,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
};
}
}
// In the updatePathConnections function, modify the Vehicle handling section:
else if (path.type === 'Vehicle') {
// Handle outgoing connections from Vehicle
if (path.modeluuid === fromPathUUID && path.point.uuid === fromPointUUID) {
@ -95,6 +96,27 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
};
const existingTargets = path.point.connections.targets || [];
// Check if we're trying to add a connection to a Conveyor
const toPath = simulationPaths.find(p => p.modeluuid === toPathUUID);
const isConnectingToConveyor = toPath?.type === 'Conveyor';
// Count existing connections
if (existingTargets.length >= 2) {
console.log("Vehicle can have maximum 2 connections");
return path;
}
// Check if we already have a Conveyor connection and trying to add another
const hasConveyorConnection = existingTargets.some(target => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
return targetPath?.type === 'Conveyor';
});
if (hasConveyorConnection && isConnectingToConveyor) {
console.log("Vehicle can only have one connection to a Conveyor");
return path;
}
if (!existingTargets.some(target =>
target.pathUUID === newTarget.pathUUID &&
target.pointUUID === newTarget.pointUUID
@ -119,6 +141,27 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
};
const existingTargets = path.point.connections.targets || [];
// Check if we're receiving a connection from a Conveyor
const fromPath = simulationPaths.find(p => p.modeluuid === fromPathUUID);
const isConnectingFromConveyor = fromPath?.type === 'Conveyor';
// Count existing connections
if (existingTargets.length >= 2) {
console.log("Vehicle can have maximum 2 connections");
return path;
}
// Check if we already have a Conveyor connection and trying to add another
const hasConveyorConnection = existingTargets.some(target => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
return targetPath?.type === 'Conveyor';
});
if (hasConveyorConnection && isConnectingFromConveyor) {
console.log("Vehicle can only have one connection to a Conveyor");
return path;
}
if (!existingTargets.some(target =>
target.pathUUID === reverseTarget.pathUUID &&
target.pointUUID === reverseTarget.pointUUID
@ -135,6 +178,7 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
};
}
}
return path;
}
return path;
});
@ -168,7 +212,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
drag = true;
}
};
const onContextMenu = (evt: MouseEvent) => {
evt.preventDefault();
if (drag || evt.button === 0) return;
@ -200,29 +243,126 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const firstPath = simulationPaths.find(p => p.modeluuid === firstSelected?.pathUUID);
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
// Prevent vehicle-to-vehicle connections
if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') {
console.log("Cannot connect two vehicle paths together");
return;
}
const isAlreadyConnected = simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
} else if (path.type === 'Vehicle') {
return path.point.uuid === sphereUUID &&
path.point.connections.targets.length > 0;
}
return false;
});
if (isAlreadyConnected) {
console.log("Sphere is already connected. Ignoring.");
// Prevent conveyor middle point to conveyor connections
if (firstPath && secondPath &&
firstPath.type === 'Conveyor' &&
secondPath.type === 'Conveyor' &&
!firstSelected?.isCorner) {
console.log("Conveyor middle points can only connect to non-conveyor paths");
return;
}
if (!firstSelected) {
// Check if this specific connection already exists
const isDuplicateConnection = firstSelected
? simulationPaths.some(path => {
if (path.modeluuid === firstSelected.pathUUID) {
if (path.type === 'Conveyor') {
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
return point?.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
);
} else if (path.type === 'Vehicle') {
return path.point.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
);
}
}
return false;
})
: false;
if (isDuplicateConnection) {
console.log("These points are already connected. Ignoring.");
return;
}
// For Vehicles, skip the "already connected" check since they can have multiple connections
if (intersected.userData.path.type !== 'Vehicle') {
const isAlreadyConnected = simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
}
return false;
});
if (isAlreadyConnected) {
console.log("Conveyor point is already connected. Ignoring.");
return;
}
}
// Check vehicle connection limits
const checkVehicleConnections = (pathUUID: string) => {
const path = simulationPaths.find(p => p.modeluuid === pathUUID);
if (path?.type === 'Vehicle') {
return path.point.connections.targets.length >= 2;
}
return false;
};
if (firstSelected) {
// Check if either selected point is from a Vehicle with max connections
if (checkVehicleConnections(firstSelected.pathUUID) ||
checkVehicleConnections(pathUUID)) {
console.log("Vehicle already has maximum connections");
return;
}
// Check if we're trying to add a second Conveyor connection to a Vehicle
if (firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor') {
const hasConveyorConnection = firstPath.point.connections.targets.some(target => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
return targetPath?.type === 'Conveyor';
});
if (hasConveyorConnection) {
console.log("Vehicle can only have one connection to a Conveyor");
return;
}
}
if (secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor') {
const hasConveyorConnection = secondPath.point.connections.targets.some(target => {
const targetPath = simulationPaths.find(p => p.modeluuid === target.pathUUID);
return targetPath?.type === 'Conveyor';
});
if (hasConveyorConnection) {
console.log("Vehicle can only have one connection to a Conveyor");
return;
}
}
// Prevent same-path connections
if (firstSelected.pathUUID === pathUUID) {
console.log("Cannot connect spheres on the same path.");
return;
}
// At least one must be start/end point
if (!firstSelected.isCorner && !isStartOrEnd) {
console.log("At least one of the selected spheres must be a start or end point.");
return;
}
// All checks passed - make the connection
handleAddConnection(
firstSelected.pathUUID,
firstSelected.sphereUUID,
pathUUID,
sphereUUID
);
} else {
// First selection - just store it
setFirstSelected({
pathUUID,
sphereUUID,
@ -230,28 +370,11 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
isCorner: isStartOrEnd
});
setIsConnecting(true);
} else {
if (firstSelected.sphereUUID === sphereUUID) return;
if (firstSelected.pathUUID === pathUUID) {
console.log("Cannot connect spheres on the same path.");
return;
}
if (!firstSelected.isCorner && !isStartOrEnd) {
console.log("At least one of the selected spheres must be a start or end point.");
return;
}
handleAddConnection(
firstSelected.pathUUID,
firstSelected.sphereUUID,
pathUUID,
sphereUUID
);
}
}
}
} else {
// Clicked outside - cancel connection
setFirstSelected(null);
setCurrentLine(null);
setIsConnecting(false);
@ -294,7 +417,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
if (intersects.length > 0) {
point = intersects[0].point;
if (point.y < 0.05) {
point = new THREE.Vector3(point.x, 0.05, point.z);
}
@ -316,28 +438,68 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
const secondPath = simulationPaths.find(p => p.modeluuid === pathUUID);
const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle';
// Inside the useFrame hook, where we check for snapped spheres:
const isConnectable = (pathData.type === 'Vehicle' ||
(pathData.points.length > 0 && (
sphereUUID === pathData.points[0].uuid ||
sphereUUID === pathData.points[pathData.points.length - 1].uuid
))) && !isVehicleToVehicle;
))) &&
!isVehicleToVehicle &&
!(firstPath?.type === 'Conveyor' &&
pathData.type === 'Conveyor' &&
!firstSelected.isCorner);
const isAlreadyConnected = simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
} else if (path.type === 'Vehicle') {
return path.point.uuid === sphereUUID &&
path.point.connections.targets.length > 0;
// Check for duplicate connection (regardless of path type)
const isDuplicateConnection = simulationPaths.some(path => {
if (path.modeluuid === firstSelected.pathUUID) {
if (path.type === 'Conveyor') {
const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
return point?.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
);
} else if (path.type === 'Vehicle') {
return path.point.connections.targets.some(t =>
t.pathUUID === pathUUID && t.pointUUID === sphereUUID
);
}
}
return false;
});
// For non-Vehicle paths, check if already connected
const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' &&
simulationPaths.some(path => {
if (path.type === 'Conveyor') {
return path.points.some(point =>
point.uuid === sphereUUID &&
point.connections.targets.length > 0
);
}
return false;
});
// Check vehicle connection limits
const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
pathData.point.connections.targets.length >= 2;
const isVehicleConveyorConflict =
(firstPath?.type === 'Vehicle' && secondPath?.type === 'Conveyor' &&
firstPath.point.connections.targets.some(t => {
const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID);
return targetPath?.type === 'Conveyor';
})) ||
(secondPath?.type === 'Vehicle' && firstPath?.type === 'Conveyor' &&
secondPath.point.connections.targets.some(t => {
const targetPath = simulationPaths.find(p => p.modeluuid === t.pathUUID);
return targetPath?.type === 'Conveyor';
}));
if (
!isAlreadyConnected &&
!isDuplicateConnection &&
!isVehicleToVehicle &&
!isNonVehicleAlreadyConnected &&
!isVehicleAtMaxConnections &&
!isVehicleConveyorConflict &&
firstSelected.sphereUUID !== sphereUUID &&
firstSelected.pathUUID !== pathUUID &&
(firstSelected.isCorner || isConnectable)
@ -371,13 +533,6 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec
end: point,
mid: midPoint,
});
console.log({
start: firstSelected.position,
end: point,
mid: midPoint,
});
// setIsConnecting(true);
if (sphereIntersects.length > 0) {
setHelperLineColor(isInvalidConnection ? 'red' : '#6cf542');

View File

@ -6,37 +6,37 @@ const MqttEvents = () => {
const { setTouch, setTemperature, setHumidity } = useDrieUIValue();
useEffect(() => {
const client = mqtt.connect(`ws://${process.env.REACT_APP_SERVER_MQTT_URL}`);
// const client = mqtt.connect(`ws://${process.env.REACT_APP_SERVER_MQTT_URL}`);
client.subscribe("touch");
client.subscribe("temperature");
client.subscribe("humidity");
// client.subscribe("touch");
// client.subscribe("temperature");
// client.subscribe("humidity");
const handleMessage = (topic: string, message: any) => {
const value = message.toString();
// const handleMessage = (topic: string, message: any) => {
// const value = message.toString();
if (topic === "touch") {
setTouch(value);
} else if (topic === "temperature") {
setTemperature(parseFloat(value));
} else if (topic === "humidity") {
setHumidity(parseFloat(value));
}
};
// if (topic === "touch") {
// setTouch(value);
// } else if (topic === "temperature") {
// setTemperature(parseFloat(value));
// } else if (topic === "humidity") {
// setHumidity(parseFloat(value));
// }
// };
client.on("message", handleMessage);
// client.on("message", handleMessage);
client.on("error", (err) => {
console.error("MQTT Connection Error:", err);
});
// client.on("error", (err) => {
// console.error("MQTT Connection Error:", err);
// });
client.on("close", () => {
console.log("MQTT Connection Closed");
});
// client.on("close", () => {
// console.log("MQTT Connection Closed");
// });
return () => {
client.end();
};
// return () => {
// client.end();
// };
}, [setTouch, setTemperature, setHumidity]);
return null;

View File

@ -1,5 +1,4 @@
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
console.log("url_Backend_dwinzo: ", url_Backend_dwinzo);
export const getSelect2dZoneData = async (
ZoneId?: string,