diff --git a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx index a719023..443bdbd 100644 --- a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx +++ b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx @@ -35,19 +35,32 @@ interface ProductionCapacityProps { // onPointerDown:any } -const ProductionCapacity: React.FC = ({ id, type, position, rotation, onContextMenu }) => { +const ProductionCapacity: React.FC = ({ + id, + type, + position, + rotation, + onContextMenu, +}) => { const { selectedChartId, setSelectedChartId } = useWidgetStore(); - const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const { + measurements: chartMeasurements, + duration: chartDuration, + name: widgetName, + } = useChartStore(); const [measurements, setmeasurements] = useState({}); - const [duration, setDuration] = useState("1h") - const [name, setName] = useState("Widget") - const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + const [duration, setDuration] = useState("1h"); + const [name, setName] = useState("Widget"); + const [chartData, setChartData] = useState<{ + labels: string[]; + datasets: any[]; + }>({ labels: [], datasets: [], }); const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0] + const organization = email?.split("@")[1]?.split(".")[0]; // Chart data for a week const defaultChartData = { labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], // Days of the week @@ -101,7 +114,8 @@ const ProductionCapacity: React.FC = ({ id, type, posit }; useEffect(() => { - if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) + return; const socket = io(`http://${iotApiUrl}`); @@ -111,7 +125,6 @@ const ProductionCapacity: React.FC = ({ id, type, posit interval: 1000, }; - const startStream = () => { socket.emit("lineInput", inputData); }; @@ -148,22 +161,20 @@ const ProductionCapacity: React.FC = ({ id, type, posit }, [measurements, duration, iotApiUrl]); const fetchSavedInputes = async () => { - if (id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`); + const response = await axios.get( + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}` + ); if (response.status === 200) { - setmeasurements(response.data.Data.measurements) - setDuration(response.data.Data.duration) - setName(response.data.widgetName) + setmeasurements(response.data.Data.measurements); + setDuration(response.data.Data.duration); + setName(response.data.widgetName); } else { - } - } catch (error) { - - } + } catch (error) { } } - } + }; useEffect(() => { fetchSavedInputes(); @@ -173,13 +184,9 @@ const ProductionCapacity: React.FC = ({ id, type, posit if (selectedChartId?.id === id) { fetchSavedInputes(); } - } - , [chartMeasurements, chartDuration, widgetName]) + }, [chartMeasurements, chartDuration, widgetName]); - useEffect(() => { - - - }, [rotation]) + useEffect(() => { }, [rotation]); const rotationDegrees = { x: (rotation[0] * 180) / Math.PI, y: (rotation[1] * 180) / Math.PI, @@ -187,30 +194,44 @@ const ProductionCapacity: React.FC = ({ id, type, posit }; const transformStyle = { - transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`, + transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg) translate(-50%, -50%)`, }; return ( - -
{ + e.preventDefault(); + e.stopPropagation(); + }} + onDrop={(e) => { + e.preventDefault(); + // e.stopPropagation(); + }} + wrapperClass="pointer-none" + + > +
setSelectedChartId({ id: id, type: type })} onContextMenu={onContextMenu} + style={{ - width: '300px', // Original width - height: '300px', // Original height + width: "300px", // Original width + height: "300px", // Original height transform: transformStyle.transform, - transformStyle: 'preserve-3d' + transformStyle: "preserve-3d", + position: "absolute", }} >
@@ -233,10 +254,18 @@ const ProductionCapacity: React.FC = ({ id, type, posit
{" "}
{/* Bar Chart */} - 0 ? chartData : defaultChartData} options={chartOptions} /> + 0 + ? chartData + : defaultChartData + } + options={chartOptions} + />
+ ); }; diff --git a/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx b/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx index 8e6c707..3d5d291 100644 --- a/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx +++ b/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx @@ -46,20 +46,32 @@ interface ReturnOfInvestmentProps { rotation: [number, number, number]; onContextMenu?: (event: React.MouseEvent) => void; } -const ReturnOfInvestment: React.FC = ({ id, type, position, rotation, onContextMenu }) => { - +const ReturnOfInvestment: React.FC = ({ + id, + type, + position, + rotation, + onContextMenu, +}) => { const { selectedChartId, setSelectedChartId } = useWidgetStore(); - const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const { + measurements: chartMeasurements, + duration: chartDuration, + name: widgetName, + } = useChartStore(); const [measurements, setmeasurements] = useState({}); - const [duration, setDuration] = useState("1h") - const [name, setName] = useState("Widget") - const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + const [duration, setDuration] = useState("1h"); + const [name, setName] = useState("Widget"); + const [chartData, setChartData] = useState<{ + labels: string[]; + datasets: any[]; + }>({ labels: [], datasets: [], }); const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0] + const organization = email?.split("@")[1]?.split(".")[0]; // Improved sample data for the smooth curve graph (single day) const graphData: ChartData<"line"> = { labels: [ @@ -129,7 +141,8 @@ const ReturnOfInvestment: React.FC = ({ id, type, posit }; useEffect(() => { - if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) + return; const socket = io(`http://${iotApiUrl}`); @@ -139,7 +152,6 @@ const ReturnOfInvestment: React.FC = ({ id, type, posit interval: 1000, }; - const startStream = () => { socket.emit("lineInput", inputData); }; @@ -157,8 +169,10 @@ const ReturnOfInvestment: React.FC = ({ id, type, posit return { label: datasetKey, data: responseData[datasetKey]?.values ?? [], - borderColor: index === 0 ? "rgba(75, 192, 192, 1)" : "rgba(255, 99, 132, 1)", // Light blue color - backgroundColor: index === 0 ? "rgba(75, 192, 192, 0.2)" : "rgba(255, 99, 132, 0.2)", + borderColor: + index === 0 ? "rgba(75, 192, 192, 1)" : "rgba(255, 99, 132, 1)", // Light blue color + backgroundColor: + index === 0 ? "rgba(75, 192, 192, 0.2)" : "rgba(255, 99, 132, 0.2)", fill: true, tension: 0.4, // Smooth curve effect pointRadius: 0, // Hide dots @@ -177,14 +191,15 @@ const ReturnOfInvestment: React.FC = ({ id, type, posit }, [measurements, duration, iotApiUrl]); const fetchSavedInputes = async () => { - if (id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`); + const response = await axios.get( + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}` + ); if (response.status === 200) { - setmeasurements(response.data.Data.measurements) - setDuration(response.data.Data.duration) - setName(response.data.widgetName) + setmeasurements(response.data.Data.measurements); + setDuration(response.data.Data.duration); + setName(response.data.widgetName); } else { console.log("Unexpected response:", response); } @@ -192,7 +207,7 @@ const ReturnOfInvestment: React.FC = ({ id, type, posit console.error("There was an error!", error); } } - } + }; useEffect(() => { fetchSavedInputes(); @@ -202,8 +217,7 @@ const ReturnOfInvestment: React.FC = ({ id, type, posit if (selectedChartId?.id === id) { fetchSavedInputes(); } - } - , [chartMeasurements, chartDuration, widgetName]) + }, [chartMeasurements, chartDuration, widgetName]); const rotationDegrees = { x: (rotation[0] * 180) / Math.PI, y: (rotation[1] * 180) / Math.PI, @@ -215,26 +229,32 @@ const ReturnOfInvestment: React.FC = ({ id, type, posit }; return ( - -
setSelectedChartId({ id: id, type: type })} onContextMenu={onContextMenu} >
Return of Investment
{/* Smooth curve graph with two datasets */} - 0 ? chartData : graphData} options={graphOptions} /> + 0 ? chartData : graphData} + options={graphOptions} + />
diff --git a/app/src/components/layout/3D-cards/cards/StateWorking.tsx b/app/src/components/layout/3D-cards/cards/StateWorking.tsx index 9adf77f..829d7bf 100644 --- a/app/src/components/layout/3D-cards/cards/StateWorking.tsx +++ b/app/src/components/layout/3D-cards/cards/StateWorking.tsx @@ -13,16 +13,26 @@ interface StateWorkingProps { rotation: [number, number, number]; onContextMenu?: (event: React.MouseEvent) => void; } -const StateWorking: React.FC = ({ id, type, position, rotation, onContextMenu }) => { +const StateWorking: React.FC = ({ + id, + type, + position, + rotation, + onContextMenu, +}) => { const { selectedChartId, setSelectedChartId } = useWidgetStore(); - const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const { + measurements: chartMeasurements, + duration: chartDuration, + name: widgetName, + } = useChartStore(); const [measurements, setmeasurements] = useState({}); - const [duration, setDuration] = useState("1h") - const [name, setName] = useState("Widget") + const [duration, setDuration] = useState("1h"); + const [name, setName] = useState("Widget"); const [datas, setDatas] = useState({}); const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0] + const organization = email?.split("@")[1]?.split(".")[0]; // const datas = [ // { key: "Oil Tank:", value: "24/341" }, // { key: "Oil Refin:", value: 36.023 }, @@ -33,7 +43,8 @@ const StateWorking: React.FC = ({ id, type, position, rotatio // ]; useEffect(() => { - if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) + return; const socket = io(`http://${iotApiUrl}`); const inputData = { measurements, @@ -46,7 +57,6 @@ const StateWorking: React.FC = ({ id, type, position, rotatio socket.on("connect", startStream); socket.on("lastOutput", (response) => { const responseData = response; - setDatas(responseData); }); @@ -59,14 +69,15 @@ const StateWorking: React.FC = ({ id, type, position, rotatio }, [measurements, duration, iotApiUrl]); const fetchSavedInputes = async () => { - if (id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`); + const response = await axios.get( + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}` + ); if (response.status === 200) { - setmeasurements(response.data.Data.measurements) - setDuration(response.data.Data.duration) - setName(response.data.widgetName) + setmeasurements(response.data.Data.measurements); + setDuration(response.data.Data.duration); + setName(response.data.widgetName); } else { console.log("Unexpected response:", response); } @@ -74,10 +85,7 @@ const StateWorking: React.FC = ({ id, type, position, rotatio console.error("There was an error!", error); } } - } - - - + }; useEffect(() => { fetchSavedInputes(); @@ -87,8 +95,7 @@ const StateWorking: React.FC = ({ id, type, position, rotatio if (selectedChartId?.id === id) { fetchSavedInputes(); } - } - , [chartMeasurements, chartDuration, widgetName]) + }, [chartMeasurements, chartDuration, widgetName]); const rotationDegrees = { x: (rotation[0] * 180) / Math.PI, @@ -100,19 +107,22 @@ const StateWorking: React.FC = ({ id, type, position, rotatio transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`, }; return ( - -
setSelectedChartId({ id: id, type: type })} onContextMenu={onContextMenu} > @@ -120,12 +130,10 @@ const StateWorking: React.FC = ({ id, type, position, rotatio
State - {datas?.input1 ? datas.input1 : 'input1'} . + {datas?.input1 ? datas.input1 : "input1"} .
-
- {/* */} -
+
{/* */}
{/* Data */}
@@ -136,28 +144,52 @@ const StateWorking: React.FC = ({ id, type, position, rotatio
))} */}
-
{measurements?.input2?.fields ? measurements.input2.fields : 'input2'}
-
{datas?.input2 ? datas.input2 : 'data'}
+
+ {measurements?.input2?.fields + ? measurements.input2.fields + : "input2"} +
+
{datas?.input2 ? datas.input2 : "data"}
-
{measurements?.input3?.fields ? measurements.input3.fields : 'input3'}
-
{datas?.input3 ? datas.input3 : 'data'}
+
+ {measurements?.input3?.fields + ? measurements.input3.fields + : "input3"} +
+
{datas?.input3 ? datas.input3 : "data"}
-
{measurements?.input4?.fields ? measurements.input4.fields : 'input4'}
-
{datas?.input4 ? datas.input4 : 'data'}
+
+ {measurements?.input4?.fields + ? measurements.input4.fields + : "input4"} +
+
{datas?.input4 ? datas.input4 : "data"}
-
{measurements?.input5?.fields ? measurements.input5.fields : 'input5'}
-
{datas?.input5 ? datas.input5 : 'data'}
+
+ {measurements?.input5?.fields + ? measurements.input5.fields + : "input5"} +
+
{datas?.input5 ? datas.input5 : "data"}
-
{measurements?.input6?.fields ? measurements.input6.fields : 'input6'}
-
{datas?.input6 ? datas.input6 : 'data'}
+
+ {measurements?.input6?.fields + ? measurements.input6.fields + : "input6"} +
+
{datas?.input6 ? datas.input6 : "data"}
-
{measurements?.input7?.fields ? measurements.input7.fields : 'input7'}
-
{datas?.input7 ? datas.input7 : 'data'}
+
+ {measurements?.input7?.fields + ? measurements.input7.fields + : "input7"} +
+
{datas?.input7 ? datas.input7 : "data"}
@@ -166,5 +198,3 @@ const StateWorking: React.FC = ({ id, type, position, rotatio }; export default StateWorking; - - diff --git a/app/src/components/layout/3D-cards/cards/Throughput.tsx b/app/src/components/layout/3D-cards/cards/Throughput.tsx index de3109b..a99d171 100644 --- a/app/src/components/layout/3D-cards/cards/Throughput.tsx +++ b/app/src/components/layout/3D-cards/cards/Throughput.tsx @@ -49,20 +49,32 @@ interface ThroughputProps { onContextMenu?: (event: React.MouseEvent) => void; } -const Throughput: React.FC = ({ id, type, position, rotation, onContextMenu }) => { - +const Throughput: React.FC = ({ + id, + type, + position, + rotation, + onContextMenu, +}) => { const { selectedChartId, setSelectedChartId } = useWidgetStore(); - const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const { + measurements: chartMeasurements, + duration: chartDuration, + name: widgetName, + } = useChartStore(); const [measurements, setmeasurements] = useState({}); - const [duration, setDuration] = useState("1h") - const [name, setName] = useState("Widget") - const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + const [duration, setDuration] = useState("1h"); + const [name, setName] = useState("Widget"); + const [chartData, setChartData] = useState<{ + labels: string[]; + datasets: any[]; + }>({ labels: [], datasets: [], }); const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0] + const organization = email?.split("@")[1]?.split(".")[0]; // Sample data for the line graph const graphData: ChartData<"line"> = { @@ -112,7 +124,8 @@ const Throughput: React.FC = ({ id, type, position, rotation, o }; useEffect(() => { - if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) + return; const socket = io(`http://${iotApiUrl}`); @@ -122,7 +135,6 @@ const Throughput: React.FC = ({ id, type, position, rotation, o interval: 1000, }; - const startStream = () => { socket.emit("lineInput", inputData); }; @@ -157,14 +169,15 @@ const Throughput: React.FC = ({ id, type, position, rotation, o }, [measurements, duration, iotApiUrl]); const fetchSavedInputes = async () => { - if (id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}`); + const response = await axios.get( + `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${id}/${organization}` + ); if (response.status === 200) { - setmeasurements(response.data.Data.measurements) - setDuration(response.data.Data.duration) - setName(response.data.widgetName) + setmeasurements(response.data.Data.measurements); + setDuration(response.data.Data.duration); + setName(response.data.widgetName); } else { console.log("Unexpected response:", response); } @@ -172,7 +185,7 @@ const Throughput: React.FC = ({ id, type, position, rotation, o console.error("There was an error!", error); } } - } + }; useEffect(() => { fetchSavedInputes(); @@ -182,8 +195,7 @@ const Throughput: React.FC = ({ id, type, position, rotation, o if (selectedChartId?.id === id) { fetchSavedInputes(); } - } - , [chartMeasurements, chartDuration, widgetName]) + }, [chartMeasurements, chartDuration, widgetName]); const rotationDegrees = { x: (rotation[0] * 180) / Math.PI, y: (rotation[1] * 180) / Math.PI, @@ -195,19 +207,22 @@ const Throughput: React.FC = ({ id, type, position, rotation, o }; return ( - -
setSelectedChartId({ id: id, type: type })} onContextMenu={onContextMenu} > @@ -234,7 +249,10 @@ const Throughput: React.FC = ({ id, type, position, rotation, o
{/* Line graph using react-chartjs-2 */} - 0 ? chartData : graphData} options={graphOptions} /> + 0 ? chartData : graphData} + options={graphOptions} + />
You made an extra $1256.13 this month diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index c924b0c..b2839fc 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -147,7 +147,7 @@ const Assets: React.FC = () => {
{categoryAssets && categoryAssets?.map((asset: any, index: number) => ( -
+
{asset.filename} {
{ setSelectedCategory(null); setCategoryAssets([]); @@ -182,7 +183,7 @@ const Assets: React.FC = () => {
{categoryAssets && categoryAssets?.map((asset: any, index: number) => ( -
+
{asset.filename} {
fetchCategoryAssets(category)} > { const { templates, removeTemplate, setTemplates } = useTemplateStore(); @@ -34,7 +35,10 @@ const Templates = () => { templateID: id, }; if (visualizationSocket) { - visualizationSocket.emit("v2:viz-template:deleteTemplate", deleteTemplate); + visualizationSocket.emit( + "v2:viz-template:deleteTemplate", + deleteTemplate + ); } removeTemplate(id); } catch (error) { @@ -65,11 +69,15 @@ const Templates = () => { widgets: template.widgets, }); - useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId); + useDroppedObjectsStore + .getState() + .setZone(selectedZone.zoneName, selectedZone.zoneId); if (Array.isArray(template.floatingWidget)) { template.floatingWidget.forEach((val: any) => { - useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val); + useDroppedObjectsStore + .getState() + .addObject(selectedZone.zoneName, val); }); } } catch (error) { @@ -79,7 +87,7 @@ const Templates = () => { return (
- {templates.map((template) => ( + {templates.map((template, index) => (
{template?.snapshot && (
@@ -96,7 +104,8 @@ const Templates = () => { onClick={() => handleLoadTemplate(template)} className="template-name" > - {template.name} + {/* {`Template ${index + 1}`} */} +
))} diff --git a/app/src/components/layout/sidebarRight/SideBarRight.tsx b/app/src/components/layout/sidebarRight/SideBarRight.tsx index 433052f..f991478 100644 --- a/app/src/components/layout/sidebarRight/SideBarRight.tsx +++ b/app/src/components/layout/sidebarRight/SideBarRight.tsx @@ -16,7 +16,7 @@ import Analysis from "./analysis/Analysis"; import Simulations from "./simulation/Simulations"; import { useSelectedActionSphere, - useselectedFloorItem, + useSelectedFloorItem, } from "../../../store/store"; import GlobalProperties from "./properties/GlobalProperties"; import AsstePropertiies from "./properties/AssetProperties"; @@ -30,7 +30,7 @@ const SideBarRight: React.FC = () => { const { toggleUI } = useToggleStore(); const { selectedActionSphere } = useSelectedActionSphere(); const { subModule, setSubModule } = useSubModuleStore(); - const { selectedFloorItem } = useselectedFloorItem(); + const { selectedFloorItem } = useSelectedFloorItem(); // Reset activeList whenever activeModule changes useEffect(() => { if (activeModule !== "simulation") setSubModule("properties"); @@ -101,7 +101,7 @@ const SideBarRight: React.FC = () => { )} {toggleUI && subModule === "zoneProperties" && - activeModule === "builder" && ( + (activeModule === "builder" || activeModule === "simulation") && (
@@ -135,7 +135,7 @@ const SideBarRight: React.FC = () => { selectedActionSphere.path.type === "StaticMachine" && (
- +
)} @@ -144,7 +144,7 @@ const SideBarRight: React.FC = () => { selectedActionSphere.path.type === "ArmBot" && (
- +
)} diff --git a/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx index 744d555..4dffdb2 100644 --- a/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx @@ -1,65 +1,121 @@ -import React, { useRef, useMemo } from "react"; +import React, { useRef, useMemo, useCallback, useState } from "react"; import { InfoIcon } from "../../../icons/ExportCommonIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; -import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store"; +import { + useSelectedActionSphere, + useSimulationStates, + useSocketStore +} from "../../../../store/store"; import * as Types from '../../../../types/world/worldTypes'; -import PositionInput from "../customInput/PositionInputs"; -import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt"; +import LabeledButton from "../../../ui/inputs/LabledButton"; +import LabledDropdown from "../../../ui/inputs/LabledDropdown"; const ArmBotMechanics: React.FC = () => { const { selectedActionSphere } = useSelectedActionSphere(); const { simulationStates, setSimulationStates } = useSimulationStates(); const { socket } = useSocketStore(); + const [selectedTrigger, setSelectedTrigger] = useState(null); const propertiesContainerRef = useRef(null); - const { selectedPoint, connectedPointUuids } = useMemo(() => { - if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] }; + // Get connected models for dropdowns + const connectedModels = useMemo(() => { + if (!selectedActionSphere?.points?.uuid) return []; - const vehiclePaths = simulationStates.filter( + }, [selectedActionSphere, simulationStates]); + + // Get triggers only from connected models + const connectedTriggers = useMemo(() => { + }, [connectedModels, simulationStates]); + + const { selectedPoint } = useMemo(() => { + if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null }; + + const armBotPaths = simulationStates.filter( (path): path is Types.ArmBotEventsSchema => path.type === "ArmBot" ); - const points = vehiclePaths.find( + const points = armBotPaths.find( (path) => path.points.uuid === selectedActionSphere.points.uuid )?.points; - if (!points) return { selectedPoint: null, connectedPointUuids: [] }; - - const connectedUuids: string[] = []; - if (points.connections?.targets) { - points.connections.targets.forEach(target => { - connectedUuids.push(target.pointUUID); - }); - } - return { - selectedPoint: points, - connectedPointUuids: connectedUuids + selectedPoint: points || null }; }, [selectedActionSphere, simulationStates]); const updateBackend = async (updatedPath: Types.ArmBotEventsSchema | undefined) => { - if (!updatedPath) return; - const email = localStorage.getItem("email"); - const organization = email ? email.split("@")[1].split(".")[0] : ""; + // if (!updatedPath) return; + // const email = localStorage.getItem("email"); + // const organization = email ? email.split("@")[1].split(".")[0] : ""; - // await setEventApi( - // organization, - // updatedPath.modeluuid, - // { type: "ArmBot", points: updatedPath.points } - // ); - - const data = { - organization: organization, - modeluuid: updatedPath.modeluuid, - eventData: { type: "ArmBot", points: updatedPath.points } - } - - socket.emit('v2:model-asset:updateEventData', data); + // const data = { + // organization: organization, + // modeluuid: updatedPath.modeluuid, + // eventData: { type: "ArmBot", points: updatedPath.points } + // } + // socket.emit('v2:model-asset:updateEventData', data); } + // const handleActionUpdate = useCallback((updatedAction: Partial) => { + // if (!selectedActionSphere?.points?.uuid) return; + + // const updatedPaths = simulationStates.map((path) => { + // return path; + // }); + + // const updatedPath = updatedPaths.find( + // (path): path is Types.ArmBotEventsSchema => + // path.type === "ArmBot" && + // path.points.uuid === selectedActionSphere.points.uuid + // ); + // updateBackend(updatedPath); + + // setSimulationStates(updatedPaths); + // }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]); + + // const handleSpeedChange = useCallback((speed: number) => { + // handleActionUpdate({ speed }); + // }, [handleActionUpdate]); + + // const handleProcessChange = useCallback((processes: Types.ArmBotEventsSchema['points']['actions']['processes']) => { + // handleActionUpdate({ processes }); + // }, [handleActionUpdate]); + + // const handleTriggerSelect = useCallback((displayName: string) => { + // const selected = connectedTriggers.find(t => t.displayName === displayName); + // setSelectedTrigger(selected?.uuid || null); + // }, [connectedTriggers]); + + // const handleStartPointSelect = useCallback((pointUUID: string) => { + // if (!selectedTrigger || !selectedPoint) return; + + // const updatedProcesses = selectedPoint.actions.processes?.map(process => + // process.triggerId === selectedTrigger + // ? { ...process, startPoint: pointUUID } + // : process + // ) || []; + + // handleProcessChange(updatedProcesses); + // }, [selectedTrigger, selectedPoint, handleProcessChange]); + + // const handleEndPointSelect = useCallback((pointUUID: string) => { + // if (!selectedTrigger || !selectedPoint) return; + + // const updatedProcesses = selectedPoint.actions.processes?.map(process => + // process.triggerId === selectedTrigger + // ? { ...process, endPoint: pointUUID } + // : process + // ) || []; + + // handleProcessChange(updatedProcesses); + // }, [selectedTrigger, selectedPoint, handleProcessChange]); + + // const getCurrentProcess = useCallback(() => { + // if (!selectedTrigger || !selectedPoint) return null; + // return selectedPoint.actions.processes?.find(p => p.triggerId === selectedTrigger); + // }, [selectedTrigger, selectedPoint]); return (
@@ -71,16 +127,50 @@ const ArmBotMechanics: React.FC = () => {
ArmBot Properties
- {selectedPoint && ( + {/* {selectedPoint && ( <> + handleSpeedChange(parseInt(value))} + /> + t.uuid === selectedTrigger)?.displayName || ''} + onSelect={handleTriggerSelect} + options={connectedTriggers.map(trigger => trigger.displayName)} + /> + + {selectedTrigger && ( + <> + `${model.modelName} [${index}]`)} + /> + + `${model.modelName} [${index}]`)} + /> + + + )} - )} + )} */}
- Configure armbot properties. + Configure ArmBot properties and trigger-based processes.
diff --git a/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx index 254753e..564f221 100644 --- a/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/StaticMachineMechanics.tsx @@ -1,9 +1,9 @@ -import React, { useRef, useMemo } from "react"; +import React, { useRef, useMemo, useCallback } from "react"; import { InfoIcon } from "../../../icons/ExportCommonIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; -import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store"; +import { useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store"; import * as Types from '../../../../types/world/worldTypes'; -import PositionInput from "../customInput/PositionInputs"; +import LabledDropdown from "../../../ui/inputs/LabledDropdown"; import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt"; const StaticMachineMechanics: React.FC = () => { @@ -16,11 +16,11 @@ const StaticMachineMechanics: React.FC = () => { const { selectedPoint, connectedPointUuids } = useMemo(() => { if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null, connectedPointUuids: [] }; - const vehiclePaths = simulationStates.filter( + const staticMachinePaths = simulationStates.filter( (path): path is Types.StaticMachineEventsSchema => path.type === "StaticMachine" ); - const points = vehiclePaths.find( + const points = staticMachinePaths.find( (path) => path.points.uuid === selectedActionSphere.points.uuid )?.points; @@ -47,7 +47,7 @@ const StaticMachineMechanics: React.FC = () => { // await setEventApi( // organization, // updatedPath.modeluuid, - // { type: "StaticMachine", points: updatedPath.points } + // { type: "Vehicle", points: updatedPath.points } // ); const data = { @@ -57,9 +57,77 @@ const StaticMachineMechanics: React.FC = () => { } socket.emit('v2:model-asset:updateEventData', data); - } + const handleActionUpdate = useCallback((updatedAction: Partial) => { + if (!selectedActionSphere?.points?.uuid) return; + + const updatedPaths = simulationStates.map((path) => { + if (path.type === "StaticMachine" && path.points.uuid === selectedActionSphere.points.uuid) { + return { + ...path, + points: { + ...path.points, + actions: { + ...path.points.actions, + ...updatedAction + } + } + }; + } + return path; + }); + + const updatedPath = updatedPaths.find( + (path): path is Types.StaticMachineEventsSchema => + path.type === "StaticMachine" && + path.points.uuid === selectedActionSphere.points.uuid + ); + updateBackend(updatedPath); + + setSimulationStates(updatedPaths); + }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]); + + const handleBufferChange = useCallback((buffer: number) => { + handleActionUpdate({ buffer }); + }, [handleActionUpdate]); + + const handleMaterialChange = useCallback((material: string) => { + handleActionUpdate({ material }); + }, [handleActionUpdate]); + + const handleTriggerChange = useCallback((updatedTrigger: Partial) => { + if (!selectedActionSphere?.points?.uuid) return; + + const updatedPaths = simulationStates.map((path) => { + if (path.type === "StaticMachine" && path.points.uuid === selectedActionSphere.points.uuid) { + return { + ...path, + points: { + ...path.points, + triggers: { + ...path.points.triggers, + ...updatedTrigger + } + } + }; + } + return path; + }); + + const updatedPath = updatedPaths.find( + (path): path is Types.StaticMachineEventsSchema => + path.type === "StaticMachine" && + path.points.uuid === selectedActionSphere.points.uuid + ); + updateBackend(updatedPath); + + setSimulationStates(updatedPaths); + }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]); + + const handleTriggerTypeChange = useCallback((type: string) => { + handleTriggerChange({ type }); + }, [handleTriggerChange]); return (
@@ -67,20 +135,50 @@ const StaticMachineMechanics: React.FC = () => { {selectedActionSphere?.path?.modelName || "Machine point not found"}
+
Machine Properties
{selectedPoint && ( <> + handleBufferChange(parseInt(value))} + /> + handleMaterialChange(value)} + options={["Inherit", "Crate", "Box"]} + /> + + handleTriggerTypeChange(value)} + options={["OnComplete", "OnStart"]} + /> + + {/* { + // Implement reset functionality if needed + }} + /> */} )}
- Configure machine properties. + Configure machine interaction properties and triggers.
diff --git a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx index 4db77fe..67d132f 100644 --- a/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/VehicleMechanics.tsx @@ -5,6 +5,7 @@ import { useEditingPoint, useEyeDropMode, usePreviewPosition, useSelectedActionS import * as Types from '../../../../types/world/worldTypes'; import PositionInput from "../customInput/PositionInputs"; import { setEventApi } from "../../../../services/factoryBuilder/assest/floorAsset/setEventsApt"; +import LabeledButton from "../../../ui/inputs/LabledButton"; const VehicleMechanics: React.FC = () => { const { selectedActionSphere } = useSelectedActionSphere(); @@ -126,6 +127,33 @@ const VehicleMechanics: React.FC = () => { setSimulationStates(updatedPaths); }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]); + + const ResetVehicleState = React.useCallback(() => { + if (!selectedActionSphere?.points?.uuid) return; + + const updatedPaths = simulationStates.map((state) => { + if (state.type === "Vehicle" && state.points.uuid === selectedActionSphere.points.uuid) { + return { + ...state, + points: { + ...state.points, + actions: { ...state.points.actions, start: {}, end: {} } + } + }; + } + return state; + }); + + const updatedPath = updatedPaths.find( + (path): path is Types.VehicleEventsSchema => + path.type === "Vehicle" && + path.points.uuid === selectedActionSphere.points.uuid + ); + updateBackend(updatedPath); + + setSimulationStates(updatedPaths); + }, [selectedActionSphere?.points?.uuid, simulationStates, setSimulationStates]); + const handleStartEyeDropClick = () => { setEditingPoint('start'); setEyeDropMode(true); @@ -193,6 +221,14 @@ const VehicleMechanics: React.FC = () => { handleEyeDropClick={handleEndEyeDropClick} /> + { + ResetVehicleState(); + }} + /> + { const [userData, setUserData] = useState([]); // State to track user data const [nextId, setNextId] = useState(1); // Unique ID for new entries - const { selectedFloorItem } = useselectedFloorItem(); + const { selectedFloorItem } = useSelectedFloorItem(); // Function to handle adding new user data const handleAddUserData = () => { const newUserData: UserData = { diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index b704241..f52006a 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -22,7 +22,7 @@ import { useSelectedZoneStore } from "../../store/useZoneStore"; import { useActiveTool, useAddAction, - useDeleteModels, + useDeleteTool, useDeletePointOrLine, useMovePoint, useRefTextUpdate, @@ -61,7 +61,7 @@ const Tools: React.FC = () => { // wall options const { toggleView, setToggleView } = useToggleView(); - const { setDeleteModels } = useDeleteModels(); + const { setDeleteTool } = useDeleteTool(); const { setAddAction } = useAddAction(); const { setSelectedWallItem } = useSelectedWallItem(); @@ -89,7 +89,7 @@ const Tools: React.FC = () => { const toggleSwitch = () => { if (toggleThreeD) { setSelectedWallItem(null); - setDeleteModels(false); + setDeleteTool(false); setAddAction(null); setToggleView(true); // localStorage.setItem("navBarUi", JSON.stringify(!toggleThreeD)); @@ -136,7 +136,7 @@ const Tools: React.FC = () => { useEffect(() => { setToolMode(null); - setDeleteModels(false); + setDeleteTool(false); setAddAction(null); setTransformMode(null); setMovePoint(false); @@ -202,7 +202,7 @@ const Tools: React.FC = () => { if (toggleView) { setDeletePointOrLine(true); } else { - setDeleteModels(true); + setDeleteTool(true); } break; diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index 6527414..13e4c89 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -1,17 +1,20 @@ -import React, { useEffect } from "react"; +import React from "react"; import { CleanPannel, EyeIcon, LockIcon, } from "../../icons/RealTimeVisulationIcons"; -import { panelData } from "../../../services/realTimeVisulization/zoneData/panel"; import { AddIcon } from "../../icons/ExportCommonIcons"; -import { deletePanelApi } from "../../../services/realTimeVisulization/zoneData/deletePanel"; import { useSocketStore } from "../../../store/store"; // Define the type for `Side` type Side = "top" | "bottom" | "left" | "right"; +// Define the type for HiddenPanels, where keys are zone IDs and values are arrays of hidden sides +interface HiddenPanels { + [zoneId: string]: Side[]; +} + // Define the type for the props passed to the Buttons component interface ButtonsProps { selectedZone: { @@ -35,7 +38,6 @@ interface ButtonsProps { zoneName: string; activeSides: Side[]; panelOrder: Side[]; - lockedPanels: Side[]; zoneId: string; zoneViewPortTarget: number[]; @@ -49,8 +51,8 @@ interface ButtonsProps { }[]; }> >; - hiddenPanels: Side[]; // Add this prop for hidden panels - setHiddenPanels: React.Dispatch>; // Add this prop for updating hidden panels + hiddenPanels: HiddenPanels; // Updated prop type + setHiddenPanels: React.Dispatch>; // Updated prop type } const AddButtons: React.FC = ({ @@ -61,11 +63,33 @@ const AddButtons: React.FC = ({ }) => { const { visualizationSocket } = useSocketStore(); - // Local state to track hidden panels + // Function to toggle visibility of a panel + const toggleVisibility = (side: Side) => { + const isHidden = hiddenPanels[selectedZone.zoneId]?.includes(side) ?? false; + + if (isHidden) { + // If the panel is already hidden, remove it from the hiddenPanels array for this zone + setHiddenPanels((prevHiddenPanels) => ({ + ...prevHiddenPanels, + [selectedZone.zoneId]: prevHiddenPanels[selectedZone.zoneId].filter( + (panel) => panel !== side + ), + })); + } else { + // If the panel is visible, add it to the hiddenPanels array for this zone + setHiddenPanels((prevHiddenPanels) => ({ + ...prevHiddenPanels, + [selectedZone.zoneId]: [ + ...(prevHiddenPanels[selectedZone.zoneId] || []), + side, + ], + })); + } + }; // Function to toggle lock/unlock a panel const toggleLockPanel = (side: Side) => { - console.log('side: ', side); + console.log("side: ", side); //add api const newLockedPanels = selectedZone.lockedPanels.includes(side) ? selectedZone.lockedPanels.filter((panel) => panel !== side) @@ -80,22 +104,10 @@ const AddButtons: React.FC = ({ setSelectedZone(updatedZone); }; - // Function to toggle visibility of a panel - const toggleVisibility = (side: Side) => { - const isHidden = hiddenPanels.includes(side); - if (isHidden) { - // If the panel is already hidden, remove it from the hiddenPanels array - setHiddenPanels(hiddenPanels.filter((panel) => panel !== side)); - } else { - // If the panel is visible, add it to the hiddenPanels array - setHiddenPanels([...hiddenPanels, side]); - } - }; - // Function to clean all widgets from a panel const cleanPanel = (side: Side) => { //add api - console.log('side: ', side); + console.log("side: ", side); const cleanedWidgets = selectedZone.widgets.filter( (widget) => widget.panel !== side ); @@ -150,8 +162,6 @@ const AddButtons: React.FC = ({ // // } } else { - setHiddenPanels(hiddenPanels.filter((panel) => panel !== side)); - // Panel does not exist: Create panel try { // Get email and organization safely with a default fallback @@ -188,7 +198,6 @@ const AddButtons: React.FC = ({ } catch (error) {} } }; - return ( <>
@@ -217,16 +226,20 @@ const AddButtons: React.FC = ({ {/* Hide Panel */}
toggleVisibility(side)} > (null); - const isPanelHidden = hiddenPanels.includes(widget.panel); - - // OuterClick({ - // contextClassName: ["chart-container", "floating", "sidebar-right-wrapper"], - // setMenuVisible: () => setSelectedChartId(null), - // }); + OuterClick({ + contextClassName: [ + "chart-container", + "floating", + "sidebar-right-wrapper", + "card", + ], + setMenuVisible: () => setSelectedChartId(null), + }); const deleteSelectedChart = async () => { try { @@ -397,7 +400,4 @@ export const DraggableWidget = ({ ); }; - - - -// by using canvasDimensions.height canvasDimensions.width dynamically div value insted of static 6 and 4 calculate according to canvasDimensions.width canvasDimensions.height \ No newline at end of file +// by using canvasDimensions.height canvasDimensions.width dynamically div value insted of static 6 and 4 calculate according to canvasDimensions.width canvasDimensions.height diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index f03dea8..5dbdb5b 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -1,6 +1,10 @@ import { useThree } from "@react-three/fiber"; import React, { useEffect, useRef } from "react"; -import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../store/store"; +import { + useAsset3dWidget, + useSocketStore, + useWidgetSubOption, +} from "../../../store/store"; import useModuleStore from "../../../store/useModuleStore"; import { ThreeState } from "../../../types/world/worldTypes"; import * as THREE from "three"; @@ -13,11 +17,19 @@ import { generateUniqueId } from "../../../functions/generateUniqueId"; import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget"; import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData"; import { use3DWidget } from "../../../store/useDroppedObjectsStore"; -import { useEditWidgetOptionsStore, useLeftData, useRightClickSelected, useRightSelected, useTopData, useZoneWidgetStore } from "../../../store/useZone3DWidgetStore"; -import { useWidgetStore } from "../../../store/useWidgetStore"; -import EditWidgetOption from "../menu/EditWidgetOption"; +import { + useEditWidgetOptionsStore, + useLeftData, + useRightClickSelected, + useRightSelected, + useTopData, + useZoneWidgetStore, +} from "../../../store/useZone3DWidgetStore"; import { delete3dWidgetApi } from "../../../services/realTimeVisulization/zoneData/delete3dWidget"; -import { update3dWidget, update3dWidgetRotation } from "../../../services/realTimeVisulization/zoneData/update3dWidget"; +import { + update3dWidget, + update3dWidgetRotation, +} from "../../../services/realTimeVisulization/zoneData/update3dWidget"; type WidgetData = { id: string; type: string; @@ -26,7 +38,6 @@ type WidgetData = { tempPosition?: [number, number, number]; }; - export default function Dropped3dWidgets() { const { widgetSelect } = useAsset3dWidget(); const { activeModule } = useModuleStore(); @@ -36,19 +47,18 @@ export default function Dropped3dWidgets() { const { top, setTop } = useTopData(); const { left, setLeft } = useLeftData(); const { rightSelect, setRightSelect } = useRightSelected(); - const { editWidgetOptions, setEditWidgetOptions } = useEditWidgetOptionsStore() - const { zoneWidgetData, setZoneWidgetData, addWidget, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore(); + const { editWidgetOptions, setEditWidgetOptions } = useEditWidgetOptionsStore(); + const { zoneWidgetData, setZoneWidgetData, addWidget, updateWidgetPosition, updateWidgetRotation, tempWidget, tempWidgetPosition } = useZoneWidgetStore(); const { setWidgets3D } = use3DWidget(); const { visualizationSocket } = useSocketStore(); const { rightClickSelected, setRightClickSelected } = useRightClickSelected(); const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // Floor plane for horizontal move const verticalPlane = useRef(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)); // Vertical plane for vertical move const planeIntersect = useRef(new THREE.Vector3()); - const rotationStartRef = useRef<[number, number, number]>([0, 0, 0]); const mouseStartRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 }); - + const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; useEffect(() => { if (activeModule !== "visualization") return; if (!selectedZone.zoneId) return; @@ -57,7 +67,10 @@ export default function Dropped3dWidgets() { const organization = email?.split("@")[1]?.split(".")[0]; async function get3dWidgetData() { - const result = await get3dWidgetZoneData(selectedZone.zoneId, organization); + const result = await get3dWidgetZoneData( + selectedZone.zoneId, + organization + ); setWidgets3D(result); @@ -68,66 +81,50 @@ export default function Dropped3dWidgets() { rotation: widget.rotation || [0, 0, 0], })); - setZoneWidgetData(selectedZone.zoneId, formattedWidgets); } get3dWidgetData(); }, [selectedZone.zoneId, activeModule]); + const createdWidgetRef = useRef(null); + useEffect(() => { if (activeModule !== "visualization") return; if (widgetSubOption === "Floating" || widgetSubOption === "2D") return; if (selectedZone.zoneName === "") return; - const canvasElement = gl.domElement; + const canvasElement = document.getElementById("real-time-vis-canvas"); + + if (!canvasElement) return; + + const hasEntered = { current: false }; const handleDragEnter = (event: DragEvent) => { event.preventDefault(); event.stopPropagation(); - console.log("Drag enter"); - }; + if (hasEntered.current || !widgetSelect.startsWith("ui")) return; + hasEntered.current = true; - const handleDragOver = (event: DragEvent) => { - event.preventDefault(); - event.stopPropagation(); - - }; - - const handleDragLeave = (event: DragEvent) => { - event.preventDefault(); - event.stopPropagation(); - console.log("Drag leave"); - // Remove visual feedback - canvasElement.style.cursor = ""; - }; - - const onDrop = async (event: DragEvent) => { - event.preventDefault(); - event.stopPropagation(); - canvasElement.style.cursor = ""; // Reset cursor - - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0]; - if (!widgetSelect.startsWith("ui")) return; const group1 = scene.getObjectByName("itemsGroup"); if (!group1) return; - // Update raycaster with current mouse position const rect = canvasElement.getBoundingClientRect(); mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; raycaster.setFromCamera(mouse, camera); - const intersects = raycaster.intersectObjects(scene.children, true).filter( - (intersect) => - !intersect.object.name.includes("Roof") && - !intersect.object.name.includes("agv-collider") && - !intersect.object.name.includes("MeasurementReference") && - !intersect.object.userData.isPathObject && - !(intersect.object.type === "GridHelper") - ); + const intersects = raycaster + .intersectObjects(scene.children, true) + .filter( + (intersect) => + !intersect.object.name.includes("Roof") && + !intersect.object.name.includes("agv-collider") && + !intersect.object.name.includes("MeasurementReference") && + !intersect.object.userData.isPathObject && + !(intersect.object.type === "GridHelper") + ); if (intersects.length > 0) { const { x, y, z } = intersects[0].point; @@ -138,36 +135,100 @@ export default function Dropped3dWidgets() { rotation: [0, 0, 0], }; - const add3dWidget = { - organization: organization, - widget: newWidget, - zoneId: selectedZone.zoneId - }; - - if (visualizationSocket) { - visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget); - } - - addWidget(selectedZone.zoneId, newWidget); + createdWidgetRef.current = newWidget; + tempWidget(selectedZone.zoneId, newWidget); // temp add in UI } }; - // Add all event listeners - // canvasElement.addEventListener("dragenter", handleDragEnter); - // canvasElement.addEventListener("dragover", handleDragOver); - // canvasElement.addEventListener("dragleave", handleDragLeave); + const handleDragOver = (event: DragEvent) => { + event.preventDefault(); + event.stopPropagation(); + event.dataTransfer!.dropEffect = "move"; // ✅ Add this line + const widget = createdWidgetRef.current; + if (!widget) return; + + const rect = canvasElement.getBoundingClientRect(); + mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; + mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; + raycaster.setFromCamera(mouse, camera); + + const intersects = raycaster + .intersectObjects(scene.children, true) + .filter( + (intersect) => + !intersect.object.name.includes("Roof") && + !intersect.object.name.includes("agv-collider") && + !intersect.object.name.includes("MeasurementReference") && + !intersect.object.userData.isPathObject && + !(intersect.object.type === "GridHelper") + ); + // Update widget's position in memory + if (intersects.length > 0) { + const { x, y, z } = intersects[0].point; + tempWidgetPosition(selectedZone.zoneId, widget.id, [x, y, z]); + widget.position = [x, y, z]; + } + + }; + + const onDrop = (event: any) => { + console.log("onDrop called. hasEntered: ", hasEntered.current); + event.preventDefault(); + event.stopPropagation(); + + hasEntered.current = false; + + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + const newWidget = createdWidgetRef.current; + if (!newWidget || !widgetSelect.startsWith("ui")) return; + + // ✅ Manual removal of the temp widget (same ID) + const prevWidgets = useZoneWidgetStore.getState().zoneWidgetData[selectedZone.zoneId] || []; + const cleanedWidgets = prevWidgets.filter(w => w.id !== newWidget.id); + useZoneWidgetStore.setState((state) => ({ + zoneWidgetData: { + ...state.zoneWidgetData, + [selectedZone.zoneId]: cleanedWidgets, + }, + })); + + // ✅ Now re-add it as final + addWidget(selectedZone.zoneId, newWidget); + + const add3dWidget = { + organization, + widget: newWidget, + zoneId: selectedZone.zoneId, + }; + + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget); + } + + setTimeout(() => { + let pointerDivs = document.getElementsByClassName("pointer-none"); + Array.from(pointerDivs).forEach((el) => { + el.classList.remove("pointer-none"); + }); + }, 1000); + + createdWidgetRef.current = null; + }; + + canvasElement.addEventListener("dragenter", handleDragEnter); + canvasElement.addEventListener("dragover", handleDragOver); canvasElement.addEventListener("drop", onDrop); return () => { - // // Clean up all event listeners - // canvasElement.removeEventListener("dragenter", handleDragEnter); - // canvasElement.removeEventListener("dragover", handleDragOver); - // canvasElement.removeEventListener("dragleave", handleDragLeave); + canvasElement.removeEventListener("dragenter", handleDragEnter); + canvasElement.removeEventListener("dragover", handleDragOver); canvasElement.removeEventListener("drop", onDrop); - canvasElement.style.cursor = ""; // Ensure cursor is reset }; - }, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption, gl.domElement, scene, raycaster, camera]); - const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; + }, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption, camera,]); + + useEffect(() => { if (!rightClickSelected) return; @@ -176,7 +237,9 @@ export default function Dropped3dWidgets() { if (rightSelect === "Duplicate") { async function duplicateWidget() { - const widgetToDuplicate = activeZoneWidgets.find((w: WidgetData) => w.id === rightClickSelected); + const widgetToDuplicate = activeZoneWidgets.find( + (w: WidgetData) => w.id === rightClickSelected + ); if (!widgetToDuplicate) return; const newWidget: WidgetData = { id: generateUniqueId(), @@ -191,19 +254,19 @@ export default function Dropped3dWidgets() { const adding3dWidget = { organization: organization, widget: newWidget, - zoneId: selectedZone.zoneId + zoneId: selectedZone.zoneId, }; if (visualizationSocket) { visualizationSocket.emit("v2:viz-3D-widget:add", adding3dWidget); } // let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget) - // + // addWidget(selectedZone.zoneId, newWidget); setRightSelect(null); setRightClickSelected(null); } - duplicateWidget() + duplicateWidget(); } if (rightSelect === "Delete") { @@ -215,7 +278,6 @@ export default function Dropped3dWidgets() { zoneId: selectedZone.zoneId, }; - if (visualizationSocket) { visualizationSocket.emit("v2:viz-3D-widget:delete", deleteWidget); } @@ -223,10 +285,11 @@ export default function Dropped3dWidgets() { // const response = await delete3dWidgetApi(selectedZone.zoneId, organization, rightClickSelected); setZoneWidgetData( selectedZone.zoneId, - activeZoneWidgets.filter((w: WidgetData) => w.id !== rightClickSelected) + activeZoneWidgets.filter( + (w: WidgetData) => w.id !== rightClickSelected + ) ); } catch (error) { - } finally { setRightClickSelected(null); setRightSelect(null); @@ -238,7 +301,6 @@ export default function Dropped3dWidgets() { }, [rightSelect, rightClickSelected]); useEffect(() => { - const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; const handleMouseDown = (event: MouseEvent) => { @@ -247,13 +309,18 @@ export default function Dropped3dWidgets() { if (rightSelect === "RotateX" || rightSelect === "RotateY") { mouseStartRef.current = { x: event.clientX, y: event.clientY }; - const selectedZone = Object.keys(zoneWidgetData).find((zoneId: string) => - zoneWidgetData[zoneId].some((widget: WidgetData) => widget.id === rightClickSelected) + const selectedZone = Object.keys(zoneWidgetData).find( + (zoneId: string) => + zoneWidgetData[zoneId].some( + (widget: WidgetData) => widget.id === rightClickSelected + ) ); if (!selectedZone) return; - const selectedWidget = zoneWidgetData[selectedZone].find((widget: WidgetData) => widget.id === rightClickSelected); + const selectedWidget = zoneWidgetData[selectedZone].find( + (widget: WidgetData) => widget.id === rightClickSelected + ); if (selectedWidget) { rotationStartRef.current = selectedWidget.rotation || [0, 0, 0]; } @@ -263,11 +330,15 @@ export default function Dropped3dWidgets() { const handleMouseMove = (event: MouseEvent) => { if (!rightClickSelected || !rightSelect) return; const selectedZone = Object.keys(zoneWidgetData).find((zoneId: string) => - zoneWidgetData[zoneId].some((widget: WidgetData) => widget.id === rightClickSelected) + zoneWidgetData[zoneId].some( + (widget: WidgetData) => widget.id === rightClickSelected + ) ); if (!selectedZone) return; - const selectedWidget = zoneWidgetData[selectedZone].find((widget: WidgetData) => widget.id === rightClickSelected); + const selectedWidget = zoneWidgetData[selectedZone].find( + (widget: WidgetData) => widget.id === rightClickSelected + ); if (!selectedWidget) return; const rect = gl.domElement.getBoundingClientRect(); @@ -276,22 +347,29 @@ export default function Dropped3dWidgets() { raycaster.setFromCamera(mouse, camera); - if (rightSelect === "Horizontal Move" && raycaster.ray.intersectPlane(plane.current, planeIntersect.current)) { + if ( + rightSelect === "Horizontal Move" && + raycaster.ray.intersectPlane(plane.current, planeIntersect.current) + ) { const newPosition: [number, number, number] = [ planeIntersect.current.x, selectedWidget.position[1], - planeIntersect.current.z + planeIntersect.current.z, ]; updateWidgetPosition(selectedZone, rightClickSelected, newPosition); - } if (rightSelect === "Vertical Move") { - if (raycaster.ray.intersectPlane(verticalPlane.current, planeIntersect.current)) { + if ( + raycaster.ray.intersectPlane( + verticalPlane.current, + planeIntersect.current + ) + ) { updateWidgetPosition(selectedZone, rightClickSelected, [ selectedWidget.position[0], planeIntersect.current.y, - selectedWidget.position[2] + selectedWidget.position[2], ]); } } @@ -302,7 +380,7 @@ export default function Dropped3dWidgets() { const newRotation: [number, number, number] = [ rotationStartRef.current[0] + deltaX * rotationSpeed, rotationStartRef.current[1], - rotationStartRef.current[2] + rotationStartRef.current[2], ]; updateWidgetRotation(selectedZone, rightClickSelected, newRotation); } @@ -313,7 +391,7 @@ export default function Dropped3dWidgets() { const newRotation: [number, number, number] = [ rotationStartRef.current[0], rotationStartRef.current[1] + deltaY * rotationSpeed, - rotationStartRef.current[2] + rotationStartRef.current[2], ]; updateWidgetRotation(selectedZone, rightClickSelected, newRotation); } @@ -324,31 +402,42 @@ export default function Dropped3dWidgets() { const newRotation: [number, number, number] = [ currentRotation[0], currentRotation[1], - currentRotation[2] + deltaX * rotationSpeed + currentRotation[2] + deltaX * rotationSpeed, ]; updateWidgetRotation(selectedZone, rightClickSelected, newRotation); } - }; const handleMouseUp = () => { if (!rightClickSelected || !rightSelect) return; - const selectedZone = Object.keys(zoneWidgetData).find(zoneId => - zoneWidgetData[zoneId].some(widget => widget.id === rightClickSelected) + const selectedZone = Object.keys(zoneWidgetData).find((zoneId) => + zoneWidgetData[zoneId].some( + (widget) => widget.id === rightClickSelected + ) ); if (!selectedZone) return; - const selectedWidget = zoneWidgetData[selectedZone].find(widget => widget.id === rightClickSelected); + const selectedWidget = zoneWidgetData[selectedZone].find( + (widget) => widget.id === rightClickSelected + ); if (!selectedWidget) return; // Format values to 2 decimal places - const formatValues = (vals: number[]) => vals.map(val => parseFloat(val.toFixed(2))); - if (rightSelect === "Horizontal Move" || rightSelect === "Vertical Move") { - let lastPosition = formatValues(selectedWidget.position) as [number, number, number]; + const formatValues = (vals: number[]) => + vals.map((val) => parseFloat(val.toFixed(2))); + if ( + rightSelect === "Horizontal Move" || + rightSelect === "Vertical Move" + ) { + let lastPosition = formatValues(selectedWidget.position) as [ + number, + number, + number + ]; // (async () => { // let response = await update3dWidget(selectedZone, organization, rightClickSelected, lastPosition); - // + // // if (response) { - // + // // } // })(); let updatingPosition = { @@ -356,21 +445,22 @@ export default function Dropped3dWidgets() { zoneId: selectedZone, id: rightClickSelected, position: lastPosition, - } + }; if (visualizationSocket) { - visualizationSocket.emit("v2:viz-3D-widget:modifyPositionRotation", updatingPosition); + visualizationSocket.emit( + "v2:viz-3D-widget:modifyPositionRotation", + updatingPosition + ); } - - } - else if (rightSelect.includes("Rotate")) { + } else if (rightSelect.includes("Rotate")) { const rotation = selectedWidget.rotation || [0, 0, 0]; let lastRotation = formatValues(rotation) as [number, number, number]; // (async () => { // let response = await update3dWidgetRotation(selectedZone, organization, rightClickSelected, lastRotation); - // + // // if (response) { - // + // // } // })(); let updatingRotation = { @@ -378,9 +468,12 @@ export default function Dropped3dWidgets() { zoneId: selectedZone, id: rightClickSelected, rotation: lastRotation, - } + }; if (visualizationSocket) { - visualizationSocket.emit("v2:viz-3D-widget:modifyPositionRotation", updatingRotation); + visualizationSocket.emit( + "v2:viz-3D-widget:modifyPositionRotation", + updatingRotation + ); } } @@ -403,33 +496,73 @@ export default function Dropped3dWidgets() { return ( <> - {activeZoneWidgets.map(({ id, type, position, rotation = [0, 0, 0] }: WidgetData) => { - const handleRightClick = (event: React.MouseEvent, id: string) => { - event.preventDefault(); - const canvasElement = document.getElementById("real-time-vis-canvas"); - if (!canvasElement) throw new Error("Canvas element not found"); - const canvasRect = canvasElement.getBoundingClientRect(); - const relativeX = event.clientX - canvasRect.left; - const relativeY = event.clientY - canvasRect.top; - setEditWidgetOptions(true); - setRightClickSelected(id); - setTop(relativeY); - setLeft(relativeX); - }; + {activeZoneWidgets.map( + ({ id, type, position, rotation = [0, 0, 0] }: WidgetData) => { + const handleRightClick = (event: React.MouseEvent, id: string) => { + event.preventDefault(); + const canvasElement = document.getElementById( + "real-time-vis-canvas" + ); + if (!canvasElement) throw new Error("Canvas element not found"); + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = event.clientX - canvasRect.left; + const relativeY = event.clientY - canvasRect.top; + setEditWidgetOptions(true); + setRightClickSelected(id); + setTop(relativeY); + setLeft(relativeX); + }; - switch (type) { - case "ui-Widget 1": - return ( handleRightClick(e, id)} />); - case "ui-Widget 2": - return ( handleRightClick(e, id)} />); - case "ui-Widget 3": - return ( handleRightClick(e, id)} />); - case "ui-Widget 4": - return ( handleRightClick(e, id)} />); - default: - return null; + switch (type) { + case "ui-Widget 1": + return ( + handleRightClick(e, id)} + /> + ); + case "ui-Widget 2": + return ( + handleRightClick(e, id)} + /> + ); + case "ui-Widget 3": + return ( + handleRightClick(e, id)} + /> + ); + case "ui-Widget 4": + return ( + handleRightClick(e, id)} + /> + ); + default: + return null; + } } - })} + )} ); -} \ No newline at end of file +} diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index f9a598f..30136e5 100644 --- a/app/src/components/ui/componets/Panel.tsx +++ b/app/src/components/ui/componets/Panel.tsx @@ -39,7 +39,7 @@ interface PanelProps { widgets: Widget[]; }> >; - hiddenPanels: string[]; + hiddenPanels: any; setZonesData: React.Dispatch>; } @@ -139,7 +139,12 @@ const Panel: React.FC = ({ const handleDrop = (e: React.DragEvent, panel: Side) => { e.preventDefault(); const { draggedAsset } = useWidgetStore.getState(); - if (!draggedAsset || isPanelLocked(panel)) return; + if ( + !draggedAsset || + isPanelLocked(panel) || + hiddenPanels[selectedZone.zoneId]?.includes(panel) + ) + return; const currentWidgetsCount = getCurrentWidgetCount(panel); const maxCapacity = calculatePanelCapacity(panel); @@ -255,8 +260,6 @@ const Panel: React.FC = ({ const leftCapacity = calculatePanelCapacity("left"); const rightCapacity = calculatePanelCapacity("right"); - console.log('topCapacity: ', topCapacity); - console.log('bottomWidth: ', bottomWidth); return ( <>