diff --git a/app/package-lock.json b/app/package-lock.json index 8be748e..a820896 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -29,7 +29,6 @@ "chartjs-plugin-annotation": "^3.1.0", "glob": "^11.0.0", "gsap": "^3.12.5", - "html2canvas": "^1.4.1", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", @@ -2020,7 +2019,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2032,7 +2031,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4135,6 +4134,26 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -4246,25 +4265,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "devOptional": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -8028,15 +8047,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "node_modules/base64-arraybuffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -9007,7 +9017,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9092,15 +9102,6 @@ "postcss": "^8.4" } }, - "node_modules/css-line-break": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", - "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", - "license": "MIT", - "dependencies": { - "utrie": "^1.0.2" - } - }, "node_modules/css-loader": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", @@ -9884,7 +9885,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -12488,19 +12489,6 @@ } } }, - "node_modules/html2canvas": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", - "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", - "license": "MIT", - "dependencies": { - "css-line-break": "^2.1.0", - "text-segmentation": "^1.0.3" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/htmlparser2": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", @@ -15247,7 +15235,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -20446,15 +20434,6 @@ "node": "*" } }, - "node_modules/text-segmentation": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", - "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", - "license": "MIT", - "dependencies": { - "utrie": "^1.0.2" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -20715,7 +20694,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20758,7 +20737,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "devOptional": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20770,7 +20749,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21241,15 +21220,6 @@ "node": ">= 0.4.0" } }, - "node_modules/utrie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", - "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", - "license": "MIT", - "dependencies": { - "base64-arraybuffer": "^1.0.2" - } - }, "node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", @@ -21266,7 +21236,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "devOptional": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22325,7 +22295,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } diff --git a/app/package.json b/app/package.json index ce5c7d3..66e3b39 100644 --- a/app/package.json +++ b/app/package.json @@ -24,7 +24,6 @@ "chartjs-plugin-annotation": "^3.1.0", "glob": "^11.0.0", "gsap": "^3.12.5", - "html2canvas": "^1.4.1", "leva": "^0.10.0", "mqtt": "^5.10.4", "postprocessing": "^6.36.4", diff --git a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx index cc398e2..a6343ed 100644 --- a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx +++ b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx @@ -166,6 +166,7 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ 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); @@ -219,8 +220,8 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ // e.stopPropagation(); }} wrapperClass="pointer-none" - className={`${selectedChartId?.id === id ? "activeChart" : ""}`} - > + + > <div className={`productionCapacity-wrapper card ${selectedChartId?.id === id ? "activeChart" : ""}`} onClick={() => setSelectedChartId({ id: id, type: type })} diff --git a/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx b/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx index 9019aaf..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<ReturnOfInvestmentProps> = ({ id, type, position, rotation, onContextMenu }) => { - +const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ + 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<any>({}); - 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<ReturnOfInvestmentProps> = ({ 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<ReturnOfInvestmentProps> = ({ id, type, posit interval: 1000, }; - const startStream = () => { socket.emit("lineInput", inputData); }; @@ -157,8 +169,10 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ 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<ReturnOfInvestmentProps> = ({ 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<ReturnOfInvestmentProps> = ({ id, type, posit console.error("There was an error!", error); } } - } + }; useEffect(() => { fetchSavedInputes(); @@ -202,8 +217,7 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ 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,27 +229,32 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ id, type, posit }; return ( - <Html position={[position[0], position[1], position[2]]} + <Html + position={[position[0], position[1], position[2]]} scale={[0.5, 0.5, 0.5]} transform zIndexRange={[1, 0]} sprite style={{ transform: transformStyle.transform, - transformStyle: 'preserve-3d', - transition: 'transform 0.1s ease-out' - + transformStyle: "preserve-3d", + transition: "transform 0.1s ease-out", }} - className={`${selectedChartId?.id === id ? "activeChart" : ""}`} > - <div className="returnOfInvestment card" + <div + className={`returnOfInvestment card ${ + selectedChartId?.id === id ? "activeChart" : "" + }`} onClick={() => setSelectedChartId({ id: id, type: type })} onContextMenu={onContextMenu} > <div className="header">Return of Investment</div> <div className="lineGraph charts"> {/* Smooth curve graph with two datasets */} - <SmoothLineGraphComponent data={Object.keys(measurements).length > 0 ? chartData : graphData} options={graphOptions} /> + <SmoothLineGraphComponent + data={Object.keys(measurements).length > 0 ? chartData : graphData} + options={graphOptions} + /> </div> <div className="returns-wrapper"> <div className="icon"> diff --git a/app/src/components/layout/3D-cards/cards/StateWorking.tsx b/app/src/components/layout/3D-cards/cards/StateWorking.tsx index 93b86a2..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<StateWorkingProps> = ({ id, type, position, rotation, onContextMenu }) => { +const StateWorking: React.FC<StateWorkingProps> = ({ + 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<any>({}); - const [duration, setDuration] = useState("1h") - const [name, setName] = useState("Widget") + const [duration, setDuration] = useState("1h"); + const [name, setName] = useState("Widget"); const [datas, setDatas] = useState<any>({}); 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<StateWorkingProps> = ({ 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<StateWorkingProps> = ({ 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<StateWorkingProps> = ({ 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<StateWorkingProps> = ({ id, type, position, rotatio console.error("There was an error!", error); } } - } - - - + }; useEffect(() => { fetchSavedInputes(); @@ -87,8 +95,7 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio if (selectedChartId?.id === id) { fetchSavedInputes(); } - } - , [chartMeasurements, chartDuration, widgetName]) + }, [chartMeasurements, chartDuration, widgetName]); const rotationDegrees = { x: (rotation[0] * 180) / Math.PI, @@ -100,20 +107,22 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio transform: `rotateX(${rotationDegrees.x}deg) rotateY(${rotationDegrees.y}deg) rotateZ(${rotationDegrees.z}deg)`, }; return ( - <Html position={[position[0], position[1], position[2]]} + <Html + position={[position[0], position[1], position[2]]} scale={[0.5, 0.5, 0.5]} transform zIndexRange={[1, 0]} sprite style={{ transform: transformStyle.transform, - transformStyle: 'preserve-3d', - transition: 'transform 0.1s ease-out' - + transformStyle: "preserve-3d", + transition: "transform 0.1s ease-out", }} - className={`${selectedChartId?.id === id ? "activeChart" : ""}`} > - <div className="stateWorking-wrapper card" + <div + className={`stateWorking-wrapper card ${ + selectedChartId?.id === id ? "activeChart" : "" + }`} onClick={() => setSelectedChartId({ id: id, type: type })} onContextMenu={onContextMenu} > @@ -121,12 +130,10 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio <div className="header"> <span>State</span> <span> - {datas?.input1 ? datas.input1 : 'input1'} <span>.</span> + {datas?.input1 ? datas.input1 : "input1"} <span>.</span> </span> </div> - <div className="img"> - {/* <img src={image} alt="" /> */} - </div> + <div className="img">{/* <img src={image} alt="" /> */}</div> </div> {/* Data */} <div className="data-wrapper"> @@ -137,28 +144,52 @@ const StateWorking: React.FC<StateWorkingProps> = ({ id, type, position, rotatio </div> ))} */} <div className="data-table"> - <div className="data">{measurements?.input2?.fields ? measurements.input2.fields : 'input2'}</div> - <div className="key">{datas?.input2 ? datas.input2 : 'data'}</div> + <div className="data"> + {measurements?.input2?.fields + ? measurements.input2.fields + : "input2"} + </div> + <div className="key">{datas?.input2 ? datas.input2 : "data"}</div> </div> <div className="data-table"> - <div className="data">{measurements?.input3?.fields ? measurements.input3.fields : 'input3'}</div> - <div className="key">{datas?.input3 ? datas.input3 : 'data'}</div> + <div className="data"> + {measurements?.input3?.fields + ? measurements.input3.fields + : "input3"} + </div> + <div className="key">{datas?.input3 ? datas.input3 : "data"}</div> </div> <div className="data-table"> - <div className="data">{measurements?.input4?.fields ? measurements.input4.fields : 'input4'}</div> - <div className="key">{datas?.input4 ? datas.input4 : 'data'}</div> + <div className="data"> + {measurements?.input4?.fields + ? measurements.input4.fields + : "input4"} + </div> + <div className="key">{datas?.input4 ? datas.input4 : "data"}</div> </div> <div className="data-table"> - <div className="data">{measurements?.input5?.fields ? measurements.input5.fields : 'input5'}</div> - <div className="key">{datas?.input5 ? datas.input5 : 'data'}</div> + <div className="data"> + {measurements?.input5?.fields + ? measurements.input5.fields + : "input5"} + </div> + <div className="key">{datas?.input5 ? datas.input5 : "data"}</div> </div> <div className="data-table"> - <div className="data">{measurements?.input6?.fields ? measurements.input6.fields : 'input6'}</div> - <div className="key">{datas?.input6 ? datas.input6 : 'data'}</div> + <div className="data"> + {measurements?.input6?.fields + ? measurements.input6.fields + : "input6"} + </div> + <div className="key">{datas?.input6 ? datas.input6 : "data"}</div> </div> <div className="data-table"> - <div className="data">{measurements?.input7?.fields ? measurements.input7.fields : 'input7'}</div> - <div className="key">{datas?.input7 ? datas.input7 : 'data'}</div> + <div className="data"> + {measurements?.input7?.fields + ? measurements.input7.fields + : "input7"} + </div> + <div className="key">{datas?.input7 ? datas.input7 : "data"}</div> </div> </div> </div> @@ -167,5 +198,3 @@ const StateWorking: React.FC<StateWorkingProps> = ({ 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 f51b052..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<ThroughputProps> = ({ id, type, position, rotation, onContextMenu }) => { - +const Throughput: React.FC<ThroughputProps> = ({ + 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<any>({}); - 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<ThroughputProps> = ({ 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<ThroughputProps> = ({ id, type, position, rotation, o interval: 1000, }; - const startStream = () => { socket.emit("lineInput", inputData); }; @@ -157,14 +169,15 @@ const Throughput: React.FC<ThroughputProps> = ({ 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<ThroughputProps> = ({ id, type, position, rotation, o console.error("There was an error!", error); } } - } + }; useEffect(() => { fetchSavedInputes(); @@ -182,8 +195,7 @@ const Throughput: React.FC<ThroughputProps> = ({ 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,20 +207,22 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, o }; return ( - <Html position={[position[0], position[1], position[2]]} + <Html + position={[position[0], position[1], position[2]]} scale={[0.5, 0.5, 0.5]} transform zIndexRange={[1, 0]} sprite style={{ transform: transformStyle.transform, - transformStyle: 'preserve-3d', - transition: 'transform 0.1s ease-out' - + transformStyle: "preserve-3d", + transition: "transform 0.1s ease-out", }} - className={`${selectedChartId?.id === id ? "activeChart" : ""}`} > - <div className="throughput-wrapper" + <div + className={`throughput-wrapper card ${ + selectedChartId?.id === id ? "activeChart" : "" + }`} onClick={() => setSelectedChartId({ id: id, type: type })} onContextMenu={onContextMenu} > @@ -235,7 +249,10 @@ const Throughput: React.FC<ThroughputProps> = ({ id, type, position, rotation, o </div> <div className="line-graph"> {/* Line graph using react-chartjs-2 */} - <LineGraphComponent data={Object.keys(measurements).length > 0 ? chartData : graphData} options={graphOptions} /> + <LineGraphComponent + data={Object.keys(measurements).length > 0 ? chartData : graphData} + options={graphOptions} + /> </div> <div className="footer"> You made an extra <span className="value">$1256.13</span> this month diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index c924b0c..67bf969 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -129,6 +129,7 @@ const Assets: React.FC = () => { } else { try { const res = await getCategoryAsset(asset); + console.log('res: ', res); setCategoryAssets(res); setFiltereredAssets(res); } catch (error) {} @@ -147,7 +148,7 @@ const Assets: React.FC = () => { <div className="assets-container"> {categoryAssets && categoryAssets?.map((asset: any, index: number) => ( - <div key={index} className="assets"> + <div key={index} className="assets" id={asset.filename}> <img src={asset?.thumbnail} alt={asset.filename} @@ -171,6 +172,7 @@ const Assets: React.FC = () => { <div className="assets-wrapper"> <div className="back-button" + id="asset-backButtom" onClick={() => { setSelectedCategory(null); setCategoryAssets([]); @@ -182,7 +184,7 @@ const Assets: React.FC = () => { <div className="assets-container"> {categoryAssets && categoryAssets?.map((asset: any, index: number) => ( - <div key={index} className="assets"> + <div key={index} className="assets" id={asset.filename}> <img src={asset?.thumbnail} alt={asset.filename} @@ -190,7 +192,7 @@ const Assets: React.FC = () => { onPointerDown={() => setSelectedItem({ name: asset.filename, - id: asset.modelfileID, + id: asset.AssetID, }) } /> @@ -222,6 +224,7 @@ const Assets: React.FC = () => { <div key={index} className="category" + id={category} onClick={() => fetchCategoryAssets(category)} > <img diff --git a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx index 5eb8d4e..436af7f 100644 --- a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx @@ -4,6 +4,7 @@ import useTemplateStore from "../../../../store/useTemplateStore"; import { useSelectedZoneStore } from "../../../../store/useZoneStore"; import { getTemplateData } from "../../../../services/realTimeVisulization/zoneData/getTemplate"; import { useSocketStore } from "../../../../store/store"; +import RenameInput from "../../../ui/inputs/RenameInput"; const Templates = () => { 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 ( <div className="template-list"> - {templates.map((template) => ( + {templates.map((template, index) => ( <div key={template.id} className="template-item"> {template?.snapshot && ( <div className="template-image-container"> @@ -96,7 +104,8 @@ const Templates = () => { onClick={() => handleLoadTemplate(template)} className="template-name" > - {template.name} + {/* {`Template ${index + 1}`} */} + <RenameInput value={`Template ${index + 1}`} /> </div> <button onClick={() => handleDeleteTemplate(template.id)} diff --git a/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx index 4dffdb2..cfa7822 100644 --- a/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/ArmBotMechanics.tsx @@ -1,32 +1,128 @@ import React, { useRef, useMemo, useCallback, useState } from "react"; -import { InfoIcon } from "../../../icons/ExportCommonIcons"; +import { InfoIcon, AddIcon, RemoveIcon, ResizeHeightIcon } from "../../../icons/ExportCommonIcons"; import InputWithDropDown from "../../../ui/inputs/InputWithDropDown"; -import { - useSelectedActionSphere, - useSimulationStates, - useSocketStore -} from "../../../../store/store"; +import { useSelectedActionSphere, useSimulationStates, useSocketStore } from "../../../../store/store"; import * as Types from '../../../../types/world/worldTypes'; -import LabeledButton from "../../../ui/inputs/LabledButton"; import LabledDropdown from "../../../ui/inputs/LabledDropdown"; +import { handleResize } from "../../../../functions/handleResizePannel"; + +interface ConnectedModel { + modelUUID: string; + modelName: string; + points: { + uuid: string; + position: [number, number, number]; + index?: number; + }[]; + triggers?: { + uuid: string; + name: string; + type: string; + isUsed: boolean; + }[]; +} const ArmBotMechanics: React.FC = () => { const { selectedActionSphere } = useSelectedActionSphere(); const { simulationStates, setSimulationStates } = useSimulationStates(); const { socket } = useSocketStore(); - const [selectedTrigger, setSelectedTrigger] = useState<string | null>(null); + const [selectedProcessIndex, setSelectedProcessIndex] = useState<number | null>(null); + const actionsContainerRef = useRef<HTMLDivElement>(null); - const propertiesContainerRef = useRef<HTMLDivElement>(null); - - // Get connected models for dropdowns - const connectedModels = useMemo(() => { + // Get connected models and their triggers + const connectedModels = useMemo<ConnectedModel[]>(() => { if (!selectedActionSphere?.points?.uuid) return []; + const armBotPaths = simulationStates.filter( + (path): path is Types.ArmBotEventsSchema => path.type === "ArmBot" + ); + + const currentPoint = armBotPaths.find( + (path) => path.points.uuid === selectedActionSphere.points.uuid + )?.points; + + if (!currentPoint?.connections?.targets) return []; + + return currentPoint.connections.targets.reduce<ConnectedModel[]>((acc, target) => { + const connectedModel = simulationStates.find( + (model) => model.modeluuid === target.modelUUID + ); + + if (!connectedModel) return acc; + + let triggers: { uuid: string; name: string; type: string; isUsed: boolean }[] = []; + let points: { uuid: string; position: [number, number, number] }[] = []; + + if (connectedModel.type === "Conveyor") { + const conveyor = connectedModel as Types.ConveyorEventsSchema; + + const connectedPointUUIDs = currentPoint?.connections?.targets + .filter(t => t.modelUUID === connectedModel.modeluuid) + .map(t => t.pointUUID) || []; + + points = conveyor.points + .map((point, idx) => ({ + uuid: point.uuid, + position: point.position, + index: idx + })) + .filter(point => connectedPointUUIDs.includes(point.uuid)); + + + triggers = conveyor.points.flatMap(p => p.triggers?.filter(t => t.isUsed) || []); + } + else if (connectedModel.type === "StaticMachine") { + const staticMachine = connectedModel as Types.StaticMachineEventsSchema; + + points = [{ + uuid: staticMachine.points.uuid, + position: staticMachine.points.position + }]; + + triggers = staticMachine.points.triggers ? + [{ + uuid: staticMachine.points.triggers.uuid, + name: staticMachine.points.triggers.name, + type: staticMachine.points.triggers.type, + isUsed: true // StaticMachine triggers are always considered used + }] : []; + } + + if (!acc.some(m => m.modelUUID === connectedModel.modeluuid)) { + acc.push({ + modelUUID: connectedModel.modeluuid, + modelName: connectedModel.modelName, + points, + triggers + }); + } + + return acc; + }, []); }, [selectedActionSphere, simulationStates]); - // Get triggers only from connected models + // Get triggers from connected models const connectedTriggers = useMemo(() => { - }, [connectedModels, simulationStates]); + return connectedModels.flatMap(model => + (model.triggers || []).map(trigger => ({ + ...trigger, + displayName: `${model.modelName} - ${trigger.name}`, + modelUUID: model.modelUUID + })) + ); + }, [connectedModels]); + + // Get all points from connected models + const connectedPoints = useMemo(() => { + return connectedModels.flatMap(model => + model.points.map(point => ({ + ...point, + displayName: `${model.modelName} - Point${typeof point.index === 'number' ? ` ${point.index}` : ''}`, + modelUUID: model.modelUUID + })) + ); + }, [connectedModels]); + const { selectedPoint } = useMemo(() => { if (!selectedActionSphere?.points?.uuid) return { selectedPoint: null }; @@ -45,77 +141,148 @@ const ArmBotMechanics: React.FC = () => { }, [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] : ""; - // const data = { - // organization: organization, - // modeluuid: updatedPath.modeluuid, - // eventData: { type: "ArmBot", points: updatedPath.points } - // } + const data = { + organization: organization, + modeluuid: updatedPath.modeluuid, + eventData: { type: "ArmBot", points: updatedPath.points } + } + console.log('data: ', data); - // socket.emit('v2:model-asset:updateEventData', data); + socket.emit('v2:model-asset:updateEventData', data); } - // const handleActionUpdate = useCallback((updatedAction: Partial<Types.ArmBotEventsSchema['points']['actions']>) => { - // if (!selectedActionSphere?.points?.uuid) return; + const handleActionUpdate = useCallback((updatedAction: Partial<Types.ArmBotEventsSchema['points']['actions']>) => { + if (!selectedActionSphere?.points?.uuid || !selectedPoint) return; - // const updatedPaths = simulationStates.map((path) => { - // return path; - // }); + const updatedPaths = simulationStates.map((path) => { + if (path.type === "ArmBot" && 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.ArmBotEventsSchema => - // path.type === "ArmBot" && - // path.points.uuid === selectedActionSphere.points.uuid - // ); - // updateBackend(updatedPath); + 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]); + setSimulationStates(updatedPaths); + }, [selectedActionSphere?.points?.uuid, selectedPoint, simulationStates, setSimulationStates]); - // const handleSpeedChange = useCallback((speed: number) => { - // handleActionUpdate({ speed }); - // }, [handleActionUpdate]); + const handleSpeedChange = useCallback((speed: number) => { + handleActionUpdate({ speed }); + }, [handleActionUpdate]); - // const handleProcessChange = useCallback((processes: Types.ArmBotEventsSchema['points']['actions']['processes']) => { - // handleActionUpdate({ processes }); - // }, [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 handleAddProcess = useCallback(() => { + if (!selectedPoint) return; - // const handleStartPointSelect = useCallback((pointUUID: string) => { - // if (!selectedTrigger || !selectedPoint) return; + const newProcess: any = { + triggerId: "", + startPoint: "", + endPoint: "" + }; - // const updatedProcesses = selectedPoint.actions.processes?.map(process => - // process.triggerId === selectedTrigger - // ? { ...process, startPoint: pointUUID } - // : process - // ) || []; + const updatedProcesses = selectedPoint.actions.processes ? [...selectedPoint.actions.processes, newProcess] : [newProcess]; - // handleProcessChange(updatedProcesses); - // }, [selectedTrigger, selectedPoint, handleProcessChange]); + handleProcessChange(updatedProcesses); + setSelectedProcessIndex(updatedProcesses.length - 1); + }, [selectedPoint, handleProcessChange]); - // const handleEndPointSelect = useCallback((pointUUID: string) => { - // if (!selectedTrigger || !selectedPoint) return; + const handleDeleteProcess = useCallback((index: number) => { + if (!selectedPoint?.actions.processes) return; - // const updatedProcesses = selectedPoint.actions.processes?.map(process => - // process.triggerId === selectedTrigger - // ? { ...process, endPoint: pointUUID } - // : process - // ) || []; + const updatedProcesses = [...selectedPoint.actions.processes]; + updatedProcesses.splice(index, 1); - // handleProcessChange(updatedProcesses); - // }, [selectedTrigger, selectedPoint, handleProcessChange]); + handleProcessChange(updatedProcesses); - // const getCurrentProcess = useCallback(() => { - // if (!selectedTrigger || !selectedPoint) return null; - // return selectedPoint.actions.processes?.find(p => p.triggerId === selectedTrigger); - // }, [selectedTrigger, selectedPoint]); + // Reset selection if deleting the currently selected process + if (selectedProcessIndex === index) { + setSelectedProcessIndex(null); + } else if (selectedProcessIndex !== null && selectedProcessIndex > index) { + // Adjust selection index if needed + setSelectedProcessIndex(selectedProcessIndex - 1); + } + }, [selectedPoint, selectedProcessIndex, handleProcessChange]); + + const handleTriggerSelect = useCallback((displayName: string, index: number) => { + const selected = connectedTriggers.find(t => t.displayName === displayName); + if (!selected || !selectedPoint?.actions.processes) return; + + const oldProcess = selectedPoint.actions.processes[index]; + + const updatedProcesses = [...selectedPoint.actions.processes]; + + // Only reset start/end if new trigger invalidates them (your logic can expand this) + updatedProcesses[index] = { + ...oldProcess, + triggerId: selected.uuid, + startPoint: oldProcess.startPoint || "", // preserve if exists + endPoint: oldProcess.endPoint || "" // preserve if exists + }; + + handleProcessChange(updatedProcesses); + }, [connectedTriggers, selectedPoint, handleProcessChange]); + + const handleStartPointSelect = useCallback((displayName: string, index: number) => { + if (!selectedPoint?.actions.processes) return; + + const point = connectedPoints.find(p => p.displayName === displayName); + if (!point) return; + + const updatedProcesses = [...selectedPoint.actions.processes]; + updatedProcesses[index] = { + ...updatedProcesses[index], + startPoint: point.uuid + }; + + handleProcessChange(updatedProcesses); + }, [selectedPoint, connectedPoints, handleProcessChange]); + + const handleEndPointSelect = useCallback((displayName: string, index: number) => { + if (!selectedPoint?.actions.processes) return; + + const point = connectedPoints.find(p => p.displayName === displayName); + if (!point) return; + + const updatedProcesses = [...selectedPoint.actions.processes]; + updatedProcesses[index] = { + ...updatedProcesses[index], + endPoint: point.uuid + }; + + handleProcessChange(updatedProcesses); + }, [selectedPoint, connectedPoints, handleProcessChange]); + + const getProcessByIndex = useCallback((index: number) => { + if (!selectedPoint?.actions.processes || index >= selectedPoint.actions.processes.length) return null; + return selectedPoint.actions.processes[index]; + }, [selectedPoint]); + + const getFilteredTriggerOptions = (currentIndex: number) => { + const usedTriggerUUIDs = selectedPoint?.actions.processes?.filter((_, i) => i !== currentIndex).map(p => p.triggerId).filter(Boolean) ?? []; + + return connectedTriggers.filter(trigger => !usedTriggerUUIDs.includes(trigger.uuid)).map(trigger => trigger.displayName); + }; return ( <div className="machine-mechanics-container" key={selectedPoint?.uuid}> @@ -124,10 +291,10 @@ const ArmBotMechanics: React.FC = () => { </div> <div className="machine-mechanics-content-container"> - <div className="selected-properties-container" ref={propertiesContainerRef}> + <div className="selected-properties-container"> <div className="properties-header">ArmBot Properties</div> - {/* {selectedPoint && ( + {selectedPoint && ( <> <InputWithDropDown key={`speed-${selectedPoint.uuid}`} @@ -136,36 +303,90 @@ const ArmBotMechanics: React.FC = () => { onChange={(value) => handleSpeedChange(parseInt(value))} /> - <LabledDropdown - key={`trigger-select-${selectedPoint.uuid}`} - label="Select Trigger" - defaultOption={connectedTriggers.find(t => t.uuid === selectedTrigger)?.displayName || ''} - onSelect={handleTriggerSelect} - options={connectedTriggers.map(trigger => trigger.displayName)} - /> + <div className="actions"> + <div className="header"> + <div className="header-value">Processes</div> + <div className="add-button" onClick={handleAddProcess}> + <AddIcon /> Add + </div> + </div> + <div + className="lists-main-container" + ref={actionsContainerRef} + style={{ height: "120px" }} + > + <div className="list-container"> + {selectedPoint.actions.processes?.map((process, index) => ( + <div + key={`process-${index}`} + className={`list-item ${selectedProcessIndex === index ? "active" : ""}`} + > + <div + className="value" + onClick={() => setSelectedProcessIndex(index)} + > + Process {index + 1} + </div> + <div + className="remove-button" + onClick={() => handleDeleteProcess(index)} + > + <RemoveIcon /> + </div> + </div> + ))} + </div> + <div + className="resize-icon" + id="action-resize" + onMouseDown={(e) => handleResize(e, actionsContainerRef)} + > + <ResizeHeightIcon /> + </div> + </div> + </div> - {selectedTrigger && ( - <> + {selectedProcessIndex !== null && ( + <div className="process-configuration"> <LabledDropdown - key={`start-point-${selectedTrigger}`} + key={`trigger-select-${selectedProcessIndex}`} + label="Select Trigger" + defaultOption={ + connectedTriggers.find(t => + t.uuid === getProcessByIndex(selectedProcessIndex)?.triggerId + )?.displayName || 'Select a trigger' + } + onSelect={(value) => handleTriggerSelect(value, selectedProcessIndex)} + options={getFilteredTriggerOptions(selectedProcessIndex)} + /> + + <LabledDropdown + key={`start-point-${selectedProcessIndex}`} label="Start Point" - defaultOption={getCurrentProcess()?.startPoint || ''} - onSelect={handleStartPointSelect} - options={connectedModels.map((model, index) => `${model.modelName} [${index}]`)} + defaultOption={ + connectedPoints.find(p => + p.uuid === getProcessByIndex(selectedProcessIndex)?.startPoint + )?.displayName || 'Select start point' + } + onSelect={(value) => handleStartPointSelect(value, selectedProcessIndex)} + options={connectedPoints.map(point => point.displayName)} /> <LabledDropdown - key={`end-point-${selectedTrigger}`} + key={`end-point-${selectedProcessIndex}`} label="End Point" - defaultOption={getCurrentProcess()?.endPoint || ''} - onSelect={handleEndPointSelect} - options={connectedModels.map((model, index) => `${model.modelName} [${index}]`)} + defaultOption={ + connectedPoints.find(p => + p.uuid === getProcessByIndex(selectedProcessIndex)?.endPoint + )?.displayName || 'Select end point' + } + onSelect={(value) => handleEndPointSelect(value, selectedProcessIndex)} + options={connectedPoints.map(point => point.displayName)} /> - - </> + </div> )} </> - )} */} + )} </div> <div className="footer"> diff --git a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx b/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx index 6c7487e..71ee9ce 100644 --- a/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/mechanics/ConveyorMechanics.tsx @@ -647,7 +647,7 @@ const ConveyorMechanics: React.FC = () => { setSelectedItem({ type: "action", item: action }) } > - <input type="radio" name="action" id="action" defaultChecked={action.isUsed} /> + <input type="radio" name="action" id="action" checked={action.isUsed} readOnly /> <RenameInput value={action.name} /> </div> <div @@ -696,7 +696,7 @@ const ConveyorMechanics: React.FC = () => { setSelectedItem({ type: "trigger", item: trigger }) } > - <input type="radio" name="trigger" id="trigger" defaultChecked={trigger.isUsed} /> + <input type="radio" name="trigger" id="trigger" checked={trigger.isUsed} readOnly /> <RenameInput value={trigger.name} /> </div> <div diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index ce399b4..6492252 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"; import RenameInput from "../../../ui/inputs/RenameInput"; import Vector3Input from "../customInput/Vector3Input"; import { useSelectedZoneStore } from "../../../../store/useZoneStore"; -import { useEditPosition, usezonePosition, usezoneTarget } from "../../../../store/store"; +import { useEditPosition, usezonePosition, useZones, usezoneTarget } from "../../../../store/store"; import { zoneCameraUpdate } from "../../../../services/realTimeVisulization/zoneData/zoneCameraUpdation"; const ZoneProperties: React.FC = () => { @@ -10,6 +10,7 @@ const ZoneProperties: React.FC = () => { const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { zonePosition, setZonePosition } = usezonePosition(); const { zoneTarget, setZoneTarget } = usezoneTarget(); + const { zones, setZones } = useZones(); useEffect(() => { setZonePosition(selectedZone.zoneViewPortPosition) @@ -31,11 +32,11 @@ const ZoneProperties: React.FC = () => { if (response.message === "updated successfully") { setEdit(false); } else { - console.log("Not updated Camera Position and Target"); + console.log(response); } } catch (error) { - console.error("Error in handleSetView:", error); + } } @@ -43,17 +44,32 @@ const ZoneProperties: React.FC = () => { setEdit(!Edit); // This will toggle the `Edit` state correctly } - function handleZoneNameChange(newName: string) { - setSelectedZone((prev) => ({ ...prev, zoneName: newName })); + async function handleZoneNameChange(newName: string) { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + const zonesdata = { + zoneId: selectedZone.zoneId, + zoneName: newName + }; + // Call your API to update the zone + let response = await zoneCameraUpdate(zonesdata, organization); + console.log('response: ', response); + if (response.message === "updated successfully") { + setZones((prevZones: any[]) => + prevZones.map((zone) => + zone.zoneId === selectedZone.zoneId + ? { ...zone, zoneName: newName } + : zone + ) + ); + }else{ + console.log(response?.message); + } } - function handleVectorChange(key: "zoneViewPortTarget" | "zoneViewPortPosition", newValue: [number, number, number]) { setSelectedZone((prev) => ({ ...prev, [key]: newValue })); } - useEffect(() => { - - }, [selectedZone]); return ( <div className="zone-properties-container"> diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index 6527414..eb70dea 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -1,17 +1,22 @@ -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"; +import { clearPanel } from "../../../services/realTimeVisulization/zoneData/clearPanel"; +import { lockPanel } from "../../../services/realTimeVisulization/zoneData/lockPanel"; // 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 +40,6 @@ interface ButtonsProps { zoneName: string; activeSides: Side[]; panelOrder: Side[]; - lockedPanels: Side[]; zoneId: string; zoneViewPortTarget: number[]; @@ -49,8 +53,8 @@ interface ButtonsProps { }[]; }> >; - hiddenPanels: Side[]; // Add this prop for hidden panels - setHiddenPanels: React.Dispatch<React.SetStateAction<Side[]>>; // Add this prop for updating hidden panels + hiddenPanels: HiddenPanels; // Updated prop type + setHiddenPanels: React.Dispatch<React.SetStateAction<HiddenPanels>>; // Updated prop type } const AddButtons: React.FC<ButtonsProps> = ({ @@ -61,11 +65,35 @@ const AddButtons: React.FC<ButtonsProps> = ({ }) => { 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); + const toggleLockPanel = async (side: Side) => { + // console.log('side: ', side); + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value //add api const newLockedPanels = selectedZone.lockedPanels.includes(side) ? selectedZone.lockedPanels.filter((panel) => panel !== side) @@ -76,36 +104,65 @@ const AddButtons: React.FC<ButtonsProps> = ({ lockedPanels: newLockedPanels, }; - // Update the selectedZone state - 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]); + let lockedPanel = { + organization: organization, + lockedPanel: newLockedPanels, + zoneId: selectedZone.zoneId, + }; + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-panel:locked", lockedPanel); } + + setSelectedZone(updatedZone); + // let response = await lockPanel(selectedZone.zoneId, organization, newLockedPanels) + // console.log('response: ', response); + // if (response.message === 'locked panel updated successfully') { + // // Update the selectedZone state + // setSelectedZone(updatedZone); + // } + }; // Function to clean all widgets from a panel - const cleanPanel = (side: Side) => { + const cleanPanel = async (side: Side) => { //add api - console.log('side: ', side); + // console.log('side: ', side); + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value + + let clearPanel = { + organization: organization, + panelName: side, + zoneId: selectedZone.zoneId, + }; + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-panel:clear", clearPanel); + } const cleanedWidgets = selectedZone.widgets.filter( (widget) => widget.panel !== side ); - const updatedZone = { ...selectedZone, widgets: cleanedWidgets, }; // Update the selectedZone state + // console.log('updatedZone: ', updatedZone); setSelectedZone(updatedZone); + + // let response = await clearPanel(selectedZone.zoneId, organization, side) + // console.log('response: ', response); + // if (response.message === 'PanelWidgets cleared successfully') { + + // const cleanedWidgets = selectedZone.widgets.filter( + // (widget) => widget.panel !== side + // ); + // const updatedZone = { + // ...selectedZone, + // widgets: cleanedWidgets, + // }; + // // Update the selectedZone state + // setSelectedZone(updatedZone); + // } }; // Function to handle "+" button click @@ -150,8 +207,6 @@ const AddButtons: React.FC<ButtonsProps> = ({ // // } } else { - setHiddenPanels(hiddenPanels.filter((panel) => panel !== side)); - // Panel does not exist: Create panel try { // Get email and organization safely with a default fallback @@ -185,10 +240,9 @@ const AddButtons: React.FC<ButtonsProps> = ({ // } else { // // } - } catch (error) {} + } catch (error) { } } }; - return ( <> <div> @@ -196,9 +250,8 @@ const AddButtons: React.FC<ButtonsProps> = ({ <div key={side} className={`side-button-container ${side}`}> {/* "+" Button */} <button - className={`side-button ${side}${ - selectedZone.activeSides.includes(side) ? " active" : "" - }`} + className={`side-button ${side}${selectedZone.activeSides.includes(side) ? " active" : "" + }`} onClick={() => handlePlusButtonClick(side)} title={ selectedZone.activeSides.includes(side) @@ -217,16 +270,20 @@ const AddButtons: React.FC<ButtonsProps> = ({ {/* Hide Panel */} <div className={`icon ${ - hiddenPanels.includes(side) ? "active" : "" + hiddenPanels[selectedZone.zoneId]?.includes(side) + ? "active" + : "" }`} title={ - hiddenPanels.includes(side) ? "Show Panel" : "Hide Panel" + hiddenPanels[selectedZone.zoneId]?.includes(side) + ? "Show Panel" + : "Hide Panel" } onClick={() => toggleVisibility(side)} > <EyeIcon fill={ - hiddenPanels.includes(side) + hiddenPanels[selectedZone.zoneId]?.includes(side) ? "var(--primary-color)" : "var(--text-color)" } @@ -244,9 +301,8 @@ const AddButtons: React.FC<ButtonsProps> = ({ {/* Lock/Unlock Panel */} <div - className={`icon ${ - selectedZone.lockedPanels.includes(side) ? "active" : "" - }`} + className={`icon ${selectedZone.lockedPanels.includes(side) ? "active" : "" + }`} title={ selectedZone.lockedPanels.includes(side) ? "Unlock Panel" diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index 03fd44f..e0a5c07 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -157,6 +157,7 @@ const DisplayZone: React.FC<DisplayZoneProps> = ({ const organization = email?.split("@")[1]?.split(".")[0]; let response = await getSelect2dZoneData(zoneId, organization); + let res = await getFloatingZoneData(zoneId, organization); setFloatingWidget(res); diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx index cfd002d..fb20169 100644 --- a/app/src/components/ui/componets/DraggableWidget.tsx +++ b/app/src/components/ui/componets/DraggableWidget.tsx @@ -88,12 +88,15 @@ export const DraggableWidget = ({ const chartWidget = useRef<HTMLDivElement>(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,4 +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 diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index bd707f4..6e7513e 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -143,7 +143,7 @@ const DroppedObjects: React.FC = () => { // if (res.message === "FloatingWidget deleted successfully") { // deleteObject(zoneName, id, index); // Call the deleteObject method from the store // } - } catch (error) {} + } catch (error) { } } const handlePointerDown = (event: React.PointerEvent, index: number) => { @@ -510,7 +510,6 @@ const DroppedObjects: React.FC = () => { const widthMultiplier = parseFloat(containerWidth) * 0.13; - console.log("zone.objects: ", zone.objects); return ( <div onPointerMove={handlePointerMove} @@ -520,46 +519,41 @@ const DroppedObjects: React.FC = () => { {zone.objects.map((obj, index) => { const topPosition = typeof obj.position.top === "number" - ? `calc(${obj.position.top}px + ${ - isPlaying && selectedZone.activeSides.includes("top") - ? `${heightMultiplier - 55}px` - : "0px" - })` + ? `calc(${obj.position.top}px + ${isPlaying && selectedZone.activeSides.includes("top") + ? `${heightMultiplier - 55}px` + : "0px" + })` : "auto"; const leftPosition = typeof obj.position.left === "number" - ? `calc(${obj.position.left}px + ${ - isPlaying && selectedZone.activeSides.includes("left") - ? `${widthMultiplier - 100}px` - : "0px" - })` + ? `calc(${obj.position.left}px + ${isPlaying && selectedZone.activeSides.includes("left") + ? `${widthMultiplier - 100}px` + : "0px" + })` : "auto"; const rightPosition = typeof obj.position.right === "number" - ? `calc(${obj.position.right}px + ${ - isPlaying && selectedZone.activeSides.includes("right") - ? `${widthMultiplier - 100}px` - : "0px" - })` + ? `calc(${obj.position.right}px + ${isPlaying && selectedZone.activeSides.includes("right") + ? `${widthMultiplier - 100}px` + : "0px" + })` : "auto"; const bottomPosition = typeof obj.position.bottom === "number" - ? `calc(${obj.position.bottom}px + ${ - isPlaying && selectedZone.activeSides.includes("bottom") - ? `${heightMultiplier - 55}px` - : "0px" - })` + ? `calc(${obj.position.bottom}px + ${isPlaying && selectedZone.activeSides.includes("bottom") + ? `${heightMultiplier - 55}px` + : "0px" + })` : "auto"; return ( <div key={`${zoneName}-${index}`} - className={`${obj.className} ${ - selectedChartId?.id === obj.id && "activeChart" - }`} + className={`${obj.className} ${selectedChartId?.id === obj.id && "activeChart" + }`} ref={chartWidget} style={{ position: "absolute", diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index 85c58d0..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<React.SetStateAction<any>>; } @@ -139,7 +139,12 @@ const Panel: React.FC<PanelProps> = ({ 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); @@ -261,7 +266,7 @@ const Panel: React.FC<PanelProps> = ({ {` :root { --topWidth: ${topWidth}; - --bottomWidth: ${bottomWidth}; + --bottomWidth: ${bottomWidth} ; --leftHeight: ${leftHeight}; --rightHeight: ${rightHeight}; @@ -278,7 +283,7 @@ const Panel: React.FC<PanelProps> = ({ key={side} id="panel-wrapper" className={`panel ${side}-panel absolute ${ - hiddenPanels.includes(side) ? "hidePanel" : "" + hiddenPanels[selectedZone.zoneId]?.includes(side) ? "hidePanel" : "" }`} style={getPanelStyle(side)} onDrop={(e) => handleDrop(e, side)} @@ -294,9 +299,11 @@ const Panel: React.FC<PanelProps> = ({ <div className={`panel-content ${isPlaying && "fullScreen"}`} style={{ - pointerEvents: selectedZone.lockedPanels.includes(side) - ? "none" - : "auto", + pointerEvents: + selectedZone.lockedPanels.includes(side) || + hiddenPanels[selectedZone.zoneId]?.includes(side) + ? "none" + : "auto", opacity: selectedZone.lockedPanels.includes(side) ? "0.8" : "1", }} > diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index 293f42e..aa67191 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -7,7 +7,7 @@ import DisplayZone from "./DisplayZone"; import Scene from "../../../modules/scene/scene"; import useModuleStore from "../../../store/useModuleStore"; -import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; +import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore"; import { useAsset3dWidget, useSocketStore, @@ -53,8 +53,13 @@ type Widget = { data: any; }; +// Define the type for HiddenPanels, where keys are zone IDs and values are arrays of hidden sides +interface HiddenPanels { + [zoneId: string]: Side[]; +} + const RealTimeVisulization: React.FC = () => { - const [hiddenPanels, setHiddenPanels] = React.useState<Side[]>([]); + const [hiddenPanels, setHiddenPanels] = React.useState<HiddenPanels>({}); const containerRef = useRef<HTMLDivElement>(null); const { isPlaying } = usePlayButtonStore(); const { activeModule } = useModuleStore(); @@ -68,12 +73,12 @@ const RealTimeVisulization: React.FC = () => { const { rightClickSelected, setRightClickSelected } = useRightClickSelected(); const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false); - const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({}); + // const [floatingWidgets, setFloatingWidgets] = useState<Record<string, { zoneName: string; zoneId: string; objects: any[] }>>({}); + const { floatingWidget, setFloatingWidget } = useFloatingWidget() const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); const { visualizationSocket } = useSocketStore(); - useEffect(() => { async function GetZoneData() { const email = localStorage.getItem("email") || ""; @@ -100,7 +105,7 @@ const RealTimeVisulization: React.FC = () => { {} ); setZonesData(formattedData); - } catch (error) { } + } catch (error) {} } GetZoneData(); @@ -129,7 +134,6 @@ const RealTimeVisulization: React.FC = () => { const handleDrop = async (event: React.DragEvent<HTMLDivElement>) => { event.preventDefault(); - try { event.preventDefault(); const email = localStorage.getItem("email") || ""; @@ -175,6 +179,25 @@ const RealTimeVisulization: React.FC = () => { if (visualizationSocket) { visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); } + useDroppedObjectsStore + .getState() + .addObject(selectedZone.zoneName, newObject); + + //I need to console here objects based on selectedZone.zoneId + // Console the objects after adding + const droppedObjectsStore = useDroppedObjectsStore.getState(); + const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; + + if (currentZone && currentZone.zoneId === selectedZone.zoneId) { + console.log( + `Objects for Zone ID: ${selectedZone.zoneId}`, + currentZone.objects + ); + setFloatingWidget(currentZone.objects) + } else { + console.warn("Zone not found or mismatched zoneId"); + } + // let response = await addingFloatingWidgets( // selectedZone.zoneId, // organization, @@ -182,23 +205,10 @@ const RealTimeVisulization: React.FC = () => { // ); // Add the dropped object to the zone if the API call is successful // if (response.message === "FloatWidget created successfully") { - useDroppedObjectsStore - .getState() - .addObject(selectedZone.zoneName, newObject); // } + // Update floating widgets state - setFloatingWidgets((prevWidgets) => ({ - ...prevWidgets, - [selectedZone.zoneName]: { - ...prevWidgets[selectedZone.zoneName], - zoneName: selectedZone.zoneName, - zoneId: selectedZone.zoneId, - objects: [ - ...(prevWidgets[selectedZone.zoneName]?.objects || []), - newObject, - ], - }, - })); + } catch (error) { } }; @@ -223,8 +233,6 @@ const RealTimeVisulization: React.FC = () => { }; }, [setRightClickSelected]); - - return ( <> <div @@ -257,7 +265,6 @@ const RealTimeVisulization: React.FC = () => { }} onDrop={(event) => handleDrop(event)} onDragOver={(event) => event.preventDefault()} - > <Scene /> </div> diff --git a/app/src/components/ui/componets/zoneAssets.tsx b/app/src/components/ui/componets/zoneAssets.tsx index daa5a60..e2ec994 100644 --- a/app/src/components/ui/componets/zoneAssets.tsx +++ b/app/src/components/ui/componets/zoneAssets.tsx @@ -12,25 +12,66 @@ export default function ZoneAssets() { if (!zoneAssetId) return console.log('zoneAssetId: ', zoneAssetId); let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id); - if (!AssetMesh) return; + if (AssetMesh) { + const bbox = new THREE.Box3().setFromObject(AssetMesh); + const size = bbox.getSize(new THREE.Vector3()); + const center = bbox.getCenter(new THREE.Vector3()); - const bbox = new THREE.Box3().setFromObject(AssetMesh); - const size = bbox.getSize(new THREE.Vector3()); - const center = bbox.getCenter(new THREE.Vector3()); + const front = new THREE.Vector3(0, 0, 1); + AssetMesh.localToWorld(front); + front.sub(AssetMesh.position).normalize(); - const front = new THREE.Vector3(0, 0, 1); - AssetMesh.localToWorld(front); - front.sub(AssetMesh.position).normalize(); + const distance = Math.max(size.x, size.y, size.z) * 2; + const newPosition = center.clone().addScaledVector(front, distance); - const distance = Math.max(size.x, size.y, size.z) * 2; - const newPosition = center.clone().addScaledVector(front, distance); + controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true); + controls.setTarget(center.x, center.y, center.z, true); + controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, }); - controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true); - controls.setTarget(center.x, center.y, center.z, true); - controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, }); + setSelectedFloorItem(AssetMesh); + } else { + console.log('zoneAssetId: ', zoneAssetId) + if (Array.isArray(zoneAssetId.position) && zoneAssetId.position.length >= 3) { + let selectedAssetPosition = [ + zoneAssetId.position[0], + 10, + zoneAssetId.position[2] + ]; + console.log('selectedAssetPosition: ', selectedAssetPosition); + let selectedAssetTarget = [ + zoneAssetId.position[0], + zoneAssetId.position[1], + zoneAssetId.position[2] + ]; + console.log('selectedAssetTarget: ', selectedAssetTarget); + const setCam = async () => { + await controls?.setLookAt(...selectedAssetPosition, ...selectedAssetTarget, true); + setTimeout(() => { + let AssetMesh = scene.getObjectByProperty("uuid", zoneAssetId.id); + if (AssetMesh) { + const bbox = new THREE.Box3().setFromObject(AssetMesh); + const size = bbox.getSize(new THREE.Vector3()); + const center = bbox.getCenter(new THREE.Vector3()); - setSelectedFloorItem(AssetMesh); + const front = new THREE.Vector3(0, 0, 1); + AssetMesh.localToWorld(front); + front.sub(AssetMesh.position).normalize(); + const distance = Math.max(size.x, size.y, size.z) * 2; + const newPosition = center.clone().addScaledVector(front, distance); + + controls.setPosition(newPosition.x, newPosition.y, newPosition.z, true); + controls.setTarget(center.x, center.y, center.z, true); + controls.fitToBox(AssetMesh, true, { cover: true, paddingTop: 5, paddingLeft: 5, paddingBottom: 5, paddingRight: 5, }); + + setSelectedFloorItem(AssetMesh); + } + }, 500) + + }; + setCam(); + } + } }, [zoneAssetId, scene, controls]) diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index faa5f4e..b2f05b9 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -4,6 +4,7 @@ import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons"; import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect"; import { useFloorItems, useZones } from "../../../store/store"; import { useSelectedZoneStore } from "../../../store/useZoneStore"; +import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/getZoneData"; interface DropDownListProps { value?: string; // Value to display in the DropDownList @@ -52,10 +53,10 @@ const DropDownList: React.FC<DropDownListProps> = ({ interface ZoneData { id: string; name: string; - assets: { id: string; name: string; position?: [] ;rotation?:{}}[]; + assets: { id: string; name: string; position?: []; rotation?: {} }[]; } const [zoneDataList, setZoneDataList] = useState<ZoneData[]>([]); - const { floorItems, setFloorItems } = useFloorItems(); + const { floorItems } = useFloorItems(); const isPointInsidePolygon = (point: [number, number], polygon: [number, number][]) => { let inside = false; @@ -70,9 +71,9 @@ const DropDownList: React.FC<DropDownListProps> = ({ } return inside; }; - useEffect(() => { - const updatedZoneList: ZoneData[] = zones.map((zone: Zone) => { + useEffect(() => { + const updatedZoneList: ZoneData[] = zones?.map((zone: Zone) => { const polygon2D = zone.points.map((p: [number, number, number]) => [p[0], p[2]]) as [number, number][]; const assetsInZone = floorItems @@ -84,7 +85,7 @@ const DropDownList: React.FC<DropDownListProps> = ({ id: item.modeluuid, name: item.modelname, position: item.position, - rotation:item.rotation + rotation: item.rotation })); return { @@ -96,9 +97,6 @@ const DropDownList: React.FC<DropDownListProps> = ({ setZoneDataList(updatedZoneList); }, [zones, floorItems]); - - - return ( <div className="dropdown-list-container"> <div className="head"> diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index a176e14..06bc129 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -13,7 +13,9 @@ import { RmoveIcon, } from "../../icons/ExportCommonIcons"; import { useThree } from "@react-three/fiber"; -import { useZoneAssetId } from "../../../store/store"; +import { useFloorItems, useZoneAssetId } from "../../../store/store"; +import { zoneCameraUpdate } from "../../../services/realTimeVisulization/zoneData/zoneCameraUpdation"; +import { setFloorItemApi } from "../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; interface Asset { id: string; @@ -38,11 +40,12 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => { const { activeModule, setActiveModule } = useModuleStore(); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { zoneAssetId, setZoneAssetId } = useZoneAssetId(); + const { setSubModule } = useSubModuleStore(); const [expandedZones, setExpandedZones] = useState<Record<string, boolean>>( {} ); - + const { floorItems, setFloorItems } = useFloorItems(); useEffect(() => { useSelectedZoneStore.getState().setSelectedZone({ @@ -67,7 +70,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => { async function handleSelectZone(id: string) { try { if (selectedZone?.zoneId === id) { - console.log("Zone is already selected:", selectedZone.zoneName); + return; } @@ -89,19 +92,52 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => { zoneViewPortPosition: response?.viewPortposition || [], }); - console.log("Zone selected:", response?.zoneName); + } catch (error) { - console.error("Error selecting zone:", error); + } } function handleAssetClick(asset: Asset) { setZoneAssetId(asset) } + async function handleZoneNameChange(newName: string) { + //zone apiiiiii + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + let zonesdata = { + zoneId: selectedZone.zoneId, + zoneName: newName + }; + let response = await zoneCameraUpdate(zonesdata, organization); + if (response.message === "updated successfully") { + setSelectedZone((prev) => ({ ...prev, zoneName: newName })); + } + } + async function handleZoneAssetName(newName: string) { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + if (zoneAssetId?.id) { + let response = await setFloorItemApi(organization, zoneAssetId.id, newName) + console.log('response: ', response); + setFloorItems((prevFloorItems: any[]) => + prevFloorItems.map((floorItems) => + floorItems.modeluuid === zoneAssetId.id + ? { ...floorItems, modelname: response.modelname } + : floorItems + ) + ); + } + + console.log('newName: ', newName); + + } + return ( <> - {items.length > 0 ? ( + {items?.length > 0 ? ( <ul className="list-wrapper"> - {items.map((item) => ( + {items?.map((item) => ( <React.Fragment key={`zone-${item.id}`}> <li className="list-container"> <div className="list-item"> @@ -110,7 +146,7 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => { className="value" onClick={() => handleSelectZone(item.id)} > - <RenameInput value={item.name} /> + <RenameInput value={item.name} onRename={handleZoneNameChange} /> </div> </div> <div className="options-container"> @@ -147,8 +183,8 @@ const List: React.FC<ListProps> = ({ items = [], remove }) => { className="list-container asset-item" > <div className="list-item"> - <div className="value" onClick={() => handleAssetClick(asset)}> - <RenameInput value={asset.name} /> + <div className="value" onClick={() => handleAssetClick(asset)} > + <RenameInput value={asset.name} onRename={handleZoneAssetName} /> </div> <div className="options-container"> <div className="lock option"> diff --git a/app/src/modules/builder/agv/navMeshDetails.tsx b/app/src/modules/builder/agv/navMeshDetails.tsx index ae95942..697d89b 100644 --- a/app/src/modules/builder/agv/navMeshDetails.tsx +++ b/app/src/modules/builder/agv/navMeshDetails.tsx @@ -32,7 +32,7 @@ export default function NavMeshDetails({ const [positions, indices] = getPositionsAndIndices(meshes); - const cellSize = 0.35; + const cellSize = 0.2; const cellHeight = 0.7; const walkableRadius = 0.5; const { success, navMesh } = generateSoloNavMesh(positions, indices, { diff --git a/app/src/modules/builder/geomentries/assets/addAssetModel.ts b/app/src/modules/builder/geomentries/assets/addAssetModel.ts index d66d019..d109eb8 100644 --- a/app/src/modules/builder/geomentries/assets/addAssetModel.ts +++ b/app/src/modules/builder/geomentries/assets/addAssetModel.ts @@ -86,8 +86,8 @@ async function addAssetModel( } else { // console.log(`Added ${selectedItem.name} from Backend`); - loader.load(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`, async (gltf) => { - const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${selectedItem.id}`).then((res) => res.blob()); + loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, async (gltf) => { + const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`).then((res) => res.blob()); await storeGLTF(selectedItem.id, modelBlob); THREE.Cache.add(selectedItem.id, gltf); await handleModelLoad(gltf, intersectPoint!, selectedItem, itemsGroup, tempLoader, isTempLoader, setFloorItems, setSimulationStates, socket); @@ -235,6 +235,7 @@ async function handleModelLoad( points: { uuid: pointUUID, position: res.points.position as [number, number, number], + rotation: res.points.rotation as [number, number, number], actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', type: '', start: {}, hitCount: 1, end: {}, buffer: 0 }, connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] }, speed: 2, @@ -297,6 +298,7 @@ async function handleModelLoad( points: { uuid: pointUUID, position: res.points.position as [number, number, number], + rotation: res.points.rotation as [number, number, number], actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', buffer: 0, material: 'Inherit' }, triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] }, @@ -360,6 +362,7 @@ async function handleModelLoad( points: { uuid: pointUUID, position: res.points.position as [number, number, number], + rotation: res.points.rotation as [number, number, number], actions: { uuid: THREE.MathUtils.generateUUID(), name: 'Action 1', speed: 1, processes: [] }, triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, connections: { source: { modelUUID: model.uuid, pointUUID: pointUUID }, targets: [] }, diff --git a/app/src/modules/builder/geomentries/assets/assetManager.ts b/app/src/modules/builder/geomentries/assets/assetManager.ts index 240e7a1..5ff75a3 100644 --- a/app/src/modules/builder/geomentries/assets/assetManager.ts +++ b/app/src/modules/builder/geomentries/assets/assetManager.ts @@ -53,7 +53,7 @@ export default async function assetManager( if (!activePromises.get(taskId)) return; // Stop processing if task is canceled await new Promise<void>(async (resolve) => { - const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`; + const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`; // Check Three.js Cache const cachedModel = THREE.Cache.get(item.modelfileID!); diff --git a/app/src/modules/builder/groups/zoneGroup.tsx b/app/src/modules/builder/groups/zoneGroup.tsx index 8f2d9de..d218534 100644 --- a/app/src/modules/builder/groups/zoneGroup.tsx +++ b/app/src/modules/builder/groups/zoneGroup.tsx @@ -2,34 +2,52 @@ import React, { useState, useEffect, useMemo, useRef } from "react"; import { Line, Sphere } from "@react-three/drei"; import { useThree, useFrame } from "@react-three/fiber"; import * as THREE from "three"; -import { useActiveLayer, useDeleteTool, useDeletePointOrLine, useMovePoint, useSocketStore, useToggleView, useToolMode, useRemovedLayer, useZones, useZonePoints } from "../../../store/store"; +import { + useActiveLayer, + useDeleteTool, + useDeletePointOrLine, + useMovePoint, + useSocketStore, + useToggleView, + useToolMode, + useRemovedLayer, + useZones, + useZonePoints, +} from "../../../store/store"; // import { setZonesApi } from "../../../services/factoryBuilder/zones/setZonesApi"; // import { deleteZonesApi } from "../../../services/factoryBuilder/zones/deleteZoneApi"; import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi"; -import * as CONSTANTS from '../../../types/world/worldConstants'; +import * as CONSTANTS from "../../../types/world/worldConstants"; const ZoneGroup: React.FC = () => { - const { camera, pointer, gl, raycaster, scene, controls } = useThree(); - const [startPoint, setStartPoint] = useState<THREE.Vector3 | null>(null); - const [endPoint, setEndPoint] = useState<THREE.Vector3 | null>(null); - const { zones, setZones } = useZones(); - const { zonePoints, setZonePoints } = useZonePoints(); - const [isDragging, setIsDragging] = useState(false); - const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>(null); - const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); - const { toggleView } = useToggleView(); - const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); - const { removedLayer, setRemovedLayer } = useRemovedLayer(); - const { toolMode, setToolMode } = useToolMode(); - const { movePoint, setMovePoint } = useMovePoint(); - const { deleteTool, setDeleteTool } = useDeleteTool(); - const { activeLayer, setActiveLayer } = useActiveLayer(); - const { socket } = useSocketStore(); + const { camera, pointer, gl, raycaster, scene, controls } = useThree(); + const [startPoint, setStartPoint] = useState<THREE.Vector3 | null>(null); + const [endPoint, setEndPoint] = useState<THREE.Vector3 | null>(null); + const { zones, setZones } = useZones(); + const { zonePoints, setZonePoints } = useZonePoints(); + const [isDragging, setIsDragging] = useState(false); + const [draggedSphere, setDraggedSphere] = useState<THREE.Vector3 | null>( + null + ); + const plane = useMemo( + () => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), + [] + ); + const { toggleView } = useToggleView(); + const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); + const { removedLayer, setRemovedLayer } = useRemovedLayer(); + const { toolMode, setToolMode } = useToolMode(); + const { movePoint, setMovePoint } = useMovePoint(); + const { deleteTool, setDeleteTool } = useDeleteTool(); + const { activeLayer, setActiveLayer } = useActiveLayer(); + const { socket } = useSocketStore(); - const groupsRef = useRef<any>(); + const groupsRef = useRef<any>(); - const zoneMaterial = useMemo(() => new THREE.ShaderMaterial({ + const zoneMaterial = useMemo( + () => + new THREE.ShaderMaterial({ side: THREE.DoubleSide, vertexShader: ` varying vec2 vUv; @@ -47,466 +65,555 @@ const ZoneGroup: React.FC = () => { } `, uniforms: { - uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, + uColor: { value: new THREE.Color(CONSTANTS.zoneConfig.color) }, }, transparent: true, depthWrite: false, }), []); - useEffect(() => { - const fetchZones = async () => { - const email = localStorage.getItem('email'); - if (!email) return; + useEffect(() => { + const fetchZones = async () => { + const email = localStorage.getItem("email"); + if (!email) return; - const organization = email.split("@")[1].split(".")[0]; - const data = await getZonesApi(organization); + const organization = email.split("@")[1].split(".")[0]; + const data = await getZonesApi(organization); - if (data.data && data.data.length > 0) { - const fetchedZones = data.data.map((zone: any) => ({ - zoneId: zone.zoneId, - zoneName: zone.zoneName, - points: zone.points, - viewPortCenter: zone.viewPortCenter, - viewPortposition: zone.viewPortposition, - layer: zone.layer - })); + if (data.data && data.data.length > 0) { + const fetchedZones = data.data.map((zone: any) => ({ + zoneId: zone.zoneId, + zoneName: zone.zoneName, + points: zone.points, + viewPortCenter: zone.viewPortCenter, + viewPortposition: zone.viewPortposition, + layer: zone.layer, + })); - setZones(fetchedZones); + setZones(fetchedZones); - const fetchedPoints = data.data.flatMap((zone: any) => - zone.points.slice(0, 4).map((point: [number, number, number]) => new THREE.Vector3(...point)) - ); + const fetchedPoints = data.data.flatMap((zone: any) => + zone.points + .slice(0, 4) + .map( + (point: [number, number, number]) => new THREE.Vector3(...point) + ) + ); - setZonePoints(fetchedPoints); - } - }; + setZonePoints(fetchedPoints); + } + }; - fetchZones(); - }, []); + fetchZones(); + }, []); - useEffect(() => { + useEffect(() => { + localStorage.setItem("zones", JSON.stringify(zones)); + }, [zones]); - localStorage.setItem('zones', JSON.stringify(zones)); + useEffect(() => { + if (removedLayer) { + const updatedZones = zones.filter( + (zone: any) => zone.layer !== removedLayer + ); + setZones(updatedZones); - }, [zones]) + const updatedzonePoints = zonePoints.filter((_: any, index: any) => { + const zoneIndex = Math.floor(index / 4); + return zones[zoneIndex]?.layer !== removedLayer; + }); + setZonePoints(updatedzonePoints); - useEffect(() => { - if (removedLayer) { - const updatedZones = zones.filter((zone: any) => zone.layer !== removedLayer); - setZones(updatedZones); + zones + .filter((zone: any) => zone.layer === removedLayer) + .forEach((zone: any) => { + deleteZoneFromBackend(zone.zoneId); + }); - const updatedzonePoints = zonePoints.filter((_: any, index: any) => { - const zoneIndex = Math.floor(index / 4); - return zones[zoneIndex]?.layer !== removedLayer; - }); - setZonePoints(updatedzonePoints); + setRemovedLayer(null); + } + }, [removedLayer]); - zones.filter((zone: any) => zone.layer === removedLayer).forEach((zone: any) => { - deleteZoneFromBackend(zone.zoneId); - }); + useEffect(() => { + if (toolMode !== "Zone") { + setStartPoint(null); + setEndPoint(null); + } else { + setDeletePointOrLine(false); + setMovePoint(false); + setDeleteTool(false); + } + if (!toggleView) { + setStartPoint(null); + setEndPoint(null); + } + }, [toolMode, toggleView]); - setRemovedLayer(null); + const addZoneToBackend = async (zone: { + zoneId: string; + zoneName: string; + points: [number, number, number][]; + layer: string; + }) => { + const email = localStorage.getItem("email"); + const userId = localStorage.getItem("userId"); + const organization = email!.split("@")[1].split(".")[0]; + + const calculateCenter = (points: number[][]) => { + if (!points || points.length === 0) return null; + + let sumX = 0, + sumY = 0, + sumZ = 0; + const numPoints = points.length; + + points.forEach(([x, y, z]) => { + sumX += x; + sumY += y; + sumZ += z; + }); + + return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ + number, + number, + number + ]; + }; + + const target: [number, number, number] | null = calculateCenter( + zone.points + ); + if (!target) return; + const position = [target[0], 10, target[2]]; + + const input = { + userId: userId, + organization: organization, + zoneData: { + zoneName: zone.zoneName, + zoneId: zone.zoneId, + points: zone.points, + viewPortCenter: target, + viewPortposition: position, + layer: zone.layer, + }, + }; + + socket.emit("v2:zone:set", input); + }; + + const updateZoneToBackend = async (zone: { + zoneId: string; + zoneName: string; + points: [number, number, number][]; + layer: string; + }) => { + const email = localStorage.getItem("email"); + const userId = localStorage.getItem("userId"); + const organization = email!.split("@")[1].split(".")[0]; + + const calculateCenter = (points: number[][]) => { + if (!points || points.length === 0) return null; + + let sumX = 0, + sumY = 0, + sumZ = 0; + const numPoints = points.length; + + points.forEach(([x, y, z]) => { + sumX += x; + sumY += y; + sumZ += z; + }); + + return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [ + number, + number, + number + ]; + }; + + const target: [number, number, number] | null = calculateCenter( + zone.points + ); + if (!target) return; + const position = [target[0], 10, target[2]]; + + const input = { + userId: userId, + organization: organization, + zoneData: { + zoneName: zone.zoneName, + zoneId: zone.zoneId, + points: zone.points, + viewPortCenter: target, + viewPortposition: position, + layer: zone.layer, + }, + }; + + socket.emit("v2:zone:set", input); + }; + + const deleteZoneFromBackend = async (zoneId: string) => { + const email = localStorage.getItem("email"); + const userId = localStorage.getItem("userId"); + const organization = email!.split("@")[1].split(".")[0]; + + const input = { + userId: userId, + organization: organization, + zoneId: zoneId, + }; + + socket.emit("v2:zone:delete", input); + }; + + const handleDeleteZone = (zoneId: string) => { + const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId); + setZones(updatedZones); + + const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId); + if (zoneIndex !== -1) { + const zonePointsToRemove = zonePoints.slice( + zoneIndex * 4, + zoneIndex * 4 + 4 + ); + zonePointsToRemove.forEach((point: any) => + groupsRef.current.remove(point) + ); + const updatedzonePoints = zonePoints.filter( + (_: any, index: any) => + index < zoneIndex * 4 || index >= zoneIndex * 4 + 4 + ); + setZonePoints(updatedzonePoints); + } + + deleteZoneFromBackend(zoneId); + }; + + useEffect(() => { + if (!camera || !toggleView) return; + const canvasElement = gl.domElement; + + let drag = false; + let isLeftMouseDown = false; + + const onMouseDown = (evt: any) => { + if (evt.button === 0) { + isLeftMouseDown = true; + drag = false; + + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects( + groupsRef.current.children, + true + ); + + if (intersects.length > 0 && movePoint) { + const clickedObject = intersects[0].object; + const sphereIndex = zonePoints.findIndex((point: any) => + point.equals(clickedObject.position) + ); + if (sphereIndex !== -1) { + (controls as any).enabled = false; + setDraggedSphere(zonePoints[sphereIndex]); + setIsDragging(true); + } } - }, [removedLayer]); + } + }; - useEffect(() => { - if (toolMode !== "Zone") { - setStartPoint(null); + const onMouseUp = (evt: any) => { + if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) { + isLeftMouseDown = false; + + if (!startPoint && !movePoint) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (point) { + setStartPoint(point); setEndPoint(null); - } else { - setDeletePointOrLine(false); - setMovePoint(false); - setDeleteTool(false); + } + } else if (startPoint && !movePoint) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (!point) return; + + const points = [ + [startPoint.x, 0.15, startPoint.z], + [point.x, 0.15, startPoint.z], + [point.x, 0.15, point.z], + [startPoint.x, 0.15, point.z], + [startPoint.x, 0.15, startPoint.z], + ] as [number, number, number][]; + + const zoneName = `Zone ${zones.length + 1}`; + const zoneId = THREE.MathUtils.generateUUID(); + const newZone = { + zoneId, + zoneName, + points: points, + layer: activeLayer, + }; + + const newZones = [...zones, newZone]; + + setZones(newZones); + + const newzonePoints = [ + new THREE.Vector3(startPoint.x, 0.15, startPoint.z), + new THREE.Vector3(point.x, 0.15, startPoint.z), + new THREE.Vector3(point.x, 0.15, point.z), + new THREE.Vector3(startPoint.x, 0.15, point.z), + ]; + + const updatedZonePoints = [...zonePoints, ...newzonePoints]; + setZonePoints(updatedZonePoints); + + addZoneToBackend(newZone); + + setStartPoint(null); + setEndPoint(null); } - if (!toggleView) { - setStartPoint(null); - setEndPoint(null); + } else if ( + evt.button === 0 && + !drag && + !isDragging && + deletePointOrLine + ) { + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects( + groupsRef.current.children, + true + ); + + if (intersects.length > 0) { + const clickedObject = intersects[0].object; + + const sphereIndex = zonePoints.findIndex((point: any) => + point.equals(clickedObject.position) + ); + if (sphereIndex !== -1) { + const zoneIndex = Math.floor(sphereIndex / 4); + const zoneId = zones[zoneIndex].zoneId; + handleDeleteZone(zoneId); + return; + } } - }, [toolMode, toggleView]); + } + if (evt.button === 0) { + if (isDragging && draggedSphere) { + setIsDragging(false); + setDraggedSphere(null); - const addZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => { + const sphereIndex = zonePoints.findIndex( + (point: any) => point === draggedSphere + ); + if (sphereIndex !== -1) { + const zoneIndex = Math.floor(sphereIndex / 4); - const email = localStorage.getItem('email'); - const userId = localStorage.getItem('userId'); - const organization = (email!.split("@")[1]).split(".")[0]; - - const calculateCenter = (points: number[][]) => { - if (!points || points.length === 0) return null; - - let sumX = 0, sumY = 0, sumZ = 0; - const numPoints = points.length; - - points.forEach(([x, y, z]) => { - sumX += x; - sumY += y; - sumZ += z; - }); - - return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number]; - }; - - const target: [number, number, number] | null = calculateCenter(zone.points); - if (!target) return; - const position = [target[0], 10, target[2]]; - - const input = { - userId: userId, - organization: organization, - zoneData: { - zoneName: zone.zoneName, - zoneId: zone.zoneId, - points: zone.points, - viewPortCenter: target, - viewPortposition: position, - layer: zone.layer + if (zoneIndex !== -1 && zones[zoneIndex]) { + updateZoneToBackend(zones[zoneIndex]); } + } } - - socket.emit('v2:zone:set', input); + } }; - const updateZoneToBackend = async (zone: { zoneId: string; zoneName: string; points: [number, number, number][]; layer: string }) => { + const onMouseMove = () => { + if (isLeftMouseDown) { + drag = true; + } + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects( + groupsRef.current.children, + true + ); - const email = localStorage.getItem('email'); - const userId = localStorage.getItem('userId'); - const organization = (email!.split("@")[1]).split(".")[0]; - - const calculateCenter = (points: number[][]) => { - if (!points || points.length === 0) return null; - - let sumX = 0, sumY = 0, sumZ = 0; - const numPoints = points.length; - - points.forEach(([x, y, z]) => { - sumX += x; - sumY += y; - sumZ += z; - }); - - return [sumX / numPoints, sumY / numPoints, sumZ / numPoints] as [number, number, number]; - }; - - const target: [number, number, number] | null = calculateCenter(zone.points); - if (!target) return; - const position = [target[0], 10, target[2]]; - - const input = { - userId: userId, - organization: organization, - zoneData: { - zoneName: zone.zoneName, - zoneId: zone.zoneId, - points: zone.points, - viewPortCenter: target, - viewPortposition: position, - layer: zone.layer - } - } - - socket.emit('v2:zone:set', input); - }; - - - const deleteZoneFromBackend = async (zoneId: string) => { - - const email = localStorage.getItem('email'); - const userId = localStorage.getItem('userId'); - const organization = (email!.split("@")[1]).split(".")[0]; - - const input = { - userId: userId, - organization: organization, - zoneId: zoneId - } - - socket.emit('v2:zone:delete', input); - }; - - const handleDeleteZone = (zoneId: string) => { - const updatedZones = zones.filter((zone: any) => zone.zoneId !== zoneId); - setZones(updatedZones); - - const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === zoneId); - if (zoneIndex !== -1) { - const zonePointsToRemove = zonePoints.slice(zoneIndex * 4, zoneIndex * 4 + 4); - zonePointsToRemove.forEach((point: any) => groupsRef.current.remove(point)); - const updatedzonePoints = zonePoints.filter((_: any, index: any) => index < zoneIndex * 4 || index >= zoneIndex * 4 + 4); - setZonePoints(updatedzonePoints); - } - - deleteZoneFromBackend(zoneId); - }; - - useEffect(() => { - if (!camera || !toggleView) return; - const canvasElement = gl.domElement; - - let drag = false; - let isLeftMouseDown = false; - - const onMouseDown = (evt: any) => { - if (evt.button === 0) { - isLeftMouseDown = true; - drag = false; - - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects(groupsRef.current.children, true); - - if (intersects.length > 0 && movePoint) { - const clickedObject = intersects[0].object; - const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position)); - if (sphereIndex !== -1) { - (controls as any).enabled = false; - setDraggedSphere(zonePoints[sphereIndex]); - setIsDragging(true); - } - } - } - }; - - const onMouseUp = (evt: any) => { - if (evt.button === 0 && !drag && !isDragging && !deletePointOrLine) { - isLeftMouseDown = false; - - if (!startPoint && !movePoint) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - setStartPoint(point); - setEndPoint(null); - } - } else if (startPoint && !movePoint) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (!point) return; - - const points = [ - [startPoint.x, 0.15, startPoint.z], - [point.x, 0.15, startPoint.z], - [point.x, 0.15, point.z], - [startPoint.x, 0.15, point.z], - [startPoint.x, 0.15, startPoint.z], - ] as [number, number, number][]; - - const zoneName = `Zone ${zones.length + 1}`; - const zoneId = THREE.MathUtils.generateUUID(); - const newZone = { - zoneId, - zoneName, - points: points, - layer: activeLayer - }; - - const newZones = [...zones, newZone]; - - setZones(newZones); - - const newzonePoints = [ - new THREE.Vector3(startPoint.x, 0.15, startPoint.z), - new THREE.Vector3(point.x, 0.15, startPoint.z), - new THREE.Vector3(point.x, 0.15, point.z), - new THREE.Vector3(startPoint.x, 0.15, point.z), - ]; - - const updatedZonePoints = [...zonePoints, ...newzonePoints]; - setZonePoints(updatedZonePoints); - - addZoneToBackend(newZone); - - setStartPoint(null); - setEndPoint(null); - } - } else if (evt.button === 0 && !drag && !isDragging && deletePointOrLine) { - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects(groupsRef.current.children, true); - - if (intersects.length > 0) { - const clickedObject = intersects[0].object; - - const sphereIndex = zonePoints.findIndex((point: any) => point.equals(clickedObject.position)); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - const zoneId = zones[zoneIndex].zoneId; - handleDeleteZone(zoneId); - return; - } - } - } - - if (evt.button === 0) { - if (isDragging && draggedSphere) { - setIsDragging(false); - setDraggedSphere(null); - - const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - - if (zoneIndex !== -1 && zones[zoneIndex]) { - updateZoneToBackend(zones[zoneIndex]); - } - } - } - } - }; - - const onMouseMove = () => { - if (isLeftMouseDown) { - drag = true; - } - raycaster.setFromCamera(pointer, camera); - const intersects = raycaster.intersectObjects(groupsRef.current.children, true); - - if (intersects.length > 0 && intersects[0].object.name.includes('point')) { - gl.domElement.style.cursor = movePoint ? "pointer" : "default"; - } else { - gl.domElement.style.cursor = "default"; - } - if (isDragging && draggedSphere) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); - if (point) { - draggedSphere.set(point.x, 0.15, point.z); - - const sphereIndex = zonePoints.findIndex((point: any) => point === draggedSphere); - if (sphereIndex !== -1) { - const zoneIndex = Math.floor(sphereIndex / 4); - const cornerIndex = sphereIndex % 4; - - const updatedZones = zones.map((zone: any, index: number) => { - if (index === zoneIndex) { - const updatedPoints = [...zone.points]; - updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; - updatedPoints[4] = updatedPoints[0]; - return { ...zone, points: updatedPoints }; - } - return zone; - }); - - setZones(updatedZones); - } - } - } - }; - - const onContext = (event: any) => { - event.preventDefault(); - setStartPoint(null); - setEndPoint(null); - }; - - if (toolMode === 'Zone' || deletePointOrLine || movePoint) { - canvasElement.addEventListener("mousedown", onMouseDown); - canvasElement.addEventListener("mouseup", onMouseUp); - canvasElement.addEventListener("mousemove", onMouseMove); - canvasElement.addEventListener("contextmenu", onContext); - } - return () => { - canvasElement.removeEventListener("mousedown", onMouseDown); - canvasElement.removeEventListener("mouseup", onMouseUp); - canvasElement.removeEventListener("mousemove", onMouseMove); - canvasElement.removeEventListener("contextmenu", onContext); - }; - }, [gl, camera, startPoint, toggleView, scene, toolMode, zones, isDragging, deletePointOrLine, zonePoints, draggedSphere, movePoint, activeLayer]); - - useFrame(() => { - if (!startPoint) return; + if ( + intersects.length > 0 && + intersects[0].object.name.includes("point") + ) { + gl.domElement.style.cursor = movePoint ? "pointer" : "default"; + } else { + gl.domElement.style.cursor = "default"; + } + if (isDragging && draggedSphere) { raycaster.setFromCamera(pointer, camera); const intersectionPoint = new THREE.Vector3(); const point = raycaster.ray.intersectPlane(plane, intersectionPoint); if (point) { - setEndPoint(point); + draggedSphere.set(point.x, 0.15, point.z); + + const sphereIndex = zonePoints.findIndex( + (point: any) => point === draggedSphere + ); + if (sphereIndex !== -1) { + const zoneIndex = Math.floor(sphereIndex / 4); + const cornerIndex = sphereIndex % 4; + + const updatedZones = zones.map((zone: any, index: number) => { + if (index === zoneIndex) { + const updatedPoints = [...zone.points]; + updatedPoints[cornerIndex] = [point.x, 0.15, point.z]; + updatedPoints[4] = updatedPoints[0]; + return { ...zone, points: updatedPoints }; + } + return zone; + }); + + setZones(updatedZones); + } } - }); - return ( - <group ref={groupsRef} name='zoneGroup' > - <group name="zones" visible={!toggleView}> - {zones - .map((zone: any) => ( - <group key={zone.zoneId} name={zone.zoneName}> - {zone.points.slice(0, -1).map((point: [number, number, number], index: number) => { - const nextPoint = zone.points[index + 1]; + } + }; - const point1 = new THREE.Vector3(point[0], point[1], point[2]); - const point2 = new THREE.Vector3(nextPoint[0], nextPoint[1], nextPoint[2]); + const onContext = (event: any) => { + event.preventDefault(); + setStartPoint(null); + setEndPoint(null); + }; - const planeWidth = point1.distanceTo(point2); - const planeHeight = CONSTANTS.zoneConfig.height; + if (toolMode === "Zone" || deletePointOrLine || movePoint) { + canvasElement.addEventListener("mousedown", onMouseDown); + canvasElement.addEventListener("mouseup", onMouseUp); + canvasElement.addEventListener("mousemove", onMouseMove); + canvasElement.addEventListener("contextmenu", onContext); + } + return () => { + canvasElement.removeEventListener("mousedown", onMouseDown); + canvasElement.removeEventListener("mouseup", onMouseUp); + canvasElement.removeEventListener("mousemove", onMouseMove); + canvasElement.removeEventListener("contextmenu", onContext); + }; + }, [ + gl, + camera, + startPoint, + toggleView, + scene, + toolMode, + zones, + isDragging, + deletePointOrLine, + zonePoints, + draggedSphere, + movePoint, + activeLayer, + ]); - const midpoint = new THREE.Vector3((point1.x + point2.x) / 2, (CONSTANTS.zoneConfig.height / 2) + ((zone.layer - 1) * CONSTANTS.zoneConfig.height), (point1.z + point2.z) / 2); + useFrame(() => { + if (!startPoint) return; + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + if (point) { + setEndPoint(point); + } + }); + return ( + <group ref={groupsRef} name="zoneGroup"> + <group name="zones" visible={!toggleView}> + {zones.map((zone: any) => ( + <group key={zone.zoneId} name={zone.zoneName}> + {zone.points + .slice(0, -1) + .map((point: [number, number, number], index: number) => { + const nextPoint = zone.points[index + 1]; - const angle = Math.atan2(point2.z - point1.z, point2.x - point1.x); + const point1 = new THREE.Vector3(point[0], point[1], point[2]); + const point2 = new THREE.Vector3( + nextPoint[0], + nextPoint[1], + nextPoint[2] + ); - return ( - <mesh - key={index} - position={midpoint} - rotation={[0, -angle, 0]} - > - <planeGeometry args={[planeWidth, planeHeight]} /> - <primitive - object={zoneMaterial.clone()} - attach="material" - /> - </mesh> - ); - })} - </group> - ))} - </group> - <group name='zoneLines' visible={toggleView}> - {zones - .filter((zone: any) => zone.layer === activeLayer) - .map((zone: any) => ( - <Line - key={zone.zoneId} - points={zone.points} - color="#007BFF" - lineWidth={3} - onClick={(e) => { - e.stopPropagation(); - if (deletePointOrLine) { - handleDeleteZone(zone.zoneId); - } - }} - /> - ))} - </group> - <group name="zonePoints" visible={toggleView}> - {zones.filter((zone: any) => zone.layer === activeLayer).flatMap((zone: any) => ( - zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( - <Sphere - key={`${zone.zoneId}-point-${pointIndex}`} - position={new THREE.Vector3(...point)} - args={[0.3, 16, 16]} - name={`point-${zone.zoneId}-${pointIndex}`} - > - <meshBasicMaterial color="red" /> - </Sphere> - )) - ))} - </group> - <group name="tempGroup" visible={toggleView}> - {startPoint && endPoint && ( - <Line - points={[ - [startPoint.x, 0.15, startPoint.z], - [endPoint.x, 0.15, startPoint.z], - [endPoint.x, 0.15, endPoint.z], - [startPoint.x, 0.15, endPoint.z], - [startPoint.x, 0.15, startPoint.z], - ]} - color="#C164FF" - lineWidth={3} + const planeWidth = point1.distanceTo(point2); + const planeHeight = CONSTANTS.zoneConfig.height; + + const midpoint = new THREE.Vector3( + (point1.x + point2.x) / 2, + CONSTANTS.zoneConfig.height / 2 + + (zone.layer - 1) * CONSTANTS.zoneConfig.height, + (point1.z + point2.z) / 2 + ); + + const angle = Math.atan2( + point2.z - point1.z, + point2.x - point1.x + ); + + return ( + <mesh + key={index} + position={midpoint} + rotation={[0, -angle, 0]} + > + <planeGeometry args={[planeWidth, planeHeight]} /> + <primitive + object={zoneMaterial.clone()} + attach="material" /> - )} - </group> - </group> - ); + </mesh> + ); + })} + </group> + ))} + </group> + <group name="zoneLines" visible={toggleView}> + {zones + .filter((zone: any) => zone.layer === activeLayer) + .map((zone: any) => ( + <Line + key={zone.zoneId} + points={zone.points} + color="#007BFF" + lineWidth={3} + onClick={(e) => { + e.stopPropagation(); + if (deletePointOrLine) { + handleDeleteZone(zone.zoneId); + } + }} + /> + ))} + </group> + <group name="zonePoints" visible={toggleView}> + {zones + .filter((zone: any) => zone.layer === activeLayer) + .flatMap((zone: any) => + zone.points.slice(0, 4).map((point: any, pointIndex: number) => ( + <Sphere + key={`${zone.zoneId}-point-${pointIndex}`} + position={new THREE.Vector3(...point)} + args={[0.3, 16, 16]} + name={`point-${zone.zoneId}-${pointIndex}`} + > + <meshBasicMaterial color="red" /> + </Sphere> + )) + )} + </group> + <group name="tempGroup" visible={toggleView}> + {startPoint && endPoint && ( + <Line + points={[ + [startPoint.x, 0.15, startPoint.z], + [endPoint.x, 0.15, startPoint.z], + [endPoint.x, 0.15, endPoint.z], + [startPoint.x, 0.15, endPoint.z], + [startPoint.x, 0.15, startPoint.z], + ]} + color="#C164FF" + lineWidth={3} + /> + )} + </group> + </group> + ); }; -export default ZoneGroup; \ No newline at end of file +export default ZoneGroup; diff --git a/app/src/modules/collaboration/socketResponses.dev.tsx b/app/src/modules/collaboration/socketResponses.dev.tsx index ceef567..6e578a1 100644 --- a/app/src/modules/collaboration/socketResponses.dev.tsx +++ b/app/src/modules/collaboration/socketResponses.dev.tsx @@ -105,7 +105,7 @@ export default function SocketResponses({ // console.log(`Getting ${data.data.modelname} from cache`); const model = cachedModel.scene.clone(); model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelFileID, modeluuid: data.data.modeluuid }; + model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; model.position.set(...data.data.position as [number, number, number]); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); @@ -159,7 +159,7 @@ export default function SocketResponses({ url = URL.createObjectURL(indexedDBModel); } else { // console.log(`Getting ${data.data.modelname} from Backend`); - url = `${url_Backend_dwinzo}/api/v1/AssetFile/${data.data.modelfileID}`; + url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`; const modelBlob = await fetch(url).then((res) => res.blob()); await storeGLTF(data.data.modelfileID, modelBlob); } @@ -179,7 +179,7 @@ export default function SocketResponses({ THREE.Cache.remove(url); const model = gltf.scene; model.uuid = data.data.modeluuid; - model.userData = { name: data.data.modelname, modelId: data.data.modelFileID, modeluuid: data.data.modeluuid }; + model.userData = { name: data.data.modelname, modelId: data.data.modelfileID, modeluuid: data.data.modeluuid }; model.position.set(...data.data.position as [number, number, number]); model.rotation.set(data.data.rotation.x, data.data.rotation.y, data.data.rotation.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap); diff --git a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts b/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts index c90fe3b..ea5ea74 100644 --- a/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts +++ b/app/src/modules/scene/IntialLoad/loadInitialFloorItems.ts @@ -12,7 +12,7 @@ import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAss async function loadInitialFloorItems( itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, - setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void + setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => void ): Promise<void> { if (!itemsGroup.current) return; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; @@ -82,16 +82,14 @@ async function loadInitialFloorItems( if (indexedDBModel) { // console.log(`[IndexedDB] Fetching ${item.modelname}`); const blobUrl = URL.createObjectURL(indexedDBModel); - loader.load( - blobUrl, - (gltf) => { - URL.revokeObjectURL(blobUrl); - THREE.Cache.remove(blobUrl); - THREE.Cache.add(item.modelfileID!, gltf); - processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates); - modelsLoaded++; - checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); - }, + loader.load(blobUrl, (gltf) => { + URL.revokeObjectURL(blobUrl); + THREE.Cache.remove(blobUrl); + THREE.Cache.add(item.modelfileID!, gltf); + processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates); + modelsLoaded++; + checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); + }, undefined, (error) => { toast.error(`[IndexedDB] Error loading ${item.modelname}:`); @@ -104,17 +102,15 @@ async function loadInitialFloorItems( // Fetch from Backend // console.log(`[Backend] Fetching ${item.modelname}`); - const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${item.modelfileID!}`; - loader.load( - modelUrl, - async (gltf) => { - const modelBlob = await fetch(modelUrl).then((res) => res.blob()); - await storeGLTF(item.modelfileID!, modelBlob); - THREE.Cache.add(item.modelfileID!, gltf); - processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates); - modelsLoaded++; - checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); - }, + const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.modelfileID!}`; + loader.load(modelUrl, async (gltf) => { + const modelBlob = await fetch(modelUrl).then((res) => res.blob()); + await storeGLTF(item.modelfileID!, modelBlob); + THREE.Cache.add(item.modelfileID!, gltf); + processLoadedModel(gltf.scene.clone(), item, itemsGroup, setFloorItems, setSimulationStates); + modelsLoaded++; + checkLoadingCompletion(modelsLoaded, modelsToLoad, dracoLoader, resolve); + }, undefined, (error) => { toast.error(`[Backend] Error loading ${item.modelname}:`); @@ -137,7 +133,7 @@ async function loadInitialFloorItems( }, ]); - if (item.eventData || item.modelfileID === '67e3db95c2e8f37134526fb2') { + if (item.eventData) { processEventData(item, setSimulationStates); } @@ -157,7 +153,7 @@ function processLoadedModel( item: Types.EventData, itemsGroup: Types.RefGroup, setFloorItems: Types.setFloorItemSetState, - setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema)[]) => void + setSimulationStates: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => void ) { const model = gltf; model.uuid = item.modeluuid; @@ -192,7 +188,7 @@ function processLoadedModel( }, ]); - if (item.eventData || item.modelfileID === '67e3db5ac2e8f37134526f40') { + if (item.eventData) { processEventData(item, setSimulationStates); } @@ -221,6 +217,7 @@ function processEventData(item: Types.EventData, setSimulationStates: any) { data.modeluuid = item.modeluuid; data.modelName = item.modelname; data.position = item.position; + data.rotation = [item.rotation.x, item.rotation.y, item.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), diff --git a/app/src/modules/scene/controls/selection/copyPasteControls.tsx b/app/src/modules/scene/controls/selection/copyPasteControls.tsx index d315c10..5af10c0 100644 --- a/app/src/modules/scene/controls/selection/copyPasteControls.tsx +++ b/app/src/modules/scene/controls/selection/copyPasteControls.tsx @@ -263,6 +263,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, @@ -315,6 +316,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), @@ -339,12 +341,14 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, uuid: THREE.MathUtils.generateUUID() } : defaultAction, + triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, connections: { source: { modelUUID: obj.uuid, pointUUID }, targets: [] @@ -415,6 +419,7 @@ const CopyPasteControls = ({ itemsGroupRef, copiedObjects, setCopiedObjects, pas return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, diff --git a/app/src/modules/scene/controls/selection/duplicationControls.tsx b/app/src/modules/scene/controls/selection/duplicationControls.tsx index 9c987d0..2964181 100644 --- a/app/src/modules/scene/controls/selection/duplicationControls.tsx +++ b/app/src/modules/scene/controls/selection/duplicationControls.tsx @@ -245,6 +245,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, @@ -297,6 +298,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => [ ...(prevEvents || []), @@ -321,12 +323,14 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, uuid: THREE.MathUtils.generateUUID() } : defaultAction, + triggers: { uuid: THREE.MathUtils.generateUUID(), name: 'Trigger 1', type: 'OnComplete' }, connections: { source: { modelUUID: obj.uuid, pointUUID }, targets: [] @@ -397,6 +401,7 @@ const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedOb return { uuid: pointUUID, position: vehiclePoint?.position, + rotation: vehiclePoint?.rotation, actions: hasActions ? { ...vehiclePoint.actions, diff --git a/app/src/modules/scene/controls/selection/moveControls.tsx b/app/src/modules/scene/controls/selection/moveControls.tsx index 97ddb17..2a11c53 100644 --- a/app/src/modules/scene/controls/selection/moveControls.tsx +++ b/app/src/modules/scene/controls/selection/moveControls.tsx @@ -279,6 +279,7 @@ function MoveControls({ movedObjects, setMovedObjects, itemsGroupRef, copiedObje newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => diff --git a/app/src/modules/scene/controls/selection/rotateControls.tsx b/app/src/modules/scene/controls/selection/rotateControls.tsx index 0680f28..90143ca 100644 --- a/app/src/modules/scene/controls/selection/rotateControls.tsx +++ b/app/src/modules/scene/controls/selection/rotateControls.tsx @@ -284,6 +284,7 @@ function RotateControls({ rotatedObjects, setRotatedObjects, movedObjects, setMo newEventData.modeluuid = newFloorItem.modeluuid; newEventData.modelName = newFloorItem.modelname; newEventData.position = newFloorItem.position; + newEventData.rotation = [obj.rotation.x, obj.rotation.y, obj.rotation.z]; setSimulationStates((prevEvents: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => { const updatedEvents = (prevEvents || []).map(event => diff --git a/app/src/modules/scene/controls/selection/selectionControls.tsx b/app/src/modules/scene/controls/selection/selectionControls.tsx index 686bf42..11c2dfb 100644 --- a/app/src/modules/scene/controls/selection/selectionControls.tsx +++ b/app/src/modules/scene/controls/selection/selectionControls.tsx @@ -122,10 +122,15 @@ const SelectionControls: React.FC = () => { if (!toggleView && activeModule === "builder") { helper.enabled = true; - canvasElement.addEventListener("pointerdown", onPointerDown); - canvasElement.addEventListener("pointermove", onPointerMove); + if (duplicatedObjects.length === 0 && pastedObjects.length === 0) { + canvasElement.addEventListener("pointerdown", onPointerDown); + canvasElement.addEventListener("pointermove", onPointerMove); + canvasElement.addEventListener("pointerup", onPointerUp); + } else { + helper.enabled = false; + helper.dispose(); + } canvasElement.addEventListener("contextmenu", onContextMenu); - canvasElement.addEventListener("pointerup", onPointerUp); canvasElement.addEventListener("keydown", onKeyDown); } else { helper.enabled = false; diff --git a/app/src/modules/simulation/path/pathConnector.tsx b/app/src/modules/simulation/path/pathConnector.tsx index bb4c039..c561cbb 100644 --- a/app/src/modules/simulation/path/pathConnector.tsx +++ b/app/src/modules/simulation/path/pathConnector.tsx @@ -952,8 +952,17 @@ function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObjec ); }) }, - // Ensure all required ArmBot point properties are included - actions: state.points.actions, + actions: { + ...state.points.actions, + processes: state.points.actions.processes?.filter(process => { + return !( + process.startPoint === connection1.point || + process.endPoint === connection1.point || + process.startPoint === connection2.point || + process.endPoint === connection2.point + ); + }) || [] + }, triggers: state.points.triggers } }; diff --git a/app/src/modules/visualization/captureVisualization.ts b/app/src/modules/visualization/captureVisualization.ts index 01d67a0..7cf7bc5 100644 --- a/app/src/modules/visualization/captureVisualization.ts +++ b/app/src/modules/visualization/captureVisualization.ts @@ -1,55 +1,22 @@ +// import html2canvas from "html2canvas"; + export const captureVisualization = async (): Promise<string | null> => { - const container = document.getElementById("real-time-vis-canvas"); - if (!container) return null; + const container = document.getElementById("real-time-vis-canvas"); + if (!container) return null; - const canvas = document.createElement("canvas"); - const ctx = canvas.getContext("2d"); - if (!ctx) return null; + try { + // Use html2canvas to capture the container + // const canvas = await html2canvas(container, { + // scale: 1, // Adjust scale for higher/lower resolution + // }); - const rect = container.getBoundingClientRect(); - canvas.width = rect.width; - canvas.height = rect.height; + // // Convert the canvas to a data URL (PNG format) + // const dataUrl = canvas.toDataURL("image/png"); + // return dataUrl; - // Draw background - ctx.fillStyle = getComputedStyle(container).backgroundColor; - ctx.fillRect(0, 0, canvas.width, canvas.height); - - // Capture all canvas elements - const canvases = container.querySelectorAll("canvas"); - canvases.forEach((childCanvas) => { - const childRect = childCanvas.getBoundingClientRect(); - const x = childRect.left - rect.left; - const y = childRect.top - rect.top; - ctx.drawImage(childCanvas, x, y, childRect.width, childRect.height); - }); - - // Capture SVG elements - const svgs = container.querySelectorAll("svg"); - for (const svg of Array.from(svgs)) { - const svgString = new XMLSerializer().serializeToString(svg); - const svgBlob = new Blob([svgString], { type: "image/svg+xml" }); - const url = URL.createObjectURL(svgBlob); - - try { - const img = await new Promise<HTMLImageElement>((resolve, reject) => { - const image = new Image(); - image.onload = () => resolve(image); - image.onerror = reject; - image.src = url; - }); - - const svgRect = svg.getBoundingClientRect(); - ctx.drawImage( - img, - svgRect.left - rect.left, - svgRect.top - rect.top, - svgRect.width, - svgRect.height - ); - } finally { - URL.revokeObjectURL(url); - } - } - - return canvas.toDataURL("image/png"); + return null; + } catch (error) { + console.error("Error capturing visualization:", error); + return null; + } }; diff --git a/app/src/modules/visualization/handleSaveTemplate.ts b/app/src/modules/visualization/handleSaveTemplate.ts index f192bec..6fc5a3e 100644 --- a/app/src/modules/visualization/handleSaveTemplate.ts +++ b/app/src/modules/visualization/handleSaveTemplate.ts @@ -28,10 +28,10 @@ export const handleSaveTemplate = async ({ templates = [], visualizationSocket, }: HandleSaveTemplateProps): Promise<void> => { + console.log('floatingWidget: ', floatingWidget); try { // Check if the selected zone has any widgets if (!selectedZone.panelOrder || selectedZone.panelOrder.length === 0) { - console.warn("No widgets found in the selected zone."); return; } @@ -49,7 +49,8 @@ export const handleSaveTemplate = async ({ } // Capture visualization snapshot - const snapshot = await captureVisualization(); + // const snapshot = await captureVisualization(); + const snapshot = null; // if (!snapshot) { // return; @@ -64,8 +65,7 @@ export const handleSaveTemplate = async ({ floatingWidget, widgets3D, }; - - console.log('newTemplate: ', newTemplate); + // Extract organization from email const email = localStorage.getItem("email") || ""; const organization = email.includes("@") @@ -73,7 +73,6 @@ export const handleSaveTemplate = async ({ : ""; if (!organization) { - console.error("Organization could not be determined from email."); return; } let saveTemplate = { @@ -88,13 +87,13 @@ export const handleSaveTemplate = async ({ try { addTemplate(newTemplate); // const response = await saveTemplateApi(organization, newTemplate); - // console.log("Save API Response:", response); + // // Add template only if API call succeeds } catch (apiError) { - // console.error("Error saving template to API:", apiError); + // } } catch (error) { - // console.error("Error in handleSaveTemplate:", error); + // } }; diff --git a/app/src/modules/visualization/realTimeVizSocket.dev.tsx b/app/src/modules/visualization/realTimeVizSocket.dev.tsx index 9ee6b5b..f1abaaa 100644 --- a/app/src/modules/visualization/realTimeVizSocket.dev.tsx +++ b/app/src/modules/visualization/realTimeVizSocket.dev.tsx @@ -15,22 +15,19 @@ type WidgetData = { export default function SocketRealTimeViz() { const { visualizationSocket } = useSocketStore(); - const { selectedZone, setSelectedZone } = useSelectedZoneStore(); + const { setSelectedZone } = useSelectedZoneStore(); const deleteObject = useDroppedObjectsStore((state) => state.deleteObject); - const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject); const updateObjectPosition = useDroppedObjectsStore((state) => state.updateObjectPosition); const { addWidget } = useZoneWidgetStore() - const { templates, removeTemplate } = useTemplateStore(); + const { removeTemplate } = useTemplateStore(); const { setTemplates } = useTemplateStore(); const { zoneWidgetData, setZoneWidgetData, updateWidgetPosition, updateWidgetRotation } = useZoneWidgetStore(); useEffect(() => { - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0]; if (visualizationSocket) { //add panel response visualizationSocket.on("viz-panel:response:updates", (addPanel: any) => { - console.log('addPanel: ', addPanel); + if (addPanel.success) { let addPanelData = addPanel.data.data setSelectedZone(addPanelData) @@ -38,15 +35,33 @@ export default function SocketRealTimeViz() { }) //delete panel response visualizationSocket.on("viz-panel:response:delete", (deletePanel: any) => { - console.log('deletePanel: ', deletePanel); + if (deletePanel.success) { let deletePanelData = deletePanel.data.data setSelectedZone(deletePanelData) } }) + //clear Panel response + visualizationSocket.on("viz-panel:response:clear", (clearPanel: any) => { + + if (clearPanel.success && clearPanel.message === "PanelWidgets cleared successfully") { + + let clearPanelData = clearPanel.data.data + setSelectedZone(clearPanelData) + } + }) + //lock Panel response + visualizationSocket.on("viz-panel:response:locked", (lockPanel: any) => { + + if (lockPanel.success && lockPanel.message === "locked panel updated successfully") { + + let lockPanelData = lockPanel.data.data + setSelectedZone(lockPanelData) + } + }) // add 2dWidget response visualizationSocket.on("viz-widget:response:updates", (add2dWidget: any) => { - console.log('add2dWidget: ', add2dWidget); + if (add2dWidget.success && add2dWidget.data) { setSelectedZone((prev) => { @@ -65,7 +80,7 @@ export default function SocketRealTimeViz() { }); //delete 2D Widget response visualizationSocket.on("viz-widget:response:delete", (deleteWidget: any) => { - console.log('deleteWidget: ', deleteWidget); + if (deleteWidget?.success && deleteWidget.data) { setSelectedZone((prevZone: any) => ({ @@ -78,7 +93,7 @@ export default function SocketRealTimeViz() { }); //add Floating Widget response visualizationSocket.on("viz-float:response:updates", (addFloatingWidget: any) => { - console.log('addFloatingWidget: ', addFloatingWidget); + if (addFloatingWidget.success) { if (addFloatingWidget.success && addFloatingWidget.message === "FloatWidget created successfully") { @@ -105,7 +120,7 @@ export default function SocketRealTimeViz() { }); //duplicate Floating Widget response visualizationSocket.on("viz-float:response:addDuplicate", (duplicateFloatingWidget: any) => { - console.log('duplicateFloatingWidget: ', duplicateFloatingWidget); + if (duplicateFloatingWidget.success && duplicateFloatingWidget.message === "duplicate FloatWidget created successfully") { useDroppedObjectsStore.setState((state) => { @@ -133,7 +148,7 @@ export default function SocketRealTimeViz() { }); //delete Floating Widget response visualizationSocket.on("viz-float:response:delete", (deleteFloatingWidget: any) => { - console.log('deleteFloatingWidget: ', deleteFloatingWidget); + if (deleteFloatingWidget.success) { deleteObject(deleteFloatingWidget.data.zoneName, deleteFloatingWidget.data.floatWidgetID); @@ -142,9 +157,9 @@ export default function SocketRealTimeViz() { //add 3D Widget response visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => { - console.log('add3DWidget: ', add3DWidget); + if (add3DWidget.success) { - console.log('add3DWidget: ', add3DWidget); + if (add3DWidget.message === "Widget created successfully") { addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget); } @@ -152,7 +167,7 @@ export default function SocketRealTimeViz() { }); //delete 3D Widget response visualizationSocket.on("viz-widget3D:response:delete", (delete3DWidget: any) => { - console.log('delete3DWidget: ', delete3DWidget); + // "3DWidget delete unsuccessfull" if (delete3DWidget.success && delete3DWidget.message === "3DWidget delete successfull") { const activeZoneWidgets = zoneWidgetData[delete3DWidget.data.zoneId] || []; @@ -164,16 +179,16 @@ export default function SocketRealTimeViz() { }); //update3D widget response visualizationSocket.on("viz-widget3D:response:modifyPositionRotation", (update3DWidget: any) => { - console.log('update3DWidget: ', update3DWidget); - - if (update3DWidget.success && update3DWidget.message==="widget update successfully") { + + + if (update3DWidget.success && update3DWidget.message === "widget update successfully") { updateWidgetPosition(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.position); updateWidgetRotation(update3DWidget.data.zoneId, update3DWidget.data.widget.id, update3DWidget.data.widget.rotation); } }); // add Template response visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => { - console.log('addingTemplate: ', addingTemplate); + if (addingTemplate.success) { if (addingTemplate.message === "Template saved successfully") { @@ -183,7 +198,7 @@ export default function SocketRealTimeViz() { }); //load Template response visualizationSocket.on("viz-template:response:addTemplateZone", (loadTemplate: any) => { - console.log('loadTemplate: ', loadTemplate); + if (loadTemplate.success) { if (loadTemplate.message === "Template placed in Zone") { @@ -206,14 +221,12 @@ export default function SocketRealTimeViz() { }); //delete Template response visualizationSocket.on("viz-template:response:delete", (deleteTemplate: any) => { - console.log('deleteTemplate: ', deleteTemplate); + if (deleteTemplate.success) { if (deleteTemplate.message === 'Template deleted successfully') { removeTemplate(deleteTemplate.data); } - - } }); } diff --git a/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts b/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts index 4ccb6e9..ae7aaa4 100644 --- a/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts +++ b/app/src/services/factoryBuilder/assest/assets/getAssetModel.ts @@ -2,7 +2,7 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL} export const getAssetModel = async (modelId: string) => { try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/AssetFile/${modelId}`, { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${modelId}`, { method: "GET", headers: { "Content-Type": "application/json", diff --git a/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts index 7a0290a..7c78c41 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts +++ b/app/src/services/factoryBuilder/assest/floorAsset/getFloorItemsApi.ts @@ -1,5 +1,6 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; + export const getFloorAssets = async (organization: string) => { try { const response = await fetch(`${url_Backend_dwinzo}/api/v2/floorAssets/${organization}`, { @@ -14,6 +15,7 @@ export const getFloorAssets = async (organization: string) => { } const result = await response.json(); + return result; } catch (error) { if (error instanceof Error) { diff --git a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts index e25e05e..3e156cb 100644 --- a/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts +++ b/app/src/services/factoryBuilder/assest/floorAsset/setFloorItemApi.ts @@ -1,14 +1,13 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; - export const setFloorItemApi = async ( organization: string, - modeluuid: string, - modelname: string, - modelfileID: string, - position: Object, - rotation: Object, - isLocked: boolean, - isVisible: boolean, + modeluuid?: string, + modelname?: string, + modelfileID?: string, + position?: Object, + rotation?: Object, + isLocked?: boolean, + isVisible?: boolean, eventData?: any ) => { try { diff --git a/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js b/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js index 2fbdc13..9e7397d 100644 --- a/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js +++ b/app/src/services/factoryBuilder/webWorkers/gltfLoaderWorker.js @@ -26,7 +26,7 @@ onmessage = async (event) => { const message = "gltfLoaded"; postMessage({ message, modelID, modelBlob }); } else { - const modelUrl = `${url_Backend_dwinzo}/api/v1/AssetFile/${modelID}`; + const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${modelID}`; const modelBlob = await fetch(modelUrl).then((res) => res.blob()); await storeGLTF(modelID, modelBlob); const message = "gltfLoaded"; diff --git a/app/src/services/factoryBuilder/zones/getZonesApi.ts b/app/src/services/factoryBuilder/zones/getZonesApi.ts index be7741c..413458c 100644 --- a/app/src/services/factoryBuilder/zones/getZonesApi.ts +++ b/app/src/services/factoryBuilder/zones/getZonesApi.ts @@ -1,4 +1,5 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getZonesApi = async (organization: string) => { try { diff --git a/app/src/services/realTimeVisulization/zoneData/clearPanel.ts b/app/src/services/realTimeVisulization/zoneData/clearPanel.ts new file mode 100644 index 0000000..6e1f1d1 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/clearPanel.ts @@ -0,0 +1,30 @@ +// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const clearPanel = async ( + zoneId: string, + organization: string, + panelName: string +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/clearpanel`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneId, panelName }), + }); + + if (!response.ok) { + throw new Error("Failed to clearPanel in the zone"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/lockPanel.ts b/app/src/services/realTimeVisulization/zoneData/lockPanel.ts new file mode 100644 index 0000000..4b5898f --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/lockPanel.ts @@ -0,0 +1,30 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const lockPanel = async ( + zoneId: string, + organization: string, + lockedPanel: any +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/zones/lockedPanels`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneId, lockedPanel }), + }); + + if (!response.ok) { + throw new Error("Failed to Lock Panel in the zone"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; \ No newline at end of file diff --git a/app/src/services/realTimeVisulization/zoneData/update3dWidget.ts b/app/src/services/realTimeVisulization/zoneData/update3dWidget.ts index 553fc68..cb37a7f 100644 --- a/app/src/services/realTimeVisulization/zoneData/update3dWidget.ts +++ b/app/src/services/realTimeVisulization/zoneData/update3dWidget.ts @@ -9,20 +9,16 @@ export const update3dWidget = async ( console.log("organization: ", organization); console.log("zoneId: ", zoneId); try { - const response = await fetch( - `${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`, - { - method: "PATCH", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - organization, - zoneId, - id, - position, - }), - } + const response = await fetch(`${url_Backend_dwinzo}/api/v2/modifyPR/widget3D`, { + method: "PATCH", + headers: { "Content-Type": "application/json", }, + body: JSON.stringify({ + organization, + zoneId, + id, + position, + }), + } ); if (!response.ok) { diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 57fd6a6..8810dbe 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -68,7 +68,11 @@ export const useWalls = create<any>((set: any) => ({ export const useZones = create<any>((set: any) => ({ zones: [], - setZones: (x: any) => set(() => ({ zones: x })), + setZones: (callback: any) => + set((state: any) => ({ + zones: + typeof callback === 'function' ? callback(state.zones) : callback + })) })); interface ZonePointsState { diff --git a/app/src/styles/components/visualization/floating/common.scss b/app/src/styles/components/visualization/floating/common.scss index 7c74d54..94ea379 100644 --- a/app/src/styles/components/visualization/floating/common.scss +++ b/app/src/styles/components/visualization/floating/common.scss @@ -81,9 +81,12 @@ .returnOfInvestment { gap: 10px; + min-width: 150px; .charts { + width: 100%; height: 200px; + min-width: 150px; } .returns-wrapper { @@ -126,6 +129,12 @@ gap: 6px; border-radius: 5.2px; + width: 100%; + height: 150px; + display: flex; + justify-content: center; + align-items: center; + .header { font-size: $small; text-align: start; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index f334fff..19cd2b4 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -75,6 +75,7 @@ max-width: 80%; overflow: auto; max-width: calc(100% - 500px); + min-width: 150px; z-index: 3; transform: translate(-50%, -10%); @@ -363,6 +364,7 @@ } .panel.hidePanel { + pointer-events: none; opacity: 0.1; } } diff --git a/app/src/types/world/worldTypes.d.ts b/app/src/types/world/worldTypes.d.ts index 25ef4b6..fefca2a 100644 --- a/app/src/types/world/worldTypes.d.ts +++ b/app/src/types/world/worldTypes.d.ts @@ -310,11 +310,13 @@ interface VehicleEventsSchema { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; speed: number; }; position: [number, number, number]; + rotation: [number, number, number]; } interface StaticMachineEventsSchema { @@ -324,6 +326,7 @@ interface StaticMachineEventsSchema { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; buffer: number; material: string; }; triggers: { uuid: string; name: string; type: string }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; @@ -339,6 +342,7 @@ interface ArmBotEventsSchema { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] }; triggers: { uuid: string; name: string; type: string }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; @@ -371,6 +375,7 @@ export type EventData = { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; type: string; start: { x: number, y: number } | {}, hitCount: number, end: { x: number, y: number } | {}, buffer: number }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; speed: number; @@ -380,6 +385,7 @@ export type EventData = { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; buffer: number; material: string; }; triggers: { uuid: string; name: string; type: string }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; @@ -389,6 +395,7 @@ export type EventData = { points: { uuid: string; position: [number, number, number]; + rotation: [number, number, number]; actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[] }; triggers: { uuid: string; name: string; type: string }; connections: { source: { modelUUID: string; pointUUID: string }; targets: { modelUUID: string; pointUUID: string }[] }; diff --git a/app/src/utils/shortcutkeys/handleShortcutKeys.ts b/app/src/utils/shortcutkeys/handleShortcutKeys.ts index 73388d5..e3c484b 100644 --- a/app/src/utils/shortcutkeys/handleShortcutKeys.ts +++ b/app/src/utils/shortcutkeys/handleShortcutKeys.ts @@ -148,11 +148,10 @@ const KeyPressListener: React.FC = () => { setActiveTool("draw-floor"); setToolMode("Floor"); } - } else { - if (keyCombination === "M") { - setActiveTool("measure"); - setToolMode("MeasurementScale"); - } + } + if (keyCombination === "M") { + setActiveTool("measure"); + setToolMode("MeasurementScale"); } }