From 21d96a31bc56542cc1762f81c8069d96f90f273e Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Tue, 1 Apr 2025 08:58:56 +0530 Subject: [PATCH 01/14] searching filtered assets --- .../components/layout/sidebarLeft/Assets.tsx | 104 ++++++++++++----- .../analysis/RenderAnalysisInputs.tsx | 1 + .../properties/GlobalProperties.tsx | 105 +++++++++++++++--- app/src/components/ui/inputs/InputRange.tsx | 29 ++++- app/src/modules/market/Card.tsx | 1 + app/src/modules/market/FilterSearch.tsx | 1 - app/src/modules/scene/world/world.tsx | 6 + .../environment/findEnvironment.ts | 63 ++++++----- .../environment/setEnvironment.ts | 63 +++++++---- app/src/services/marketplace/fetchAssets.ts | 4 +- app/src/store/store.ts | 14 ++- app/src/styles/components/input.scss | 2 +- .../components/marketPlace/marketPlace.scss | 4 +- app/src/styles/layout/sidebar.scss | 49 ++++++++ 14 files changed, 342 insertions(+), 104 deletions(-) diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index f8733dc..6005546 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -9,12 +9,13 @@ import { getCategoryAsset } from "../../../services/factoryBuilder/assest/assets import arch from "../../../assets/gltf-glb/arch.glb"; import door from "../../../assets/gltf-glb/door.glb"; import window from "../../../assets/gltf-glb/window.glb"; +import { fetchAssets } from "../../../services/marketplace/fetchAssets"; interface AssetProp { filename: string; thumbnail?: string; category: string; description?: string; - tags?: string; + tags: string; url?: String; uploadDate?: number; isArchieve?: boolean; @@ -25,12 +26,27 @@ interface AssetProp { const Assets: React.FC = () => { const [searchValue, setSearchValue] = useState(""); const [selectedCategory, setSelectedCategory] = useState(null); - const [filteredAsset, setFilteredAsset] = useState([]); + const [categoryAssets, setCategoryAssets] = useState([]); + const [filtereredAssets, setFiltereredAssets] = useState([]); const handleSearchChange = (value: string) => { setSearchValue(value); - setSelectedCategory(null); // Reset selected category when search changes + setSelectedCategory(null); + const filteredModels = filtereredAssets?.filter((model) => + model.filename.toLowerCase().includes(value.toLowerCase()) + ); + + setCategoryAssets(filteredModels); }; + useEffect(() => { + const filteredAssets = async () => { + try { + const filt = await fetchAssets(); + setFiltereredAssets(filt); + } catch {} + }; + filteredAssets(); + }, []); const categoryList = useMemo( () => [ @@ -68,56 +84,53 @@ const Assets: React.FC = () => { filename: "arch", category: "Feneration", url: arch, + tags: "arch", }, { filename: "door", category: "Feneration", url: door, + thumbnail: feneration, + tags: "door", }, { filename: "window", category: "Feneration", url: window, + tags: "window", }, ]; - setFilteredAsset(localAssets); + setCategoryAssets(localAssets); + setFiltereredAssets(localAssets); } else { try { const res = await getCategoryAsset(asset); - setFilteredAsset(res || []); // Ensure it's always an array + setCategoryAssets(res || []); // Ensure it's always an array + setFiltereredAssets(res || []); } catch (error) {} } }; - useEffect(() => {}, [filteredAsset]); return (
{searchValue ? ( -
-

Results for "{searchValue}"

-
- ) : selectedCategory ? ( -
- {/* Back Button */} -
setSelectedCategory(null)} - > - ← Back +
+
+
+

Results for "{searchValue}"

+
-

{selectedCategory}

- {filteredAsset && - filteredAsset?.map((asset: any, index: number) => ( + {categoryAssets && + categoryAssets?.map((asset: any, index: number) => (
- {asset?.thumbnail && ( - {asset.filename} - )} + {asset.filename} +
{asset.filename .split("_") @@ -131,6 +144,43 @@ const Assets: React.FC = () => { ))}
+ ) : selectedCategory ? ( +
+ {/* Back Button */} +
{ + setSelectedCategory(null); + setCategoryAssets([]); + }} + > + ← Back +
+

{selectedCategory}

+
+ {searchValue || + (categoryAssets && + categoryAssets?.map((asset: any, index: number) => ( +
+ {asset.filename} + +
+ {asset.filename + .split("_") + .map( + (word: any) => + word.charAt(0).toUpperCase() + word.slice(1) + ) + .join(" ")} +
+
+ )))} +
+
) : (

Categories

diff --git a/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx b/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx index 3ab886f..e14b542 100644 --- a/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx +++ b/app/src/components/layout/sidebarRight/analysis/RenderAnalysisInputs.tsx @@ -33,6 +33,7 @@ const RenderAnalysisInputs: React.FC = ({ label={preset.inputs.label} min={0} max={0} + value={5} /> ); } diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index bd7e5c1..d65a10c 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import InputRange from "../../../ui/inputs/InputRange"; import InputToggle from "../../../ui/inputs/InputToggle"; import { AI_Icon } from "../../../icons/ExportCommonIcons"; @@ -6,6 +6,7 @@ import LabeledButton from "../../../ui/inputs/LabledButton"; import { useAzimuth, useElevation, + useLimitDistance, useRenderDistance, useResetCamera, useRoofVisibility, @@ -17,6 +18,7 @@ import { } from "../../../../store/store"; import { setEnvironment } from "../../../../services/factoryBuilder/environment/setEnvironment"; import * as CONSTANTS from "../../../../types/world/worldConstants"; +import { validateBBox } from "@turf/helpers"; const GlobalProperties: React.FC = () => { const { toggleView, setToggleView } = useToggleView(); const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem(); @@ -27,27 +29,83 @@ const GlobalProperties: React.FC = () => { const { elevation, setElevation } = useElevation(); const { azimuth, setAzimuth } = useAzimuth(); const { renderDistance, setRenderDistance } = useRenderDistance(); + const { socket } = useSocketStore(); - const [limitDistance, setLimitDistance] = useState(false); - const [distance, setDistance] = useState(30); + const { limitDistance, setLimitDistance } = useLimitDistance(); + const [distance, setDistance] = useState(40); + useEffect(() => {}, [limitDistance]); const [limitGridDistance, setLimitGridDistance] = useState(false); const [gridDistance, setGridDistance] = useState(5); - function optimizeScene() { + const optimizeScene = async (value: any) => { + const email = localStorage.getItem("email"); + const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg"; + + const data = await setEnvironment( + organization, + localStorage.getItem("userId")!, + wallVisibility, + roofVisibility, + shadows, + 30, + true + ); + setRenderDistance(30); setLimitDistance(true); - setDistance(30); - } + }; + const limitRenderDistance = async () => { + const email = localStorage.getItem("email"); + const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg"; + + if (limitDistance) { + let data = await setEnvironment( + organization, + localStorage.getItem("userId")!, + wallVisibility, + roofVisibility, + shadows, + 75, + !limitDistance + ); + setRenderDistance(75); + } else { + let data = await setEnvironment( + organization, + localStorage.getItem("userId")!, + wallVisibility, + roofVisibility, + shadows, + renderDistance, + !limitDistance + ); + } + setLimitDistance(!limitDistance); + }; function updateDistance(value: number) { - console.log("value: ", value); setDistance(value); setRenderDistance(value); } - function updateGridDistance(value: number) { setGridDistance(value); } + const updatedDist = async (value: number) => { + const email = localStorage.getItem("email"); + const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg"; + setRenderDistance(value); + // setDistance(value); + const data = await setEnvironment( + organization, + localStorage.getItem("userId")!, + wallVisibility, + roofVisibility, + shadows, + value, + limitDistance + ); + }; + // Function to toggle roof visibility const changeRoofVisibility = async () => { const email = localStorage.getItem("email"); @@ -59,9 +117,11 @@ const GlobalProperties: React.FC = () => { localStorage.getItem("userId")!, wallVisibility, !roofVisibility, - shadows + shadows, + renderDistance, + limitDistance ); - // console.log('data: ', data); + // //using Socket // const visData = { @@ -86,9 +146,11 @@ const GlobalProperties: React.FC = () => { localStorage.getItem("userId")!, !wallVisibility, roofVisibility, - shadows + shadows, + renderDistance, + limitDistance ); - // console.log('data: ', data); + // //using Socket // const visData = { @@ -113,9 +175,11 @@ const GlobalProperties: React.FC = () => { localStorage.getItem("userId")!, wallVisibility, roofVisibility, - !shadows + !shadows, + renderDistance, + limitDistance ); - // console.log('data: ', data); + // //using Socket // const visData = { @@ -185,18 +249,23 @@ const GlobalProperties: React.FC = () => { inputKey="4" label="Limit Render Distance" value={limitDistance} - onClick={() => { - setLimitDistance(!limitDistance); + // onClick={() => { + // setLimitDistance(!limitDistance); + // // setDistance(75); + // // setRenderDistance(75); + // }} + onClick={async () => { + await limitRenderDistance(); // Call the function here }} /> updateDistance(value)} + onPointerUp={updatedDist} />
diff --git a/app/src/components/ui/inputs/InputRange.tsx b/app/src/components/ui/inputs/InputRange.tsx index a09a782..51c8b1a 100644 --- a/app/src/components/ui/inputs/InputRange.tsx +++ b/app/src/components/ui/inputs/InputRange.tsx @@ -8,6 +8,7 @@ interface InputToggleProps { onChange?: (value: number) => void; // Function to handle toggle clicks disabled?: boolean; value?: number; + onPointerUp?: (value: number) => void; } const InputRange: React.FC = ({ @@ -17,9 +18,10 @@ const InputRange: React.FC = ({ min, max, disabled, - value = 5, + value, + onPointerUp, }) => { - const [rangeValue, setRangeValue] = useState(value); + const [rangeValue, setRangeValue] = useState(value ? value : 5); function handleChange(e: React.ChangeEvent) { const newValue = parseInt(e.target.value); // Parse the value to an integer @@ -31,8 +33,22 @@ const InputRange: React.FC = ({ } } useEffect(() => { - setRangeValue(value); + value && setRangeValue(value); }, [value]); + function handlePointerUp(e: React.PointerEvent) { + const newValue = parseInt(e.currentTarget.value, 10); // Parse value correctly + + if (onPointerUp) { + onPointerUp(newValue); // Call the callback function if it exists + } + } + function handlekey(e: React.KeyboardEvent) { + const newValue = parseInt(e.currentTarget.value, 10); // Parse value correctly + + if (onPointerUp) { + onPointerUp(newValue); // Call the callback function if it exists + } + } return (
@@ -52,6 +68,7 @@ const InputRange: React.FC = ({ onChange={handleChange} disabled={disabled} value={rangeValue} + onPointerUp={handlePointerUp} /> = ({ value={rangeValue} onChange={handleChange} disabled={disabled} + onKeyUp={(e) => { + if (e.key === "ArrowUp" || e.key === "ArrowDown") { + console.log("e.key: ", e.key); + handlekey(e); + } + }} />
diff --git a/app/src/modules/market/Card.tsx b/app/src/modules/market/Card.tsx index ec9db06..c1a3289 100644 --- a/app/src/modules/market/Card.tsx +++ b/app/src/modules/market/Card.tsx @@ -38,6 +38,7 @@ const Card: React.FC = ({ description, onSelectCard, }) => { + console.log('description: ', description); const handleCardSelect = () => { onSelectCard({ assetName, uploadedOn, price, rating, views, description }); }; diff --git a/app/src/modules/market/FilterSearch.tsx b/app/src/modules/market/FilterSearch.tsx index 630942d..de518c8 100644 --- a/app/src/modules/market/FilterSearch.tsx +++ b/app/src/modules/market/FilterSearch.tsx @@ -57,7 +57,6 @@ const FilterSearch: React.FC = ({ const filteredModel = filteredModels?.filter((model) => model.filename.toLowerCase().includes(val.toLowerCase()) ); - setModels(filteredModel); }; diff --git a/app/src/modules/scene/world/world.tsx b/app/src/modules/scene/world/world.tsx index eb7d555..5864ec8 100644 --- a/app/src/modules/scene/world/world.tsx +++ b/app/src/modules/scene/world/world.tsx @@ -30,6 +30,8 @@ import { useWalls, useToolMode, useRefTextUpdate, + useRenderDistance, + useLimitDistance, } from "../../../store/store"; ////////// 3D Function Imports ////////// @@ -117,6 +119,8 @@ export default function World() { const { roofVisibility, setRoofVisibility } = useRoofVisibility(); const { wallVisibility, setWallVisibility } = useWallVisibility(); const { shadows, setShadows } = useShadows(); + const { renderDistance, setRenderDistance } = useRenderDistance(); + const { limitDistance, setLimitDistance } = useLimitDistance(); const { updateScene, setUpdateScene } = useUpdateScene(); const { walls, setWalls } = useWalls(); const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); @@ -200,6 +204,8 @@ export default function World() { setRoofVisibility(visibility.roofVisibility); setWallVisibility(visibility.wallVisibility); setShadows(visibility.shadowVisibility); + setRenderDistance(visibility.renderDistance); + setLimitDistance(visibility.limitDistance); } } fetchVisibility(); diff --git a/app/src/services/factoryBuilder/environment/findEnvironment.ts b/app/src/services/factoryBuilder/environment/findEnvironment.ts index 525bdda..de5b6a6 100644 --- a/app/src/services/factoryBuilder/environment/findEnvironment.ts +++ b/app/src/services/factoryBuilder/environment/findEnvironment.ts @@ -1,32 +1,43 @@ -import { setEnvironment } from './setEnvironment'; +import { setEnvironment } from "./setEnvironment"; let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; export const findEnvironment = async (organization: string, userId: string) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/findEnvironments/${organization}/${userId}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v1/findEnvironments/${organization}/${userId}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); - if (!response.ok) { - throw new Error("Failed to get wall and roof visibility"); - } - - const result = await response.json(); - if (result === "user not found") { - const userpos = setEnvironment(organization, userId, false, false, false); - return userpos; - } else { - return result; - } - } catch (error) { - if (error instanceof Error) { - throw new Error(error.message); - } else { - throw new Error("An unknown error occurred"); - } + if (!response.ok) { + throw new Error("Failed to get wall and roof visibility"); } -}; \ No newline at end of file + + const result = await response.json(); + if (result === "user not found") { + const userpos = setEnvironment( + organization, + userId, + false, + false, + false, + 0, + true + ); + return userpos; + } else { + 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/factoryBuilder/environment/setEnvironment.ts b/app/src/services/factoryBuilder/environment/setEnvironment.ts index 070146f..1f72959 100644 --- a/app/src/services/factoryBuilder/environment/setEnvironment.ts +++ b/app/src/services/factoryBuilder/environment/setEnvironment.ts @@ -1,26 +1,45 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; -export const setEnvironment = async (organization: string, userId: string, wallVisibility: Boolean, roofVisibility: Boolean, shadowVisibility: Boolean) => { - try { - const response = await fetch(`${url_Backend_dwinzo}/api/v1/setEvironments`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ organization, userId, wallVisibility, roofVisibility, shadowVisibility }), - }); +export const setEnvironment = async ( + organization: string, + userId: string, + wallVisibility: Boolean, + roofVisibility: Boolean, + shadowVisibility: Boolean, + renderDistance: number, + limitDistance: boolean +) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v1/setEvironments`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + organization, + userId, + wallVisibility, + roofVisibility, + shadowVisibility, + renderDistance, + limitDistance, + }), + } + ); - if (!response.ok) { - throw new Error("Failed to set wall and roof visibility"); - } - - 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"); - } + if (!response.ok) { + throw new Error("Failed to set wall and roof visibility"); } -}; \ No newline at end of file + + 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/marketplace/fetchAssets.ts b/app/src/services/marketplace/fetchAssets.ts index e434a2b..7a395f9 100644 --- a/app/src/services/marketplace/fetchAssets.ts +++ b/app/src/services/marketplace/fetchAssets.ts @@ -6,8 +6,8 @@ export const fetchAssets = async () => { throw new Error("Network response was not ok"); } const result = await response.json(); - const last10Assets = result.slice(-10); - console.log('last10Assets: ', last10Assets); + // const last10Assets = result.slice(-10); + // console.log('last10Assets: ', last10Assets); return result; } catch (error) { console.log("error: ", error); diff --git a/app/src/store/store.ts b/app/src/store/store.ts index a64f417..fe35801 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -208,7 +208,9 @@ export const useActiveLayer = create((set: any) => ({ interface RefTextUpdateState { refTextupdate: number; - setRefTextUpdate: (callback: (currentValue: number) => number | number) => void; + setRefTextUpdate: ( + callback: (currentValue: number) => number | number + ) => void; } export const useRefTextUpdate = create((set) => ({ @@ -216,7 +218,9 @@ export const useRefTextUpdate = create((set) => ({ setRefTextUpdate: (callback) => set((state) => ({ refTextupdate: - typeof callback === "function" ? callback(state.refTextupdate) : callback, + typeof callback === "function" + ? callback(state.refTextupdate) + : callback, })), })); @@ -251,7 +255,7 @@ export const useAzimuth = create((set: any) => ({ })); export const useRenderDistance = create((set: any) => ({ - renderDistance: 50, + renderDistance: 40, setRenderDistance: (x: any) => set({ renderDistance: x }), })); @@ -375,3 +379,7 @@ export const useWidgetSubOption = create((set: any) => ({ widgetSubOption: "2D", setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), })); +export const useLimitDistance = create((set: any) => ({ + limitDistance: true, + setLimitDistance: (x: any) => set({ limitDistance: x }), +})); diff --git a/app/src/styles/components/input.scss b/app/src/styles/components/input.scss index f60aca6..64eaaea 100644 --- a/app/src/styles/components/input.scss +++ b/app/src/styles/components/input.scss @@ -558,7 +558,7 @@ input { } .input-value { - width: 40px; + width: 42px; text-align: center; } } diff --git a/app/src/styles/components/marketPlace/marketPlace.scss b/app/src/styles/components/marketPlace/marketPlace.scss index 620d934..b3de954 100644 --- a/app/src/styles/components/marketPlace/marketPlace.scss +++ b/app/src/styles/components/marketPlace/marketPlace.scss @@ -114,7 +114,9 @@ flex-direction: column; justify-content: center; gap: 6px; - + .assets-container { + height: auto; + } .icon { position: absolute; top: 12px; diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index e8175c5..f028f76 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -936,6 +936,7 @@ padding: 0 6px; .assets-wrapper { + width: 100%; position: relative; margin: 8px 10px; @@ -1051,3 +1052,51 @@ } } } + +.assets-container { + width: 100%; + display: flex; + flex-direction: row; + flex-wrap: wrap; + height: 100%; + gap: 3px; + padding: 10px 0; + + .assets { + width: 117px; + height: 95px; + border-radius: 3.59px; + background-color: var(--background-color-gray); + padding: 8px; + padding-top: 12px; + font-weight: $medium-weight; + position: relative; + overflow: hidden; + + .asset-name { + position: relative; + z-index: 3; + font-size: var(--font-size-regular); + } + + .asset-image { + height: 100%; + width: 100%; + position: absolute; + // top: 50%; + // right: 5px; + // transform: translate(0, -50%); + top: 0; + left: 0; + z-index: 2; + } + } +} +.assets-result { + width: 100%; + height: 100%; + margin: 8px 10px; + .assets-wrapper { + margin: 0; + } +} From 695b066c813bb0255ee1d441176a560fe82b8706 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Tue, 1 Apr 2025 11:33:10 +0530 Subject: [PATCH 02/14] deletepanel added --- .../components/ui/componets/AddButtons.tsx | 26 ++++++++++---- .../components/ui/componets/DisplayZone.tsx | 2 +- .../ui/componets/DroppedFloatingWidgets.tsx | 10 ++++-- .../zoneData/add3dWidget.ts | 4 +-- .../zoneData/addFloatingWidgets.ts | 4 +-- .../zoneData/addWidgets.ts | 4 +-- .../zoneData/deleteFloatingWidget.ts | 4 +-- .../zoneData/deletePanel.ts | 34 +++++++++++++++++++ .../zoneData/deleteTemplate.ts | 4 +-- .../zoneData/deleteWidgetApi.ts | 4 +-- .../zoneData/duplicateWidget.ts | 4 +-- .../zoneData/get3dWidgetData.ts | 4 +-- .../zoneData/getFloatingData.ts | 4 +-- .../zoneData/getSelect2dZoneData.ts | 4 +-- .../zoneData/getTemplate.ts | 4 +-- .../zoneData/getZoneData.ts | 4 +-- .../realTimeVisulization/zoneData/getZones.ts | 4 +-- .../zoneData/loadTemplate.ts | 4 +-- .../realTimeVisulization/zoneData/panel.ts | 4 +-- .../zoneData/saveTempleteApi.ts | 4 +-- app/src/store/useDroppedObjectsStore.ts | 7 ++-- 21 files changed, 97 insertions(+), 46 deletions(-) create mode 100644 app/src/services/realTimeVisulization/zoneData/deletePanel.ts diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index e0ca342..18a7628 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -6,6 +6,7 @@ import { } from "../../icons/RealTimeVisulationIcons"; import { panelData } from "../../../services/realTimeVisulization/zoneData/panel"; import { AddIcon } from "../../icons/ExportCommonIcons"; +import { deletePanelApi } from "../../../services/realTimeVisulization/zoneData/deletePanel"; // Define the type for `Side` type Side = "top" | "bottom" | "left" | "right"; @@ -34,7 +35,7 @@ interface ButtonsProps { zoneName: string; activeSides: Side[]; panelOrder: Side[]; - + lockedPanels: Side[]; zoneId: string; zoneViewPortTarget: number[]; @@ -103,8 +104,11 @@ const AddButtons: React.FC = ({ }; // Function to handle "+" button click - const handlePlusButtonClick = (side: Side) => { + const handlePlusButtonClick = async (side: Side) => { + if (selectedZone.activeSides.includes(side)) { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value // If the panel is already active, remove all widgets and close the panel const cleanedWidgets = selectedZone.widgets.filter( (widget) => widget.panel !== side @@ -118,8 +122,14 @@ const AddButtons: React.FC = ({ panelOrder: newActiveSides, }; + let response = await deletePanelApi(selectedZone.zoneId, side, organization) + + if (response.message === 'Panel deleted successfully') { + + setSelectedZone(updatedZone); + } + // Delete the selectedZone state - setSelectedZone(updatedZone); } else { const updatePanelData = async () => { try { @@ -140,13 +150,15 @@ const AddButtons: React.FC = ({ // API call const response = await panelData(organization, selectedZone.zoneId, newActiveSides); - + + if (response.message === 'Panels created successfully') { + setSelectedZone(updatedZone); + } // Update state - - setSelectedZone(updatedZone); + } catch (error) { - + } }; diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index 3889139..b482a83 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -152,7 +152,6 @@ const DisplayZone: React.FC = ({ async function handleSelect2dZoneData(zoneId: string, zoneName: string) { try { if (selectedZone?.zoneId === zoneId) { - return; } const email = localStorage.getItem("email") || ""; @@ -161,6 +160,7 @@ const DisplayZone: React.FC = ({ let response = await getSelect2dZoneData(zoneId, organization); console.log('response: ', response); let res = await getFloatingZoneData(zoneId, organization); + console.log('res: ', res); setFloatingWidget(res) // Set the selected zone in the store useDroppedObjectsStore.getState().setZone(zoneName, zoneId); diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index d7a6960..7386bbd 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -96,7 +96,7 @@ const DroppedObjects: React.FC = () => { console.log('res: ', res); if (res.message === "FloatingWidget deleted successfully") { - deleteObject(zoneName, index); // Call the deleteObject method from the store + deleteObject(zoneName,id, index); // Call the deleteObject method from the store } } catch (error) { console.error("Error deleting floating widget:", error); @@ -255,6 +255,7 @@ const DroppedObjects: React.FC = () => { ...zone.objects[draggingIndex.index], position: boundedPosition, }); + console.log('response: ', response); if (response.message === "Widget updated successfully") { updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); @@ -386,10 +387,13 @@ const DroppedObjects: React.FC = () => { ) : null} - {renderObjectContent(obj)} + {/* {renderObjectContent(obj)} */}
handleKebabClick(obj.id, event)} + onClick={(event) => { + event.stopPropagation(); + handleKebabClick(obj.id, event) + }} >
diff --git a/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts b/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts index 82562b7..6d976b6 100644 --- a/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts +++ b/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts @@ -1,5 +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`; +// 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 adding3dWidgets = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts index fb644c6..ee84841 100644 --- a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts +++ b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts @@ -1,5 +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`; +// 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 addingFloatingWidgets = async ( zoneId: string, diff --git a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts index 8539e54..08969ab 100644 --- a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts +++ b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts @@ -1,5 +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`; +// 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 addingWidgets = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts b/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts index 85c96b8..cd46e5d 100644 --- a/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts +++ b/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts @@ -1,5 +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`; +// 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 deleteFloatingWidgetApi = async ( floatWidgetID: string, diff --git a/app/src/services/realTimeVisulization/zoneData/deletePanel.ts b/app/src/services/realTimeVisulization/zoneData/deletePanel.ts new file mode 100644 index 0000000..0fc22e4 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/deletePanel.ts @@ -0,0 +1,34 @@ +// 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 deletePanelApi = async ( + zoneId: string, + panelName: string, + organization: string +) => { + console.log('panelName: ', panelName); + console.log('organization: ', organization); + console.log('zoneId: ', zoneId); + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/panel/delete`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneId, panelName }), + }); + + if (!response.ok) { + throw new Error("Failed to delete widget 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/deleteTemplate.ts b/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts index e452f6d..df55b37 100644 --- a/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts +++ b/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts @@ -1,5 +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`; +// 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 deleteTemplateApi = async ( templateID: string, diff --git a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts index e57e8cb..92836ed 100644 --- a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts +++ b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts @@ -1,5 +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`; +// 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 deleteWidgetApi = async ( widgetID: string, diff --git a/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts b/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts index f5ec834..80f486d 100644 --- a/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts +++ b/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts @@ -1,5 +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`; +// 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 duplicateWidgetApi = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts b/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts index b5b6200..71a6be7 100644 --- a/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts +++ b/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts @@ -1,5 +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`; +// 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 get3dWidgetZoneData = async ( ZoneId?: string, organization?: string diff --git a/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts index 80d2b19..0246175 100644 --- a/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts @@ -1,5 +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`; +// 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 getFloatingZoneData = async ( ZoneId?: string, organization?: string diff --git a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts index 00d4dfe..2d85b73 100644 --- a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts @@ -1,5 +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`; +// 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 getSelect2dZoneData = async ( ZoneId?: string, diff --git a/app/src/services/realTimeVisulization/zoneData/getTemplate.ts b/app/src/services/realTimeVisulization/zoneData/getTemplate.ts index a3aa3a3..3e516d7 100644 --- a/app/src/services/realTimeVisulization/zoneData/getTemplate.ts +++ b/app/src/services/realTimeVisulization/zoneData/getTemplate.ts @@ -1,5 +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`; +// 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 getTemplateData = async (organization?: string) => { try { const response = await fetch( diff --git a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts index efbac3b..f68ef15 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts @@ -1,5 +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`; +// 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 getZone2dData = async (organization?: string) => { try { const response = await fetch( diff --git a/app/src/services/realTimeVisulization/zoneData/getZones.ts b/app/src/services/realTimeVisulization/zoneData/getZones.ts index 8dbf79a..3be5c3c 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZones.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZones.ts @@ -1,5 +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`; +// 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 getZoneData = async (zoneId: string, organization: string) => { console.log("organization: ", organization); diff --git a/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts b/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts index 915160d..1ec0573 100644 --- a/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts +++ b/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts @@ -1,5 +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`; +// 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 loadTempleteApi = async ( templateID: string, zoneId: string, diff --git a/app/src/services/realTimeVisulization/zoneData/panel.ts b/app/src/services/realTimeVisulization/zoneData/panel.ts index 82f1289..6d93d1f 100644 --- a/app/src/services/realTimeVisulization/zoneData/panel.ts +++ b/app/src/services/realTimeVisulization/zoneData/panel.ts @@ -1,5 +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`; +// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +let url_Backend_dwinzo = `http://192.168.0.102:5000`; type Side = "top" | "bottom" | "left" | "right"; export const panelData = async ( diff --git a/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts b/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts index 5c18031..aa85b47 100644 --- a/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts +++ b/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts @@ -1,5 +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`; +// 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 saveTemplateApi = async (organization: string, template: {}) => { console.log('template: ', template); try { diff --git a/app/src/store/useDroppedObjectsStore.ts b/app/src/store/useDroppedObjectsStore.ts index 83f3a8a..45f40e0 100644 --- a/app/src/store/useDroppedObjectsStore.ts +++ b/app/src/store/useDroppedObjectsStore.ts @@ -36,7 +36,7 @@ type DroppedObjectsState = { bottom: number | "auto"; } ) => void; - deleteObject: (zoneName: string, index: number) => void; // Add this line + deleteObject: (zoneName: string, id: string, index: number) => void; // Add this line duplicateObject: (zoneName: string, index: number) => void; // Add this line }; @@ -77,15 +77,16 @@ export const useDroppedObjectsStore = create((set) => ({ }; }), - deleteObject: (zoneName: string, index: number) => + deleteObject: (zoneName: string, id: string, index: number) => set((state) => { const zone = state.zones[zoneName]; + console.log("zone: ", zone); if (!zone) return state; return { zones: { [zoneName]: { ...zone, - objects: zone.objects.filter((_, i) => i !== index), // Remove object at the given index + objects: zone.objects.filter((obj) => obj.id !== id), // Remove object at the given index }, }, }; From e35d3b374223175a3a42820c6b54ba31a6a1efa3 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Tue, 1 Apr 2025 11:43:59 +0530 Subject: [PATCH 03/14] bug solved while delete floating widgets --- .../ui/componets/DroppedFloatingWidgets.tsx | 67 ++----------------- 1 file changed, 5 insertions(+), 62 deletions(-) diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index 7386bbd..c3d61e3 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -96,7 +96,7 @@ const DroppedObjects: React.FC = () => { console.log('res: ', res); if (res.message === "FloatingWidget deleted successfully") { - deleteObject(zoneName,id, index); // Call the deleteObject method from the store + deleteObject(zoneName, id, index); // Call the deleteObject method from the store } } catch (error) { console.error("Error deleting floating widget:", error); @@ -105,6 +105,9 @@ const DroppedObjects: React.FC = () => { const handlePointerDown = (event: React.PointerEvent, index: number) => { + if ((event.target as HTMLElement).closest(".kebab-options") || (event.target as HTMLElement).closest(".kebab")) { + return; // Prevent dragging when clicking on the kebab menu or its options + } const obj = zone.objects[index]; const container = document.getElementById("real-time-vis-canvas"); if (!container) return; @@ -280,66 +283,6 @@ const DroppedObjects: React.FC = () => { setOpenKebabId((prevId) => (prevId === id ? null : id)); }; - const renderObjectContent = (obj: any) => { - switch (obj.className) { - case "floating total-card": - return ( - <> -
-
{obj.header}
-
-
{obj.value}
-
{obj.per}
-
-
-
- -
- - ); - case "warehouseThroughput floating": - return ( - <> -
-

Warehouse Throughput

-

- (+5) more in 2025 -

-
-
- {/* */} -
- - ); - case "fleetEfficiency floating": - return ( - <> -

Fleet Efficiency

-
-
-
-
-
-
-
-
- 0% -
-
{obj.per}%
-
Optimal
-
- 100% -
- - ); - default: - return null; - } - }; - return (
{ ) : null} - {/* {renderObjectContent(obj)} */} +
{ From 03e7c32bfbd1e58881870430e7c1626a9c49f0c1 Mon Sep 17 00:00:00 2001 From: gabriel Date: Tue, 1 Apr 2025 14:27:19 +0530 Subject: [PATCH 04/14] Merge branch 'realTimeVisulization' of http://185.100.212.76:7776/Dwinzo-Beta/Dwinzo_dev into realTimeVisulization --- .../visualization/widgets/Widgets2D.tsx | 1 + .../IotInputCards/BarChartInput.tsx | 177 +++++++++++++ .../IotInputCards/FlotingWidgetInput.tsx | 19 +- .../IotInputCards/InputSelecterComponent.tsx | 75 ++++++ .../IotInputCards/LineGrapInput.tsx | 2 +- .../IotInputCards/PieChartInput.tsx | 241 ++++++++++++------ .../WarehouseThroughputInputComponent.tsx | 178 +++++++++++++ .../sidebarRight/visualization/data/Data.tsx | 4 +- .../ui/componets/DroppedFloatingWidgets.tsx | 3 +- .../realTimeVis/floating/FleetEfficiency.tsx | 4 +- .../floating/FleetEfficiencyComponent.tsx | 15 +- .../floating/WarehouseThroughputComponent.tsx | 117 +++++++-- app/src/store/store.ts | 2 +- app/src/store/useChartStore.ts | 20 +- app/src/styles/pages/realTimeViz.scss | 2 +- 15 files changed, 741 insertions(+), 119 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx index 4c90582..c3696e0 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx @@ -99,6 +99,7 @@ const ProgressBarWidget = ({
); }; +console.log(chartTypes,"chartTypes"); const Widgets2D = () => { return ( diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx new file mode 100644 index 0000000..8fe71a6 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/BarChartInput.tsx @@ -0,0 +1,177 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +type Props = {}; + +const BarChartInput = (props: Props) => { + const [widgetName, setWidgetName] = useState('Widget'); + const { setMeasurements, updateDuration, updateName } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + const { selectedChartId } = useWidgetStore(); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setMeasurements(selections); + updateDuration(duration); + updateName(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + panel: selectedChartId.panel, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; + // }; + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + // setDuration(option); + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(3)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+
+
+
Duration
+
+ +
+
+
+ + ); +}; + +export default BarChartInput; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx index 5938da9..0a58634 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FlotingWidgetInput.tsx @@ -12,7 +12,7 @@ type Props = {}; const FlotingWidgetInput = (props: Props) => { const [widgetName, setWidgetName] = useState('Widget'); - const { setMeasurements, updateDuration, updateName } = useChartStore(); + const { setFlotingMeasurements, updateFlotingDuration, updateHeader } = useChartStore(); const [duration, setDuration] = useState('1h') const [dropDowndata, setDropDownData] = useState({}); const [selections, setSelections] = useState>({}); @@ -43,11 +43,13 @@ const FlotingWidgetInput = (props: Props) => { const fetchSavedInputes = async () => { if (selectedChartId.id !== "") { try { - const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`); if (response.status === 200) { + console.log(response.data); + setSelections(response.data.Data.measurements) setDuration(response.data.Data.duration) - setWidgetName(response.data.widgetName) + setWidgetName(response.data.header) } else { console.log("Unexpected response:", response); } @@ -63,9 +65,9 @@ const FlotingWidgetInput = (props: Props) => { // Sync Zustand state when component mounts useEffect(() => { - setMeasurements(selections); - updateDuration(duration); - updateName(widgetName); + setFlotingMeasurements(selections); + updateFlotingDuration(duration); + updateHeader(widgetName); }, [selections, duration, widgetName]); @@ -76,8 +78,7 @@ const FlotingWidgetInput = (props: Props) => { zoneId: selectedZone.zoneId, widget: { id: selectedChartId.id, - panel: selectedChartId.panel, - widgetName: inputName, + header: inputName, Data: { measurements: inputMeasurement, duration: inputDuration @@ -135,7 +136,7 @@ const FlotingWidgetInput = (props: Props) => {
Title
- +
{[...Array(6)].map((_, index) => { const inputKey = `input${index + 1}`; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx new file mode 100644 index 0000000..45ce802 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx @@ -0,0 +1,75 @@ +import React from 'react' +import LineGrapInput from './LineGrapInput' +import BarChartInput from './BarChartInput' +import PieChartInput from './PieChartInput' +import FlotingWidgetInput from './FlotingWidgetInput' +import WarehouseThroughputInputComponent from './WarehouseThroughputInputComponent' +import { useWidgetStore } from '../../../../../store/useWidgetStore' + +const InputSelecterComponent = () => { + const { selectedChartId } = useWidgetStore(); + console.log('selectedChartId:',selectedChartId); + + + if (selectedChartId && selectedChartId.type && selectedChartId.type === 'bar' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'line' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'pie' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'doughnut' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'polarArea' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'warehouseThroughput floating' ) { + return ( + <> +
Floting Widget Input
+ + + ) + } + + else { + return ( +
No chart selected
+ ) + } +} + +export default InputSelecterComponent \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx index 32a5590..017dc6d 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/LineGrapInput.tsx @@ -256,7 +256,7 @@ const LineGrapInput = (props: Props) => {
Title
- {[...Array(6)].map((_, index) => { + {[...Array(4)].map((_, index) => { const inputKey = `input${index + 1}`; return (
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx index 3087471..e3bed25 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/PieChartInput.tsx @@ -1,78 +1,177 @@ -import React, { useEffect, useState } from 'react' -import MultiLevelDropdown from '../../../../ui/inputs/MultiLevelDropDown' -import { AddIcon } from '../../../../icons/ExportCommonIcons' -import axios from 'axios' +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; -type Props = {} +type Props = {}; const PieChartInput = (props: Props) => { - const [dropDowndata, setDropDownData] = useState({}) - const [selections, setSelections] = useState>({}) - const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const [widgetName, setWidgetName] = useState('Widget'); + const { setMeasurements, updateDuration, updateName } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + const { selectedChartId } = useWidgetStore(); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] - useEffect(() => { - const fetchZoneData = async () => { - try { - const response = await axios.get(`http://${iotApiUrl}/getinput`); - if (response.status === 200) { - console.log('dropdown data:', response.data); - setDropDownData(response.data) - } else { - console.log('Unexpected response:', response); - } - } catch (error) { - console.error('There was an error!', error); - } - }; - fetchZoneData(); - }, []); - - useEffect(() => {console.log(selections); - },[selections]) - - const handleSelect = (inputKey: string, selectedData: {name: string, fields: string} | null) => { - setSelections(prev => { - if (selectedData === null) { - const newSelections = {...prev}; - delete newSelections[inputKey]; - return newSelections; - } else { - return { - ...prev, - [inputKey]: selectedData - }; - } - }); + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } }; + fetchZoneData(); + }, []); - return ( - <> -
- {[...Array(3)].map((_, index) => { - const inputKey = `input${index+1}`; - return ( -
-
Input {index+1}
-
- handleSelect(inputKey, selectedData)} - onUnselect={() => handleSelect(inputKey, null)} - selectedValue={selections[inputKey]} - /> -
- -
-
-
- ); - })} -
-
- -
- - ) -} + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } -export default PieChartInput \ No newline at end of file + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setMeasurements(selections); + updateDuration(duration); + updateName(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + panel: selectedChartId.panel, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; + // }; + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + // setDuration(option); + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(2)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+
+
+
Duration
+
+ +
+
+
+ + ); +}; + +export default PieChartInput; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx new file mode 100644 index 0000000..cd8cb96 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/WarehouseThroughputInputComponent.tsx @@ -0,0 +1,178 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +type Props = {}; + +const WarehouseThroughputInputComponent = (props: Props) => { + const [widgetName, setWidgetName] = useState('Widget'); + const { setFlotingMeasurements, updateFlotingDuration, updateHeader } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + const { selectedChartId } = useWidgetStore(); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + console.log(response.data); + + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.header) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setFlotingMeasurements(selections); + updateFlotingDuration(duration); + updateHeader(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + header: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; + // }; + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + // setDuration(option); + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(1)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+
+
+
Duration
+
+ +
+
+
+ + ); +}; + +export default WarehouseThroughputInputComponent; diff --git a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx index 2c9b5c6..1b9969c 100644 --- a/app/src/components/layout/sidebarRight/visualization/data/Data.tsx +++ b/app/src/components/layout/sidebarRight/visualization/data/Data.tsx @@ -4,6 +4,7 @@ import { AddIcon, RemoveIcon } from "../../../../icons/ExportCommonIcons"; import MultiLevelDropDown from "../../../../ui/inputs/MultiLevelDropDown"; import LineGrapInput from "../IotInputCards/LineGrapInput"; import RenameInput from "../../../../ui/inputs/RenameInput"; +import InputSelecterComponent from "../IotInputCards/InputSelecterComponent"; // Define the data structure for demonstration purposes const DATA_STRUCTURE = { @@ -133,8 +134,7 @@ const Data = () => { { chartDataGroups[selectedChartId?.id] && <> -
2D Widget Input
- + } diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index d7a6960..35278bb 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -379,14 +379,13 @@ const DroppedObjects: React.FC = () => { ) : obj.className === "warehouseThroughput floating" ? ( <> - + ) : obj.className === "fleetEfficiency floating" ? ( <> ) : null} - {renderObjectContent(obj)}
handleKebabClick(obj.id, event)} diff --git a/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx b/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx index 07e5f19..cabc3e7 100644 --- a/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx +++ b/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx @@ -1,8 +1,8 @@ const FleetEfficiency = () => { - const progress = 75; // Example progress value (0-100) + const progress = 50; // Example progress value (0-100) // Calculate the rotation angle for the progress bar - const rotationAngle = -90 + progress * 3.6; // Progress starts from the left (-90°) + const rotationAngle = 45 + progress * 1.8; const handleDragStart = (event: React.DragEvent) => { const rect = event.currentTarget.getBoundingClientRect(); // Get position diff --git a/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx b/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx index 9b2fd7f..e9221e8 100644 --- a/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx +++ b/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx @@ -1,10 +1,11 @@ -import React from 'react' +import React,{ useEffect, useState} from 'react' -type Props = {} +const FleetEfficiencyComponent = ({object}: any) => { + const [ progress, setProgress ] = useState(0) -const FleetEfficiencyComponent = ({ - object -}: any) => { + // Calculate the rotation angle for the progress bar + const rotationAngle = 45 + progress * 1.8; + return ( <>

Fleet Efficiency

@@ -13,7 +14,7 @@ const FleetEfficiencyComponent = ({
@@ -21,7 +22,7 @@ const FleetEfficiencyComponent = ({
0%
-
{object.per}%
+
{progress}%
Optimal
100% diff --git a/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx b/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx index 3aa8698..22f6529 100644 --- a/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx +++ b/app/src/components/ui/realTimeVis/floating/WarehouseThroughputComponent.tsx @@ -1,6 +1,9 @@ -import React, { useState } from 'react' +import React, { useState, useEffect } from 'react' import { Line } from 'react-chartjs-2' +import useChartStore from '../../../../store/useChartStore'; +import { useWidgetStore } from '../../../../store/useWidgetStore'; import axios from 'axios'; +import io from "socket.io-client"; const WarehouseThroughputComponent = ({ object @@ -8,6 +11,17 @@ const WarehouseThroughputComponent = ({ const [measurements, setmeasurements] = useState({}); const [duration, setDuration] = useState("1h") + const [name, setName] = useState(object.header ? object.header : '') + const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + labels: [], + datasets: [], + }); + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + const { header, flotingDuration, flotingMeasurements } = useChartStore(); + const { selectedChartId } = useWidgetStore(); + + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; const lineGraphData = { labels: [ @@ -95,35 +109,94 @@ const WarehouseThroughputComponent = ({ }; - // const fetchSavedInputes = async() => { + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + + const socket = io(`http://${iotApiUrl}`); + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + + const startStream = () => { + socket.emit("lineInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lineOutput", (response) => { + const responseData = response.data; + + // Extract timestamps and values + const labels = responseData.time; + const datasets = Object.keys(measurements).map((key) => { + const measurement = measurements[key]; + const datasetKey = `${measurement.name}.${measurement.fields}`; + return { + label: datasetKey, + data: responseData[datasetKey]?.values ?? [], + borderColor: "#6f42c1", // Use the desired color for the line (purple) + backgroundColor: "rgba(111, 66, 193, 0.2)", // Use a semi-transparent purple for the fill + borderWidth: 2, // Line thickness + fill: true, // Enable fill for this dataset + pointRadius: 0, // Remove dots at each data point + tension: 0.5, // Smooth interpolation for the line + }; + }); + + setChartData({ labels, datasets }); + }); + + return () => { + socket.off("lineOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [measurements, duration, iotApiUrl]); + + const fetchSavedInputes = async() => { + + if (object?.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.header) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === object?.id) { + fetchSavedInputes(); + } + } + ,[header, flotingDuration, flotingMeasurements]) - // if (object.id !== "") { - // try { - // const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_LOCAL_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); - // if (response.status === 200) { - // setmeasurements(response.data.Data.measurements) - // setDuration(response.data.Data.duration) - // setName(response.data.widgetName) - // } else { - // console.log("Unexpected response:", response); - // } - // } catch (error) { - // console.error("There was an error!", error); - // } - // } - // } - return ( <>
-

Warehouse Throughput

-

+

{name}

+ {/*

(+5) more in 2025 -

+

*/}
- + 0 ? chartData : lineGraphData} options={lineGraphOptions} />
) diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 6affa99..ef5c25f 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -11,7 +11,7 @@ export const useSocketStore = create((set: any, get: any) => ({ return; } - const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { + const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`, { reconnection: false, auth: { email, organization }, }); diff --git a/app/src/store/useChartStore.ts b/app/src/store/useChartStore.ts index 079b9ff..cdd8de0 100644 --- a/app/src/store/useChartStore.ts +++ b/app/src/store/useChartStore.ts @@ -10,9 +10,15 @@ interface MeasurementStore { interval: number; duration: string; name: string; + header: string; + flotingDuration: string; + flotingMeasurements: Record; // Change array to Record setMeasurements: (newMeasurements: Record) => void; updateDuration: (newDuration: string) => void; updateName: (newName: string) => void; + updateHeader: (newHeader: string) => void; + updateFlotingDuration: (newFlotingDuration: string) => void; + setFlotingMeasurements: (newFlotingMeasurements: Record) => void; } const useChartStore = create((set) => ({ @@ -20,6 +26,9 @@ const useChartStore = create((set) => ({ interval: 1000, duration: "1h", name:'', + header:'', + flotingDuration: "1h", + flotingMeasurements: {}, setMeasurements: (newMeasurements) => set(() => ({ measurements: newMeasurements })), @@ -28,7 +37,16 @@ const useChartStore = create((set) => ({ set(() => ({ duration: newDuration })), updateName: (newName) => - set(() => ({ duration: newName })), + set(() => ({ name: newName })), + + updateHeader: (newHeader) => + set(() => ({ header: newHeader })), + + updateFlotingDuration: (newFlotingDuration) => + set(() => ({ flotingDuration: newFlotingDuration })), + + setFlotingMeasurements: (newFlotingMeasurements) => + set(() => ({ flotingMeasurements: newFlotingMeasurements })), })); export default useChartStore; diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index d58f12d..4440e6d 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -196,7 +196,7 @@ border-radius: 8px; box-shadow: 0px 2px 6px 0px rgba(60, 60, 67, 0.1); padding: 6px 0; - background-color: white; + background-color: var(--background-color); position: relative; .kebab { From 900723c14a1c74ec40041aa9aaed68f663a49485 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Tue, 1 Apr 2025 15:16:54 +0530 Subject: [PATCH 05/14] server api changed for RealTimeVisulization --- .../3D-cards/cards/ProductionCapacity.tsx | 10 +- .../components/ui/componets/AddButtons.tsx | 93 ++++++++++--------- .../components/ui/componets/DisplayZone.tsx | 22 ++--- .../components/ui/componets/DistanceLines.tsx | 26 +++++- .../ui/componets/Dropped3dWidget.tsx | 35 ++----- .../ui/componets/DroppedFloatingWidgets.tsx | 60 +++++++++--- app/src/components/ui/componets/Panel.tsx | 6 +- .../ui/componets/RealTimeVisulization.tsx | 2 + .../componets/functions/determinePosition.ts | 84 ++--------------- .../zoneData/add3dWidget.ts | 4 +- .../zoneData/addFloatingWidgets.ts | 4 +- .../zoneData/addWidgets.ts | 4 +- .../zoneData/deleteFloatingWidget.ts | 4 +- .../zoneData/deletePanel.ts | 4 +- .../zoneData/deleteTemplate.ts | 4 +- .../zoneData/deleteWidgetApi.ts | 4 +- .../zoneData/duplicateWidget.ts | 4 +- .../zoneData/get3dWidgetData.ts | 4 +- .../zoneData/getFloatingData.ts | 4 +- .../zoneData/getSelect2dZoneData.ts | 4 +- .../zoneData/getTemplate.ts | 4 +- .../zoneData/getZoneData.ts | 4 +- .../realTimeVisulization/zoneData/getZones.ts | 4 +- .../zoneData/loadTemplate.ts | 4 +- .../realTimeVisulization/zoneData/panel.ts | 4 +- .../zoneData/saveTempleteApi.ts | 4 +- .../zoneData/useFloatingDataStore.ts | 8 -- app/src/store/store.ts | 10 +- app/src/styles/pages/realTimeViz.scss | 2 - 29 files changed, 201 insertions(+), 225 deletions(-) delete mode 100644 app/src/services/realTimeVisulization/zoneData/useFloatingDataStore.ts diff --git a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx index 4da32bc..785f20d 100644 --- a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx +++ b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx @@ -25,7 +25,7 @@ interface ProductionCapacityProps { position: [number, number, number]; } -const ProductionCapacity : React.FC = ({ position }) => { +const ProductionCapacity: React.FC = ({ position }) => { // Chart data for a week const chartData = { labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], // Days of the week @@ -79,10 +79,10 @@ const ProductionCapacity : React.FC = ({ position }) => }; return ( - +
Production Capacity
diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index 18a7628..d06be19 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -105,68 +105,69 @@ const AddButtons: React.FC = ({ // Function to handle "+" button click const handlePlusButtonClick = async (side: Side) => { - if (selectedZone.activeSides.includes(side)) { + // Panel already exists: Remove widgets from that side and update activeSides const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value - // If the panel is already active, remove all widgets and close the panel + + // Remove all widgets associated with the side and update active sides const cleanedWidgets = selectedZone.widgets.filter( (widget) => widget.panel !== side ); const newActiveSides = selectedZone.activeSides.filter((s) => s !== side); - + const updatedZone = { ...selectedZone, widgets: cleanedWidgets, activeSides: newActiveSides, panelOrder: newActiveSides, }; - - let response = await deletePanelApi(selectedZone.zoneId, side, organization) - - if (response.message === 'Panel deleted successfully') { - - setSelectedZone(updatedZone); - } - - // Delete the selectedZone state - } else { - const updatePanelData = async () => { - try { - // Get email and organization safely - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg"; // Fallback value - - // Prevent duplicate side entries - const newActiveSides = selectedZone.activeSides.includes(side) - ? [...selectedZone.activeSides] - : [...selectedZone.activeSides, side]; - - const updatedZone = { - ...selectedZone, - activeSides: newActiveSides, - panelOrder: newActiveSides, - }; - - // API call - const response = await panelData(organization, selectedZone.zoneId, newActiveSides); - - if (response.message === 'Panels created successfully') { - setSelectedZone(updatedZone); - } - - // Update state - - } catch (error) { - + + // API call to delete the panel + try { + const response = await deletePanelApi(selectedZone.zoneId, side, organization); + console.log('response: ', response); + if (response.message === "Panel deleted successfully") { + setSelectedZone(updatedZone); + } else { + console.error("Unexpected response:", response); } - }; - - updatePanelData(); // Call the async function + } catch (error) { + console.error("Error deleting panel:", error); + } + } else { + // Panel does not exist: Create panel + try { + // Get email and organization safely with a default fallback + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] ; + + // Prevent duplicate side entries + const newActiveSides = selectedZone.activeSides.includes(side) + ? [...selectedZone.activeSides] + : [...selectedZone.activeSides, side]; + + const updatedZone = { + ...selectedZone, + activeSides: newActiveSides, + panelOrder: newActiveSides, + }; + + // API call to create panels + const response = await panelData(organization, selectedZone.zoneId, newActiveSides); + console.log('response: ', response); + + if (response.message === "Panels created successfully") { + setSelectedZone(updatedZone); + } else { + console.error("Unexpected response:", response); + } + } catch (error) { + console.error("Error creating panels:", error); + } } - - }; + return ( <> diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index b482a83..ddc7903 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -2,7 +2,10 @@ import React, { useEffect, useRef, useState, useCallback } from "react"; import { Widget } from "../../../store/useWidgetStore"; import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons"; import { InfoIcon } from "../../icons/ExportCommonIcons"; -import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore"; +import { + useDroppedObjectsStore, + useFloatingWidget, +} from "../../../store/useDroppedObjectsStore"; import { getSelect2dZoneData } from "../../../services/realTimeVisulization/zoneData/getSelect2dZoneData"; import { getFloatingZoneData } from "../../../services/realTimeVisulization/zoneData/getFloatingData"; import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData"; @@ -66,14 +69,13 @@ const DisplayZone: React.FC = ({ selectedZone, setSelectedZone, }) => { - // Ref for the container element const containerRef = useRef(null); // State to track overflow visibility const [showLeftArrow, setShowLeftArrow] = useState(false); const [showRightArrow, setShowRightArrow] = useState(false); - const { floatingWidget, setFloatingWidget } = useFloatingWidget() + const { floatingWidget, setFloatingWidget } = useFloatingWidget(); // Function to calculate overflow state const updateOverflowState = useCallback(() => { @@ -158,10 +160,10 @@ const DisplayZone: React.FC = ({ const organization = email?.split("@")[1]?.split(".")[0]; // Fetch data from backend let response = await getSelect2dZoneData(zoneId, organization); - console.log('response: ', response); + let res = await getFloatingZoneData(zoneId, organization); - console.log('res: ', res); - setFloatingWidget(res) + + setFloatingWidget(res); // Set the selected zone in the store useDroppedObjectsStore.getState().setZone(zoneName, zoneId); if (Array.isArray(res)) { @@ -180,13 +182,9 @@ const DisplayZone: React.FC = ({ zoneViewPortTarget: response.viewPortCenter || {}, zoneViewPortPosition: response.viewPortposition || {}, }); - } catch (error) { - - - } + } catch (error) { } } - return (
= ({ className={`zone ${selectedZone.zoneName === zoneName ? "active" : "" }`} onClick={() => { - handleSelect2dZoneData(zonesData[zoneName]?.zoneId, zoneName) + handleSelect2dZoneData(zonesData[zoneName]?.zoneId, zoneName); }} > {zoneName} diff --git a/app/src/components/ui/componets/DistanceLines.tsx b/app/src/components/ui/componets/DistanceLines.tsx index 07cf202..e2ccbc1 100644 --- a/app/src/components/ui/componets/DistanceLines.tsx +++ b/app/src/components/ui/componets/DistanceLines.tsx @@ -32,7 +32,12 @@ const DistanceLines: React.FC = ({ obj, activeEdges }) => { height: `${obj.position.top}px`, }} > - {obj.position.top}px + {obj.position.top}px
)} @@ -49,7 +54,12 @@ const DistanceLines: React.FC = ({ obj, activeEdges }) => { height: `${obj.position.bottom}px`, }} > - {obj.position.bottom}px + {obj.position.bottom}px
)} @@ -66,7 +76,11 @@ const DistanceLines: React.FC = ({ obj, activeEdges }) => { width: `${obj.position.left}px`, }} > - {obj.position.left}px + {obj.position.left}px
)} @@ -83,7 +97,11 @@ const DistanceLines: React.FC = ({ obj, activeEdges }) => { width: `${obj.position.right}px`, }} > - {obj.position.right}px + {obj.position.right}px
)} diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index 94c5e45..b970872 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -51,29 +51,12 @@ export default function Dropped3dWidgets() { get3dWidgetData(); - }, [selectedZone.zoneId,activeModule]); - // useEffect(() => { - // // ✅ Set data only for the selected zone, keeping existing state structure - // setZoneWidgetData((prev) => ({ - // ...prev, - // [selectedZone.zoneId]: [ - // { - // "id": "1743322674626-50mucpb1c", - // "type": "ui-Widget 1", - // "position": [120.94655021768133, 4.142360029666558, 124.39283546121099] - // }, - // { - // "id": "1743322682086-je2h9x33v", - // "type": "ui-Widget 2", - // "position": [131.28751045879255, 0.009999999999970264, 133.92059801984362] - // } - // ] - // })); - // }, [selectedZone.zoneId]); // ✅ Only update when the zone changes + }, [selectedZone.zoneId, activeModule]); useEffect(() => { if (activeModule !== "visualization") return; if (widgetSubOption === "Floating") return; + if (widgetSubOption === "2D") return; if (selectedZone.zoneName === "") return const canvasElement = gl.domElement; const onDrop = async (event: DragEvent) => { @@ -103,13 +86,15 @@ export default function Dropped3dWidgets() { let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget) + console.log('response: ', response); - - // ✅ Store widgets uniquely for each zone - setZoneWidgetData((prev) => ({ - ...prev, - [selectedZone.zoneId]: [...(prev[selectedZone.zoneId] || []), newWidget], - })); + if (response.message === "Widget created successfully") { + // ✅ Store widgets uniquely for each zone + setZoneWidgetData((prev) => ({ + ...prev, + [selectedZone.zoneId]: [...(prev[selectedZone.zoneId] || []), newWidget], + })); + } } }; diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index c3d61e3..cc9883d 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -68,6 +68,8 @@ const DroppedObjects: React.FC = () => { } | null>(null); // State to track the current position during drag const animationRef = useRef(null); const { activeModule } = useModuleStore(); + const kebabRef = useRef(null); + // Clean up animation frame on unmount useEffect(() => { @@ -77,6 +79,21 @@ const DroppedObjects: React.FC = () => { } }; }, []); + // useEffect(() => { + // const handleClickOutside = (event: MouseEvent) => { + // if (kebabRef.current && !kebabRef.current.contains(event.target as Node)) { + // setOpenKebabId(null); + // } + // }; + + // // Add event listener when component mounts + // document.addEventListener("mousedown", handleClickOutside); + + // // Clean up event listener when component unmounts + // return () => { + // document.removeEventListener("mousedown", handleClickOutside); + // }; + // }, []); const zoneEntries = Object.entries(zones); if (zoneEntries.length === 0) return null; @@ -109,6 +126,8 @@ const DroppedObjects: React.FC = () => { return; // Prevent dragging when clicking on the kebab menu or its options } const obj = zone.objects[index]; + const element = event.currentTarget as HTMLElement; + element.setPointerCapture(event.pointerId); const container = document.getElementById("real-time-vis-canvas"); if (!container) return; @@ -201,13 +220,15 @@ const DroppedObjects: React.FC = () => { // Update the current position state for DistanceLines setCurrentPosition(newPosition); + // Update position immediately without animation frame + updateObjectPosition(zoneName, draggingIndex.index, newPosition); - if (!animationRef.current) { - animationRef.current = requestAnimationFrame(() => { - updateObjectPosition(zoneName, draggingIndex.index, newPosition); - animationRef.current = null; - }); - } + // if (!animationRef.current) { + // animationRef.current = requestAnimationFrame(() => { + // updateObjectPosition(zoneName, draggingIndex.index, newPosition); + // animationRef.current = null; + // }); + // } }; const handlePointerUp = async (event: React.PointerEvent) => { @@ -249,6 +270,9 @@ const DroppedObjects: React.FC = () => { ...finalPosition, [activeProp1]: finalY, [activeProp2]: finalX, + // Clear opposite properties + [activeProp1 === "top" ? "bottom" : "top"]: "auto", + [activeProp2 === "left" ? "right" : "left"]: "auto", }; // Save to backend @@ -264,17 +288,29 @@ const DroppedObjects: React.FC = () => { updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); } - // Clean up + // // Clean up + // setDraggingIndex(null); + // setOffset(null); + // setActiveEdges(null); // Clear active edges + // setCurrentPosition(null); // Reset current position + // if (animationRef.current) { + // cancelAnimationFrame(animationRef.current); + // animationRef.current = null; + // } + } catch (error) { + console.error("Error in handlePointerUp:", error); + } finally { + // Clean up regardless of success or failure setDraggingIndex(null); setOffset(null); - setActiveEdges(null); // Clear active edges - setCurrentPosition(null); // Reset current position + setActiveEdges(null); + setCurrentPosition(null); + + // Cancel any pending animation frame if (animationRef.current) { cancelAnimationFrame(animationRef.current); animationRef.current = null; } - } catch (error) { - console.error("Error in handlePointerUp:", error); } }; @@ -333,6 +369,7 @@ const DroppedObjects: React.FC = () => {
{ event.stopPropagation(); handleKebabClick(obj.id, event) @@ -362,6 +399,7 @@ const DroppedObjects: React.FC = () => {
)} +
))} diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index 6500119..61956b9 100644 --- a/app/src/components/ui/componets/Panel.tsx +++ b/app/src/components/ui/componets/Panel.tsx @@ -4,6 +4,7 @@ import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import { DraggableWidget } from "./DraggableWidget"; import { arrayMove } from "@dnd-kit/sortable"; import { addingWidgets } from "../../../services/realTimeVisulization/zoneData/addWidgets"; +import { useAsset3dWidget } from "../../../store/store"; type Side = "top" | "bottom" | "left" | "right"; @@ -53,6 +54,7 @@ const Panel: React.FC = ({ hiddenPanels, setZonesData, }) => { + const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({}); const [panelDimensions, setPanelDimensions] = useState<{ [side in Side]?: { width: number; height: number }; @@ -101,7 +103,9 @@ const Panel: React.FC = ({ const handleDrop = (e: React.DragEvent, panel: Side) => { + e.preventDefault(); + setWidgetSelect("") const { draggedAsset } = useWidgetStore.getState(); if (!draggedAsset) return; if (isPanelLocked(panel)) return; @@ -149,7 +153,7 @@ const Panel: React.FC = ({ }; try { let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); - + if (response.message === "Widget created successfully") { setSelectedZone((prev) => ({ ...prev, diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index f6a041a..387729d 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -132,6 +132,8 @@ const RealTimeVisulization: React.FC = () => { const relativeX = event.clientX - canvasRect.left; const relativeY = event.clientY - canvasRect.top; + const newPosition = determinePosition(canvasRect, relativeX, relativeY) + console.log('newPosition: ', newPosition); const newObject = { ...droppedData, id: generateUniqueId(), diff --git a/app/src/components/ui/componets/functions/determinePosition.ts b/app/src/components/ui/componets/functions/determinePosition.ts index 000e3a1..af9991b 100644 --- a/app/src/components/ui/componets/functions/determinePosition.ts +++ b/app/src/components/ui/componets/functions/determinePosition.ts @@ -1,69 +1,3 @@ -// export function determinePosition( -// canvasRect: DOMRect, -// relativeX: number, -// relativeY: number -// ): { -// top: number | "auto"; -// left: number | "auto"; -// right: number | "auto"; -// bottom: number | "auto"; -// } { -// // Calculate the midpoints of the canvas -// const centerX = canvasRect.width / 2; -// const centerY = canvasRect.height / 2; - -// // Initialize position with default values -// let position: { -// top: number | "auto"; -// left: number | "auto"; -// right: number | "auto"; -// bottom: number | "auto"; -// }; - -// if (relativeY < centerY) { -// // Top half -// if (relativeX < centerX) { -// // Left side -// position = { -// top: relativeY, -// left: relativeX, -// right: "auto", -// bottom: "auto", -// }; -// } else { -// // Right side -// position = { -// top: relativeY, -// right: canvasRect.width - relativeX, -// left: "auto", -// bottom: "auto", -// }; -// } -// } else { -// // Bottom half -// if (relativeX < centerX) { -// // Left side -// position = { -// bottom: canvasRect.height - relativeY, -// left: relativeX, -// right: "auto", -// top: "auto", -// }; -// } else { -// // Right side -// position = { -// bottom: canvasRect.height - relativeY, -// right: canvasRect.width - relativeX, -// left: "auto", -// top: "auto", -// }; -// } -// } - -// return position; -// } - - export function determinePosition( canvasRect: DOMRect, @@ -89,16 +23,16 @@ export function determinePosition( if (relativeX < centerX) { console.log("Top-left"); position = { - top: relativeY, - left: relativeX, + top: relativeY - 41.5, + left: relativeX - 125, right: "auto", bottom: "auto", }; } else { console.log("Top-right"); position = { - top: relativeY, - right: canvasRect.width - relativeX, + top: relativeY - 41.5, + right: canvasRect.width - relativeX - 125, left: "auto", bottom: "auto", }; @@ -107,16 +41,16 @@ export function determinePosition( if (relativeX < centerX) { console.log("Bottom-left"); position = { - bottom: canvasRect.height - relativeY, - left: relativeX, + bottom: canvasRect.height - relativeY - 41.5, + left: relativeX - 125, right: "auto", top: "auto", }; } else { console.log("Bottom-right"); position = { - bottom: canvasRect.height - relativeY, - right: canvasRect.width - relativeX, + bottom: canvasRect.height - relativeY - 41.5, + right: canvasRect.width - relativeX - 125, left: "auto", top: "auto", }; @@ -124,4 +58,4 @@ export function determinePosition( } return position; -} \ No newline at end of file +} diff --git a/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts b/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts index 6d976b6..82562b7 100644 --- a/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts +++ b/app/src/services/realTimeVisulization/zoneData/add3dWidget.ts @@ -1,5 +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`; +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 adding3dWidgets = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts index ee84841..fb644c6 100644 --- a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts +++ b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts @@ -1,5 +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`; +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 addingFloatingWidgets = async ( zoneId: string, diff --git a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts index 08969ab..8539e54 100644 --- a/app/src/services/realTimeVisulization/zoneData/addWidgets.ts +++ b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts @@ -1,5 +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`; +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 addingWidgets = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts b/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts index cd46e5d..85c96b8 100644 --- a/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts +++ b/app/src/services/realTimeVisulization/zoneData/deleteFloatingWidget.ts @@ -1,5 +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`; +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 deleteFloatingWidgetApi = async ( floatWidgetID: string, diff --git a/app/src/services/realTimeVisulization/zoneData/deletePanel.ts b/app/src/services/realTimeVisulization/zoneData/deletePanel.ts index 0fc22e4..21f4846 100644 --- a/app/src/services/realTimeVisulization/zoneData/deletePanel.ts +++ b/app/src/services/realTimeVisulization/zoneData/deletePanel.ts @@ -1,5 +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`; +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 deletePanelApi = async ( zoneId: string, diff --git a/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts b/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts index df55b37..e452f6d 100644 --- a/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts +++ b/app/src/services/realTimeVisulization/zoneData/deleteTemplate.ts @@ -1,5 +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`; +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 deleteTemplateApi = async ( templateID: string, diff --git a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts index 92836ed..e57e8cb 100644 --- a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts +++ b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts @@ -1,5 +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`; +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 deleteWidgetApi = async ( widgetID: string, diff --git a/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts b/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts index 80f486d..f5ec834 100644 --- a/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts +++ b/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts @@ -1,5 +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`; +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 duplicateWidgetApi = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts b/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts index 71a6be7..b5b6200 100644 --- a/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts +++ b/app/src/services/realTimeVisulization/zoneData/get3dWidgetData.ts @@ -1,5 +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`; +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 get3dWidgetZoneData = async ( ZoneId?: string, organization?: string diff --git a/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts index 0246175..80d2b19 100644 --- a/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts @@ -1,5 +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`; +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 getFloatingZoneData = async ( ZoneId?: string, organization?: string diff --git a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts index 2d85b73..00d4dfe 100644 --- a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts @@ -1,5 +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`; +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 getSelect2dZoneData = async ( ZoneId?: string, diff --git a/app/src/services/realTimeVisulization/zoneData/getTemplate.ts b/app/src/services/realTimeVisulization/zoneData/getTemplate.ts index 3e516d7..a3aa3a3 100644 --- a/app/src/services/realTimeVisulization/zoneData/getTemplate.ts +++ b/app/src/services/realTimeVisulization/zoneData/getTemplate.ts @@ -1,5 +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`; +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 getTemplateData = async (organization?: string) => { try { const response = await fetch( diff --git a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts index f68ef15..efbac3b 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts @@ -1,5 +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`; +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 getZone2dData = async (organization?: string) => { try { const response = await fetch( diff --git a/app/src/services/realTimeVisulization/zoneData/getZones.ts b/app/src/services/realTimeVisulization/zoneData/getZones.ts index 3be5c3c..8dbf79a 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZones.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZones.ts @@ -1,5 +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`; +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 getZoneData = async (zoneId: string, organization: string) => { console.log("organization: ", organization); diff --git a/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts b/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts index 1ec0573..915160d 100644 --- a/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts +++ b/app/src/services/realTimeVisulization/zoneData/loadTemplate.ts @@ -1,5 +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`; +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 loadTempleteApi = async ( templateID: string, zoneId: string, diff --git a/app/src/services/realTimeVisulization/zoneData/panel.ts b/app/src/services/realTimeVisulization/zoneData/panel.ts index 6d93d1f..82f1289 100644 --- a/app/src/services/realTimeVisulization/zoneData/panel.ts +++ b/app/src/services/realTimeVisulization/zoneData/panel.ts @@ -1,5 +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`; +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; type Side = "top" | "bottom" | "left" | "right"; export const panelData = async ( diff --git a/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts b/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts index aa85b47..5c18031 100644 --- a/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts +++ b/app/src/services/realTimeVisulization/zoneData/saveTempleteApi.ts @@ -1,5 +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`; +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 saveTemplateApi = async (organization: string, template: {}) => { console.log('template: ', template); try { diff --git a/app/src/services/realTimeVisulization/zoneData/useFloatingDataStore.ts b/app/src/services/realTimeVisulization/zoneData/useFloatingDataStore.ts deleted file mode 100644 index 39a542a..0000000 --- a/app/src/services/realTimeVisulization/zoneData/useFloatingDataStore.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { create } from "zustand"; - -const useFloatingDataStore = create((set) => ({ - floatingdata: [], // Initial state - setfloatingadata: (newData: []) => set({ floatingdata: newData }), // Setter function -})); - -export default useFloatingDataStore; diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 6affa99..16064e1 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -11,16 +11,22 @@ export const useSocketStore = create((set: any, get: any) => ({ return; } - const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { + const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`, { reconnection: false, auth: { email, organization }, }); - set({ socket }); + const VisualizationSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, { + reconnection: false, + auth: { email, organization }, + }); + + set({ socket, VisualizationSocket }); }, disconnectSocket: () => { set((state: any) => { state.socket?.disconnect(); + state.VisualizationSocket?.disconnect(); return { socket: null }; }); }, diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index d58f12d..4c18feb 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -616,8 +616,6 @@ - - .distance-line { position: absolute; border-style: dashed; From 652dee0c4bbc4fc3181ea1da797bdf491e4af1db Mon Sep 17 00:00:00 2001 From: Vishnu Date: Tue, 1 Apr 2025 17:46:55 +0530 Subject: [PATCH 06/14] Update background color to use CSS variable and remove unused theme toggle logic --- app/src/styles/base/base.scss | 2 +- app/src/utils/theme.ts | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/app/src/styles/base/base.scss b/app/src/styles/base/base.scss index 0dea569..e74c0ec 100644 --- a/app/src/styles/base/base.scss +++ b/app/src/styles/base/base.scss @@ -75,7 +75,7 @@ height: 100vh; // Full viewport height width: 100vw; // Full viewport width overflow: hidden; // Prevent scrollbars - background-color: #232323; + background-color: var(--background-color-gray); } // Root overlay styles diff --git a/app/src/utils/theme.ts b/app/src/utils/theme.ts index 03d2454..754904b 100644 --- a/app/src/utils/theme.ts +++ b/app/src/utils/theme.ts @@ -20,12 +20,3 @@ export function toggleTheme() { // Initialize theme on page load setTheme(); - -// Example: Call toggleTheme() when a button is clicked -const toggleSwitch: Element | null = document.querySelector('#theme-switch'); - -if (toggleSwitch) { - toggleSwitch.addEventListener('click', toggleTheme); -} else { - console.warn("Theme switch button not found!"); -} From d2be2094eb9c3bacca316b037cf09e966a03b911 Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Tue, 1 Apr 2025 18:16:11 +0530 Subject: [PATCH 07/14] functionality for grid distance --- .../components/layout/sidebarLeft/Assets.tsx | 46 +++-- .../properties/GlobalProperties.tsx | 21 ++- .../templates/CollaborationPopup.tsx | 7 +- app/src/modules/market/Card.tsx | 1 - app/src/modules/market/MarketPlace.tsx | 1 - app/src/modules/scene/environment/ground.tsx | 64 +++++-- app/src/modules/scene/environment/shadow.tsx | 52 ++++-- app/src/store/store.ts | 26 ++- app/src/styles/layout/sidebar.scss | 2 - app/src/types/world/worldConstants.ts | 164 +++++++++--------- 10 files changed, 247 insertions(+), 137 deletions(-) diff --git a/app/src/components/layout/sidebarLeft/Assets.tsx b/app/src/components/layout/sidebarLeft/Assets.tsx index 3e2510e..c924b0c 100644 --- a/app/src/components/layout/sidebarLeft/Assets.tsx +++ b/app/src/components/layout/sidebarLeft/Assets.tsx @@ -24,26 +24,42 @@ interface AssetProp { price?: number; CreatedBy?: String; } +interface CategoryListProp { + assetImage?: string; + assetName?: string; + categoryImage: string; + category: string; +} const Assets: React.FC = () => { const { setSelectedItem } = useSelectedItem(); const [searchValue, setSearchValue] = useState(""); const [selectedCategory, setSelectedCategory] = useState(null); const [categoryAssets, setCategoryAssets] = useState([]); const [filtereredAssets, setFiltereredAssets] = useState([]); + const [categoryList, setCategoryList] = useState([]); const handleSearchChange = (value: string) => { + const searchTerm = value.toLowerCase(); setSearchValue(value); - setSelectedCategory(null); - const searchTerm = value.toLowerCase(); // Convert input to lowercase + if (searchTerm.trim() === "" && !selectedCategory) { + setCategoryAssets([]); + return; + } const filteredModels = filtereredAssets?.filter((model) => { - if (!model?.tags || !model?.filename) return false; + if (!model?.tags || !model?.filename || !model?.category) return false; if (searchTerm.startsWith(":") && searchTerm.length > 1) { const tagSearchTerm = searchTerm.slice(1); return model.tags.toLowerCase().includes(tagSearchTerm); - } else if (!searchTerm.startsWith(":")) { + } else if (selectedCategory) { + return ( + model.category + .toLowerCase() + .includes(selectedCategory.toLowerCase()) && + model.filename.toLowerCase().includes(searchTerm) + ); + } else { return model.filename.toLowerCase().includes(searchTerm); } - return false; }); setCategoryAssets(filteredModels); @@ -56,10 +72,10 @@ const Assets: React.FC = () => { } catch {} }; filteredAssets(); - }, []); + }, [categoryAssets]); - const categoryList = useMemo( - () => [ + useEffect(() => { + setCategoryList([ { assetName: "Doors", assetImage: "", @@ -82,10 +98,8 @@ const Assets: React.FC = () => { { category: "Workstation", categoryImage: workStation }, { category: "Machines", categoryImage: machines }, { category: "Workers", categoryImage: worker }, - ], - [] - ); - + ]); + }, []); const fetchCategoryAssets = async (asset: any) => { setSelectedCategory(asset); if (asset === "Feneration") { @@ -127,7 +141,7 @@ const Assets: React.FC = () => {
-

Results for "{searchValue}"

+

Results for {searchValue}

@@ -155,10 +169,12 @@ const Assets: React.FC = () => {
) : selectedCategory ? (
- {/* Back Button */}
setSelectedCategory(null)} + onClick={() => { + setSelectedCategory(null); + setCategoryAssets([]); + }} > ← Back
diff --git a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx index d65a10c..4e6a537 100644 --- a/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/GlobalProperties.tsx @@ -13,6 +13,7 @@ import { useSelectedWallItem, useShadows, useSocketStore, + useTileDistance, useToggleView, useWallVisibility, } from "../../../../store/store"; @@ -29,14 +30,18 @@ const GlobalProperties: React.FC = () => { const { elevation, setElevation } = useElevation(); const { azimuth, setAzimuth } = useAzimuth(); const { renderDistance, setRenderDistance } = useRenderDistance(); - + const { setPlaneValue, setGridValue, planeValue, gridValue } = + useTileDistance(); + useEffect(() => { + console.log(gridValue, planeValue, "values"); + }, [gridValue, planeValue]); const { socket } = useSocketStore(); const { limitDistance, setLimitDistance } = useLimitDistance(); const [distance, setDistance] = useState(40); useEffect(() => {}, [limitDistance]); const [limitGridDistance, setLimitGridDistance] = useState(false); - const [gridDistance, setGridDistance] = useState(5); + const [gridDistance, setGridDistance] = useState(3); const optimizeScene = async (value: any) => { const email = localStorage.getItem("email"); @@ -89,7 +94,15 @@ const GlobalProperties: React.FC = () => { } function updateGridDistance(value: number) { setGridDistance(value); + // setGridValue({ size: value * 100, divisions: (value * 100) / 4 }); + // setPlaneValue({ height: value * 100, width: value * 100 }); } + function updatedGrid(value: number) { + console.log(" (value * 100) / 4 : ", (value * 100) / 4); + setGridValue({ size: value * 100, divisions: (value * 100) / 4 }); + setPlaneValue({ height: value * 100, width: value * 100 }); + } + const updatedDist = async (value: number) => { const email = localStorage.getItem("email"); const organization = email?.split("@")[1]?.split(".")[0] || "defaultOrg"; @@ -266,6 +279,7 @@ const GlobalProperties: React.FC = () => { max={CONSTANTS.distanceConfig.maxDistance} onChange={(value: number) => updateDistance(value)} onPointerUp={updatedDist} + key={"6"} />
@@ -283,7 +297,10 @@ const GlobalProperties: React.FC = () => { disabled={!limitGridDistance} value={gridDistance} key={"7"} + min={1} + max={5} onChange={(value: number) => updateGridDistance(value)} + onPointerUp={updatedGrid} />
); diff --git a/app/src/components/templates/CollaborationPopup.tsx b/app/src/components/templates/CollaborationPopup.tsx index 8312fe7..d2e1c16 100644 --- a/app/src/components/templates/CollaborationPopup.tsx +++ b/app/src/components/templates/CollaborationPopup.tsx @@ -1,10 +1,11 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import RenderOverlay from "./Overlay"; import { ArrowIcon, CloseIcon } from "../icons/ExportCommonIcons"; import { AccessOption, User } from "../../types/users"; import RegularDropDown from "../ui/inputs/RegularDropDown"; import { access } from "fs"; import MultiEmailInvite from "../ui/inputs/MultiEmailInvite"; +import { useActiveUsers } from "../../store/store"; interface UserListTemplateProps { user: User; @@ -57,6 +58,10 @@ interface CollaborateProps { const CollaborationPopup: React.FC = ({ setUserManagement, }) => { + const { activeUsers } = useActiveUsers(); + useEffect(() => { + console.log("activeUsers: ", activeUsers); + }, [activeUsers]); const userName = localStorage.getItem("userName") || "Anonymous"; const users = [ { diff --git a/app/src/modules/market/Card.tsx b/app/src/modules/market/Card.tsx index c1a3289..ec9db06 100644 --- a/app/src/modules/market/Card.tsx +++ b/app/src/modules/market/Card.tsx @@ -38,7 +38,6 @@ const Card: React.FC = ({ description, onSelectCard, }) => { - console.log('description: ', description); const handleCardSelect = () => { onSelectCard({ assetName, uploadedOn, price, rating, views, description }); }; diff --git a/app/src/modules/market/MarketPlace.tsx b/app/src/modules/market/MarketPlace.tsx index cd2e0e9..dfcf62e 100644 --- a/app/src/modules/market/MarketPlace.tsx +++ b/app/src/modules/market/MarketPlace.tsx @@ -25,7 +25,6 @@ const MarketPlace = () => { const filteredAssets = async () => { try { const filt = await getAssetImages("67d934ad0f42a1fdadb19aa6"); - setModels(filt.items); setFilteredModels(filt.items); } catch {} diff --git a/app/src/modules/scene/environment/ground.tsx b/app/src/modules/scene/environment/ground.tsx index ebc017e..8d2fa22 100644 --- a/app/src/modules/scene/environment/ground.tsx +++ b/app/src/modules/scene/environment/ground.tsx @@ -1,22 +1,52 @@ -import { useToggleView } from '../../../store/store'; -import * as CONSTANTS from '../../../types/world/worldConstants'; +import { useTileDistance, useToggleView } from "../../../store/store"; +import * as CONSTANTS from "../../../types/world/worldConstants"; const Ground = ({ grid, plane }: any) => { - const { toggleView } = useToggleView(); - const savedTheme: string | null = localStorage.getItem('theme'); + const { toggleView } = useToggleView(); + const savedTheme: string | null = localStorage.getItem("theme"); + const { planeValue, gridValue } = useTileDistance(); - return ( - - - - - - - - - - - ) -} + return ( + + + + + + + + + + ); +}; export default Ground; diff --git a/app/src/modules/scene/environment/shadow.tsx b/app/src/modules/scene/environment/shadow.tsx index 62202b3..4625cde 100644 --- a/app/src/modules/scene/environment/shadow.tsx +++ b/app/src/modules/scene/environment/shadow.tsx @@ -1,9 +1,22 @@ -import { useRef, useEffect} from 'react'; -import { useThree } from '@react-three/fiber'; -import * as THREE from 'three'; -import { useAzimuth, useElevation, useShadows, useSunPosition, useFloorItems, useWallItems } from '../../../store/store'; -import * as CONSTANTS from '../../../types/world/worldConstants'; -const shadowWorker = new Worker(new URL('../../../services/factoryBuilder/webWorkers/shadowWorker', import.meta.url)); +import { useRef, useEffect } from "react"; +import { useThree } from "@react-three/fiber"; +import * as THREE from "three"; +import { + useAzimuth, + useElevation, + useShadows, + useSunPosition, + useFloorItems, + useWallItems, + useTileDistance, +} from "../../../store/store"; +import * as CONSTANTS from "../../../types/world/worldConstants"; +const shadowWorker = new Worker( + new URL( + "../../../services/factoryBuilder/webWorkers/shadowWorker", + import.meta.url + ) +); export default function Shadows() { const { shadows, setShadows } = useShadows(); @@ -15,6 +28,7 @@ export default function Shadows() { const { azimuth, setAzimuth } = useAzimuth(); const { floorItems } = useFloorItems(); const { wallItems } = useWallItems(); + const { planeValue } = useTileDistance(); useEffect(() => { gl.shadowMap.enabled = true; @@ -48,9 +62,9 @@ export default function Shadows() { useEffect(() => { if (controls && shadows) { updateShadows(); - (controls as any).addEventListener('update', updateShadows); + (controls as any).addEventListener("update", updateShadows); return () => { - (controls as any).removeEventListener('update', updateShadows); + (controls as any).removeEventListener("update", updateShadows); }; } }, [controls, elevation, azimuth, shadows]); @@ -75,10 +89,24 @@ export default function Shadows() { shadow-normalBias={CONSTANTS.shadowConfig.shadownormalBias} /> - - - + + {/* + */} + + ); -} \ No newline at end of file +} diff --git a/app/src/store/store.ts b/app/src/store/store.ts index d111aae..9de1f39 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -11,10 +11,13 @@ export const useSocketStore = create((set: any, get: any) => ({ return; } - const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { - reconnection: false, - auth: { email, organization }, - }); + const socket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, + { + reconnection: false, + auth: { email, organization }, + } + ); set({ socket }); }, @@ -401,3 +404,18 @@ export const useLimitDistance = create((set: any) => ({ limitDistance: true, setLimitDistance: (x: any) => set({ limitDistance: x }), })); + +export const useTileDistance = create((set: any) => ({ + gridValue: { size: 300, divisions: 75 }, + planeValue: { height: 300, width: 300 }, + + setGridValue: (value: any) => + set((state: any) => ({ + gridValue: { ...state.gridValue, ...value }, + })), + + setPlaneValue: (value: any) => + set((state: any) => ({ + planeValue: { ...state.planeValue, ...value }, + })), +})); diff --git a/app/src/styles/layout/sidebar.scss b/app/src/styles/layout/sidebar.scss index 92b4eb2..63297c9 100644 --- a/app/src/styles/layout/sidebar.scss +++ b/app/src/styles/layout/sidebar.scss @@ -1052,7 +1052,6 @@ position: relative; z-index: 3; font-size: var(--font-size-regular); - color: var(--background-color); } .asset-image { @@ -1103,7 +1102,6 @@ position: relative; z-index: 3; font-size: var(--font-size-regular); - color: var(--background-color); } .asset-image { diff --git a/app/src/types/world/worldConstants.ts b/app/src/types/world/worldConstants.ts index 2bc3835..fe0aafb 100644 --- a/app/src/types/world/worldConstants.ts +++ b/app/src/types/world/worldConstants.ts @@ -59,39 +59,39 @@ export type ThreeDimension = { }; export type GridConfig = { - size: number; - divisions: number; - primaryColor: string; - secondaryColor: string; - position2D: [x: number, y: number, z: number]; - position3D: [x: number, y: number, z: number]; -} + size: number; + divisions: number; + primaryColor: string; + secondaryColor: string; + position2D: [x: number, y: number, z: number]; + position3D: [x: number, y: number, z: number]; +}; export type PlaneConfig = { - position2D: [x: number, y: number, z: number]; - position3D: [x: number, y: number, z: number]; - rotation: number; - width: number; - height: number; - color: string; -} + position2D: [x: number, y: number, z: number]; + position3D: [x: number, y: number, z: number]; + rotation: number; + width: number; + height: number; + color: string; +}; export type ShadowConfig = { - shadowOffset: number, - shadowmapSizewidth: number, - shadowmapSizeheight: number, - shadowcamerafar: number, - shadowcameranear: number, - shadowcameratop: number, - shadowcamerabottom: number, - shadowcameraleft: number, - shadowcameraright: number, - shadowbias: number, - shadownormalBias: number, - shadowMaterialPosition: [x: number, y: number, z: number], - shadowMaterialRotation: [x: number, y: number, z: number], - shadowMaterialOpacity: number, -} + shadowOffset: number; + shadowmapSizewidth: number; + shadowmapSizeheight: number; + shadowcamerafar: number; + shadowcameranear: number; + shadowcameratop: number; + shadowcamerabottom: number; + shadowcameraleft: number; + shadowcameraright: number; + shadowbias: number; + shadownormalBias: number; + shadowMaterialPosition: [x: number, y: number, z: number]; + shadowMaterialRotation: [x: number, y: number, z: number]; + shadowMaterialOpacity: number; +}; export type SkyConfig = { defaultTurbidity: number; @@ -109,34 +109,34 @@ export type AssetConfig = { }; export type PointConfig = { - defaultInnerColor: string; - defaultOuterColor: string; - deleteColor: string; - boxScale: [number, number, number]; - wallOuterColor: string; - floorOuterColor: string; - aisleOuterColor: string; - zoneOuterColor: string; - snappingThreshold: number; -} + defaultInnerColor: string; + defaultOuterColor: string; + deleteColor: string; + boxScale: [number, number, number]; + wallOuterColor: string; + floorOuterColor: string; + aisleOuterColor: string; + zoneOuterColor: string; + snappingThreshold: number; +}; export type LineConfig = { - tubularSegments: number; - radius: number; - radialSegments: number; - wallName: string; - floorName: string; - aisleName: string; - zoneName: string; - referenceName: string; - lineIntersectionPoints: number; - defaultColor: string; - wallColor: string; - floorColor: string; - aisleColor: string; - zoneColor: string; - helperColor: string; -} + tubularSegments: number; + radius: number; + radialSegments: number; + wallName: string; + floorName: string; + aisleName: string; + zoneName: string; + referenceName: string; + lineIntersectionPoints: number; + defaultColor: string; + wallColor: string; + floorColor: string; + aisleColor: string; + zoneColor: string; + helperColor: string; +}; export type WallConfig = { defaultColor: string; @@ -145,10 +145,10 @@ export type WallConfig = { }; export type FloorConfig = { - defaultColor: string; - height: number; - textureScale: number; -} + defaultColor: string; + height: number; + textureScale: number; +}; export type RoofConfig = { defaultColor: string; @@ -156,16 +156,16 @@ export type RoofConfig = { }; export type AisleConfig = { - width: number; - height: number; - defaultColor: number; -} + width: number; + height: number; + defaultColor: number; +}; export type ZoneConfig = { - defaultColor: string; - height: number; - color: string; -} + defaultColor: string; + height: number; + color: string; +}; export type ColumnConfig = { defaultColor: string; @@ -242,24 +242,24 @@ export const threeDimension: ThreeDimension = { export const camPositionUpdateInterval: number = 200; // Interval for updating the camera position export const gridConfig: GridConfig = { - size: 300, // Size of the grid - divisions: 75, // Number of divisions in the grid - primaryColor: savedTheme === "dark" ? "#131313" : "#d5d5d5", // Primary color of the grid - secondaryColor: savedTheme === "dark" ? "#434343" : "#e3e3e3", // Secondary color of the grid + size: 300, // Size of the grid + divisions: 75, // Number of divisions in the grid + primaryColor: savedTheme === "dark" ? "#131313" : "#d5d5d5", // Primary color of the grid + secondaryColor: savedTheme === "dark" ? "#434343" : "#e3e3e3", // Secondary color of the grid - position2D: [0, 0.1, 0], // Position of the grid in 2D view - position3D: [0, -0.5, 0], // Position of the grid in 3D view -} + position2D: [0, 0.1, 0], // Position of the grid in 2D view + position3D: [0, -0.5, 0], // Position of the grid in 3D view +}; export const planeConfig: PlaneConfig = { position2D: [0, -0.5, 0], // Position of the plane position3D: [0, -0.65, 0], // Position of the plane rotation: -Math.PI / 2, // Rotation of the plane - width: 300, // Width of the plane - height: 300, // Height of the plane - color: savedTheme === "dark" ? "#323232" : "#f3f3f3" // Color of the plane -} + width: 300, // Width of the plane + height: 300, // Height of the plane + color: savedTheme === "dark" ? "#323232" : "#f3f3f3", // Color of the plane +}; export const shadowConfig: ShadowConfig = { shadowOffset: 50, // Offset of the shadow @@ -349,10 +349,10 @@ export const aisleConfig: AisleConfig = { }; export const zoneConfig: ZoneConfig = { - defaultColor: "black", // Default color of the zones - height: 3, - color: "#8656DF" // Color of the zones -} + defaultColor: "black", // Default color of the zones + height: 3, + color: "#8656DF", // Color of the zones +}; export const columnConfig: ColumnConfig = { defaultColor: "White", // Default color of the columns From 688b7eb4a0c7f5f6198fd0fded20050b395a0e21 Mon Sep 17 00:00:00 2001 From: gabriel Date: Tue, 1 Apr 2025 19:06:29 +0530 Subject: [PATCH 08/14] Add iot data and custom input card for floting cards --- .../visualization/widgets/Widgets2D.tsx | 8 +- .../FleetEfficiencyInputComponent.tsx | 178 ++++++++++++++++++ .../IotInputCards/InputSelecterComponent.tsx | 39 ++++ .../IotInputCards/Progress1Input.tsx | 171 +++++++++++++++++ .../IotInputCards/Progress2Input.tsx | 171 +++++++++++++++++ .../components/ui/componets/DisplayZone.tsx | 5 +- .../ui/componets/DraggableWidget.tsx | 36 +--- .../ui/componets/Dropped3dWidget.tsx | 1 + .../ui/realTimeVis/charts/ProgressCard1.tsx | 105 +++++++++++ .../ui/realTimeVis/charts/ProgressCard2.tsx | 125 ++++++++++++ .../floating/FleetEfficiencyComponent.tsx | 83 +++++++- .../floating/TotalCardComponent.tsx | 92 ++++++++- app/src/styles/pages/realTimeViz.scss | 7 +- 13 files changed, 976 insertions(+), 45 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx create mode 100644 app/src/components/ui/realTimeVis/charts/ProgressCard1.tsx create mode 100644 app/src/components/ui/realTimeVis/charts/ProgressCard2.tsx diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx index c3696e0..561c82b 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets2D.tsx @@ -59,9 +59,11 @@ const ProgressBarWidget = ({ id, title, data, + type }: { id: string; title: string; + type: string; data: any; }) => { const { setDraggedAsset } = useWidgetStore((state) => state); @@ -72,7 +74,7 @@ const ProgressBarWidget = ({ draggable onDragStart={() => { setDraggedAsset({ - type: "progress", + type: type, id, title, panel: "top", @@ -99,7 +101,7 @@ const ProgressBarWidget = ({
); }; -console.log(chartTypes,"chartTypes"); +console.log(chartTypes, "chartTypes"); const Widgets2D = () => { return ( @@ -124,6 +126,7 @@ const Widgets2D = () => { { key: "units", value: 1000, description: "Initial stock" }, ], }} + type={"progress 1"} /> { { key: "units", value: 500, description: "Additional stock" }, ], }} + type={"progress 2"} />
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx new file mode 100644 index 0000000..3a86ea9 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/FleetEfficiencyInputComponent.tsx @@ -0,0 +1,178 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +type Props = {}; + +const FleetEfficiencyInputComponent = (props: Props) => { + const [widgetName, setWidgetName] = useState('Widget'); + const { setFlotingMeasurements, updateFlotingDuration, updateHeader } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + const { selectedChartId } = useWidgetStore(); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + console.log(response.data); + + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.header) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setFlotingMeasurements(selections); + updateFlotingDuration(duration); + updateHeader(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/floatwidget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + header: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; + // }; + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + // setDuration(option); + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(1)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+
+ {/*
+
Duration
+
+ +
+
*/} +
+ + ); +}; + +export default FleetEfficiencyInputComponent; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx index 45ce802..04451d6 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx @@ -3,6 +3,9 @@ import LineGrapInput from './LineGrapInput' import BarChartInput from './BarChartInput' import PieChartInput from './PieChartInput' import FlotingWidgetInput from './FlotingWidgetInput' +import FleetEfficiencyInputComponent from './FleetEfficiencyInputComponent' +import Progress1Input from './Progress1Input' +import Progress2Input from './Progress2Input' import WarehouseThroughputInputComponent from './WarehouseThroughputInputComponent' import { useWidgetStore } from '../../../../../store/useWidgetStore' @@ -56,6 +59,24 @@ const InputSelecterComponent = () => { ) } + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'progress 1' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'progress 2' ) { + return ( + <> +
2D Widget Input
+ + + ) + } + else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'warehouseThroughput floating' ) { return ( <> @@ -65,6 +86,24 @@ const InputSelecterComponent = () => { ) } + else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'fleetEfficiency floating' ) { + return ( + <> +
Floting Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.className && selectedChartId.className === 'floating total-card' ) { + return ( + <> +
Floting Widget Input
+ + + ) + } + else { return (
No chart selected
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx new file mode 100644 index 0000000..545df45 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress1Input.tsx @@ -0,0 +1,171 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +type Props = {}; + +const Progress1Input = (props: Props) => { + const [widgetName, setWidgetName] = useState('Widget'); + const { setMeasurements, updateDuration, updateName } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + const { selectedChartId } = useWidgetStore(); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setMeasurements(selections); + updateDuration(duration); + updateName(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + panel: selectedChartId.panel, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + }; + + const handleNameChange = async (name:any) => { + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(1)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+ {/*
+
+
Duration
+
+ +
+
+
*/} + + ); +}; + +export default Progress1Input; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx new file mode 100644 index 0000000..3a11a29 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Progress2Input.tsx @@ -0,0 +1,171 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +type Props = {}; + +const Progress2Input = (props: Props) => { + const [widgetName, setWidgetName] = useState('Widget'); + const { setMeasurements, updateDuration, updateName } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + const { selectedChartId } = useWidgetStore(); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setMeasurements(selections); + updateDuration(duration); + updateName(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + panel: selectedChartId.panel, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + }; + + const handleNameChange = async (name:any) => { + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(2)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+ {/*
+
+
Duration
+
+ +
+
+
*/} + + ); +}; + +export default Progress2Input; \ No newline at end of file diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index 3889139..9ce64cb 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef, useState, useCallback } from "react"; -import { Widget } from "../../../store/useWidgetStore"; +import { useWidgetStore, Widget } from "../../../store/useWidgetStore"; import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons"; import { InfoIcon } from "../../icons/ExportCommonIcons"; import { useDroppedObjectsStore, useFloatingWidget } from "../../../store/useDroppedObjectsStore"; @@ -74,6 +74,7 @@ const DisplayZone: React.FC = ({ const [showLeftArrow, setShowLeftArrow] = useState(false); const [showRightArrow, setShowRightArrow] = useState(false); const { floatingWidget, setFloatingWidget } = useFloatingWidget() + const{setSelectedChartId}=useWidgetStore() // Function to calculate overflow state const updateOverflowState = useCallback(() => { @@ -152,9 +153,9 @@ const DisplayZone: React.FC = ({ async function handleSelect2dZoneData(zoneId: string, zoneName: string) { try { if (selectedZone?.zoneId === zoneId) { - return; } + setSelectedChartId(null) const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; // Fetch data from backend diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx index db8c408..11b4bfb 100644 --- a/app/src/components/ui/componets/DraggableWidget.tsx +++ b/app/src/components/ui/componets/DraggableWidget.tsx @@ -5,6 +5,8 @@ import BarGraphComponent from "../realTimeVis/charts/BarGraphComponent"; import LineGraphComponent from "../realTimeVis/charts/LineGraphComponent"; import DoughnutGraphComponent from "../realTimeVis/charts/DoughnutGraphComponent"; import PolarAreaGraphComponent from "../realTimeVis/charts/PolarAreaGraphComponent"; +import ProgressCard1 from "../realTimeVis/charts/ProgressCard1"; +import ProgressCard2 from "../realTimeVis/charts/ProgressCard2"; import { DeleteIcon, DublicateIcon, @@ -203,6 +205,7 @@ export const DraggableWidget = ({ onReorder(fromIndex, toIndex); // Call the reorder function passed as a prop } }; + console.log("widget.type", widget.type); return ( <> @@ -249,9 +252,12 @@ export const DraggableWidget = ({ )} {/* Render charts based on widget type */} - - {widget.type === "progress" && ( - + + {widget.type === "progress 1" && ( + + )} + {widget.type === "progress 2" && ( + )} {widget.type === "line" && ( )} {widget.type === "bar" && ( @@ -277,14 +275,6 @@ export const DraggableWidget = ({ title={widget.title} fontSize={widget.fontSize} fontWeight={widget.fontWeight} - // data={{ - // measurements: [ - // { name: "testDevice", fields: "powerConsumption" }, - // { name: "furnace", fields: "powerConsumption" }, - // ], - // interval: 1000, - // duration: "1h", - // }} /> )} {widget.type === "pie" && ( @@ -294,14 +284,6 @@ export const DraggableWidget = ({ title={widget.title} fontSize={widget.fontSize} fontWeight={widget.fontWeight} - // data={{ - // measurements: [ - // { name: "testDevice", fields: "powerConsumption" }, - // { name: "furnace", fields: "powerConsumption" }, - // ], - // interval: 1000, - // duration: "1h", - // }} /> )} {widget.type === "doughnut" && ( diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index 94c5e45..0a3534a 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -126,6 +126,7 @@ export default function Dropped3dWidgets() { return ( <> {activeZoneWidgets.map(({ id, type, position }) => { + console.log('Typeeeeeeeeeeee',type); switch (type) { case "ui-Widget 1": return ; diff --git a/app/src/components/ui/realTimeVis/charts/ProgressCard1.tsx b/app/src/components/ui/realTimeVis/charts/ProgressCard1.tsx new file mode 100644 index 0000000..8fe8777 --- /dev/null +++ b/app/src/components/ui/realTimeVis/charts/ProgressCard1.tsx @@ -0,0 +1,105 @@ +import { StockIncreseIcon } from "../../../icons/RealTimeVisulationIcons"; +import React, { useEffect, useMemo, useState } from "react"; +import { Line } from "react-chartjs-2"; +import io from "socket.io-client"; +import useChartStore from "../../../../store/useChartStore"; +import { useWidgetStore } from "../../../../store/useWidgetStore"; +import axios from "axios"; + +const ProgressCard1 = ({ id,title,}: { + id: string, + title: string; +}) => { + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h") + const [name, setName] = useState(title) + const [value, setValue] = useState('') + const { selectedChartId } = useWidgetStore(); + + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + + + useEffect(() => { + const socket = io(`http://${iotApiUrl}`); + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + + const startStream = () => { + socket.emit("lastInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lastOutput", (response) => { + const responseData = response.input1; + setValue(responseData); + + }); + + return () => { + socket.off("lastOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [measurements, duration]); + + const fetchSavedInputes = async() => { + + if (id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === id) { + fetchSavedInputes(); + } + } + ,[chartMeasurements, chartDuration, widgetName]) + + return( +
+
{name}
+
+ + +
{value}
+
Units
+ +
+
{ + measurements ? `${measurements?.input1?.fields}` : 'description'}
+
+
+ +
+
+
+ ) +}; + +export default ProgressCard1; \ No newline at end of file diff --git a/app/src/components/ui/realTimeVis/charts/ProgressCard2.tsx b/app/src/components/ui/realTimeVis/charts/ProgressCard2.tsx new file mode 100644 index 0000000..083bbed --- /dev/null +++ b/app/src/components/ui/realTimeVis/charts/ProgressCard2.tsx @@ -0,0 +1,125 @@ +import { StockIncreseIcon } from "../../../icons/RealTimeVisulationIcons"; +import React, { useEffect, useMemo, useState } from "react"; +import { Line } from "react-chartjs-2"; +import io from "socket.io-client"; +import useChartStore from "../../../../store/useChartStore"; +import { useWidgetStore } from "../../../../store/useWidgetStore"; +import axios from "axios"; + +const ProgressCard2 = ({ id,title,}: { + id: string, + title: string; +}) => { + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h") + const [name, setName] = useState(title) + const [value1, setValue1] = useState('') + const [value2, setValue2] = useState('') + const { selectedChartId } = useWidgetStore(); + + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + + + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + + const socket = io(`http://${iotApiUrl}`); + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + + const startStream = () => { + socket.emit("lastInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lastOutput", (response) => { + const responseData1 = response.input1; + const responseData2 = response.input2; + setValue1(responseData1); + setValue2(responseData2); + }); + + return () => { + socket.off("lastOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [measurements, duration]); + + const fetchSavedInputes = async() => { + + if (id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/WidgetData/${id}/${organization}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === id) { + fetchSavedInputes(); + } + } + ,[chartMeasurements, chartDuration, widgetName]) + + return( +
+
{name}
+ +
+ + +
{value1}
+
Units
+ +
+
{ + measurements ? `${measurements?.input1?.fields}` : 'description'}
+
+
+ +
+
+ +
+ + +
{value2}
+
Units
+ +
+
{ + measurements ? `${measurements?.input2?.fields}` : 'description'}
+
+
+ +
+
+ +
+ ) +}; + +export default ProgressCard2; \ No newline at end of file diff --git a/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx b/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx index e9221e8..2cf12e0 100644 --- a/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx +++ b/app/src/components/ui/realTimeVis/floating/FleetEfficiencyComponent.tsx @@ -1,14 +1,93 @@ -import React,{ useEffect, useState} from 'react' +import React, { useState, useEffect } from 'react' +import { Line } from 'react-chartjs-2' +import useChartStore from '../../../../store/useChartStore'; +import { useWidgetStore } from '../../../../store/useWidgetStore'; +import axios from 'axios'; +import io from "socket.io-client"; const FleetEfficiencyComponent = ({object}: any) => { const [ progress, setProgress ] = useState(0) + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h") + const [name, setName] = useState(object.header ? object.header : '') + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + const { header, flotingDuration, flotingMeasurements } = useChartStore(); + const { selectedChartId } = useWidgetStore(); + + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; // Calculate the rotation angle for the progress bar const rotationAngle = 45 + progress * 1.8; + + + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + + const socket = io(`http://${iotApiUrl}`); + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + + const startStream = () => { + socket.emit("lastInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lastOutput", (response) => { + const responseData = response.input1; + console.log(responseData); + + if (typeof responseData === "number") { + console.log("It's a number!"); + setProgress(responseData); + } + }); + + return () => { + socket.off("lastOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [measurements, duration, iotApiUrl]); + + const fetchSavedInputes = async() => { + + if (object?.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.header) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === object?.id) { + fetchSavedInputes(); + } + } + ,[header, flotingDuration, flotingMeasurements]) return ( <> -

Fleet Efficiency

+

{name}

diff --git a/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx b/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx index 00ec479..da03fce 100644 --- a/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx +++ b/app/src/components/ui/realTimeVis/floating/TotalCardComponent.tsx @@ -1,21 +1,95 @@ -import React from 'react' -import { WalletIcon } from '../../../icons/3dChartIcons' +import React, { useState, useEffect } from 'react' +import { Line } from 'react-chartjs-2' +import useChartStore from '../../../../store/useChartStore'; import { useWidgetStore } from '../../../../store/useWidgetStore'; +import axios from 'axios'; +import io from "socket.io-client"; +import { WalletIcon } from '../../../icons/3dChartIcons'; + const TotalCardComponent = ({ object }: any) => { - const { setSelectedChartId } = - useWidgetStore(); + const [ progress, setProgress ] = useState(0) + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h") + const [name, setName] = useState(object.header ? object.header : '') + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + const { header, flotingDuration, flotingMeasurements } = useChartStore(); + const { selectedChartId } = useWidgetStore(); + + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + + const socket = io(`http://${iotApiUrl}`); + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + + const startStream = () => { + socket.emit("lastInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lastOutput", (response) => { + const responseData = response.input1; + + if (typeof responseData === "number") { + setProgress(responseData); + } + }); + + return () => { + socket.off("lastOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [measurements, duration, iotApiUrl]); + + const fetchSavedInputes = async() => { + + if (object?.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/A_floatWidget/${object?.id}/${organization}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.header) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === object?.id) { + fetchSavedInputes(); + } + } + ,[header, flotingDuration, flotingMeasurements]) + return ( <> -
{ - setSelectedChartId(object.id) - }}> -
{object.header}
+
+
{name}
-
{object.value}
+
{progress}
{object.per}
diff --git a/app/src/styles/pages/realTimeViz.scss b/app/src/styles/pages/realTimeViz.scss index 4440e6d..17407cb 100644 --- a/app/src/styles/pages/realTimeViz.scss +++ b/app/src/styles/pages/realTimeViz.scss @@ -546,9 +546,9 @@ .floating-wrapper { .icon { - width: 25px !important; - height: 25px !important; - background-color: transparent; + // width: 25px !important; + // height: 25px !important; + // background-color: transparent; } .kebab { @@ -560,6 +560,7 @@ z-index: 10; cursor: pointer; @include flex-center; + background-color: transparent !important; } .kebab-options { From b828cb24372d542cc4a1a45094b350e3ecf851bc Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Tue, 1 Apr 2025 19:35:11 +0530 Subject: [PATCH 09/14] socket added for 2d widget --- .../3D-cards/cards/ProductionCapacity.tsx | 3 +- .../3D-cards/cards/ReturnOfInvestment.tsx | 1 + .../layout/3D-cards/cards/StateWorking.tsx | 1 + .../layout/3D-cards/cards/Throughput.tsx | 1 + .../components/ui/componets/AddButtons.tsx | 79 ++++++++++------- .../ui/componets/DraggableWidget.tsx | 88 ++++++++++++------- .../ui/componets/Dropped3dWidget.tsx | 2 + .../ui/componets/DroppedFloatingWidgets.tsx | 32 +++---- app/src/components/ui/componets/Panel.tsx | 44 ++++++---- .../ui/componets/RealTimeVisulization.tsx | 4 + .../visualization/realTimeVizSocket.dev.tsx | 65 ++++++++++++++ app/src/store/store.ts | 35 +++++--- 12 files changed, 245 insertions(+), 110 deletions(-) create mode 100644 app/src/modules/visualization/realTimeVizSocket.dev.tsx diff --git a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx index 785f20d..b932417 100644 --- a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx +++ b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx @@ -79,9 +79,10 @@ const ProductionCapacity: React.FC = ({ position }) => }; return ( -
diff --git a/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx b/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx index 8e8c444..740c7be 100644 --- a/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx +++ b/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx @@ -111,6 +111,7 @@ const ReturnOfInvestment: React.FC = ({ position }) =>
Return of Investment
diff --git a/app/src/components/layout/3D-cards/cards/StateWorking.tsx b/app/src/components/layout/3D-cards/cards/StateWorking.tsx index 25ee39b..1c3ac4e 100644 --- a/app/src/components/layout/3D-cards/cards/StateWorking.tsx +++ b/app/src/components/layout/3D-cards/cards/StateWorking.tsx @@ -16,6 +16,7 @@ const StateWorking: React.FC = ({ position }) => {
diff --git a/app/src/components/layout/3D-cards/cards/Throughput.tsx b/app/src/components/layout/3D-cards/cards/Throughput.tsx index 220c2a2..543d5f1 100644 --- a/app/src/components/layout/3D-cards/cards/Throughput.tsx +++ b/app/src/components/layout/3D-cards/cards/Throughput.tsx @@ -94,6 +94,7 @@ const Throughput: React.FC = ({ position }) => {
Throughput
diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index d06be19..d5bfb29 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import { CleanPannel, EyeIcon, @@ -7,6 +7,7 @@ import { import { panelData } from "../../../services/realTimeVisulization/zoneData/panel"; import { AddIcon } from "../../icons/ExportCommonIcons"; import { deletePanelApi } from "../../../services/realTimeVisulization/zoneData/deletePanel"; +import { useSocketStore } from "../../../store/store"; // Define the type for `Side` type Side = "top" | "bottom" | "left" | "right"; @@ -17,7 +18,6 @@ interface ButtonsProps { zoneName: string; activeSides: Side[]; panelOrder: Side[]; - lockedPanels: Side[]; zoneId: string; zoneViewPortTarget: number[]; @@ -59,6 +59,9 @@ const AddButtons: React.FC = ({ setHiddenPanels, hiddenPanels, }) => { + + const { visualizationSocket } = useSocketStore(); + // Local state to track hidden panels // Function to toggle lock/unlock a panel @@ -109,65 +112,81 @@ const AddButtons: React.FC = ({ // Panel already exists: Remove widgets from that side and update activeSides const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; // Fallback value - + // Remove all widgets associated with the side and update active sides const cleanedWidgets = selectedZone.widgets.filter( (widget) => widget.panel !== side ); const newActiveSides = selectedZone.activeSides.filter((s) => s !== side); - + const updatedZone = { ...selectedZone, widgets: cleanedWidgets, activeSides: newActiveSides, panelOrder: newActiveSides, }; - - // API call to delete the panel - try { - const response = await deletePanelApi(selectedZone.zoneId, side, organization); - console.log('response: ', response); - if (response.message === "Panel deleted successfully") { - setSelectedZone(updatedZone); - } else { - console.error("Unexpected response:", response); - } - } catch (error) { - console.error("Error deleting panel:", error); + + let deletePanel = { + organization: organization, + panelName: side, + zoneId: selectedZone.zoneId } + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-panel:delete", deletePanel) + } + setSelectedZone(updatedZone); + + // API call to delete the panel + // try { + // const response = await deletePanelApi(selectedZone.zoneId, side, organization); + // + // if (response.message === "Panel deleted successfully") { + // } else { + // + // } + // } catch (error) { + // + // } } else { // Panel does not exist: Create panel try { // Get email and organization safely with a default fallback const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0] ; - + const organization = email?.split("@")[1]?.split(".")[0]; + // Prevent duplicate side entries const newActiveSides = selectedZone.activeSides.includes(side) ? [...selectedZone.activeSides] : [...selectedZone.activeSides, side]; - + const updatedZone = { ...selectedZone, activeSides: newActiveSides, panelOrder: newActiveSides, }; - - // API call to create panels - const response = await panelData(organization, selectedZone.zoneId, newActiveSides); - console.log('response: ', response); - - if (response.message === "Panels created successfully") { - setSelectedZone(updatedZone); - } else { - console.error("Unexpected response:", response); + let addPanel = { + organization: organization, + zoneId: selectedZone.zoneId, + panelOrder: newActiveSides } + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-panel:add", addPanel) + } + setSelectedZone(updatedZone); + // API call to create panels + // const response = await panelData(organization, selectedZone.zoneId, newActiveSides); + // + + // if (response.message === "Panels created successfully") { + // } else { + // + // } } catch (error) { - console.error("Error creating panels:", error); + } } }; - + return ( <> diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx index db8c408..096779e 100644 --- a/app/src/components/ui/componets/DraggableWidget.tsx +++ b/app/src/components/ui/componets/DraggableWidget.tsx @@ -13,6 +13,7 @@ import { import { useEffect, useRef, useState } from "react"; import { duplicateWidgetApi } from "../../../services/realTimeVisulization/zoneData/duplicateWidget"; import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteWidgetApi"; +import { useSocketStore } from "../../../store/store"; type Side = "top" | "bottom" | "left" | "right"; @@ -69,6 +70,7 @@ export const DraggableWidget = ({ openKebabId: string | null; setOpenKebabId: (id: string | null) => void; }) => { + const { visualizationSocket } = useSocketStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore(); const [panelDimensions, setPanelDimensions] = useState<{ [side in Side]?: { width: number; height: number }; @@ -85,16 +87,34 @@ export const DraggableWidget = ({ try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - const response = await deleteWidgetApi(widget.id, organization); - if (response?.message === "Widget deleted successfully") { - const updatedWidgets = selectedZone.widgets.filter( - (w: Widget) => w.id !== widget.id - ); - setSelectedZone((prevZone: any) => ({ - ...prevZone, - widgets: updatedWidgets, - })); + let deleteWidget = { + zoneId: selectedZone.zoneId, + widgetID: widget.id, + organization: organization } + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-widget:delete", deleteWidget) + } + const updatedWidgets = selectedZone.widgets.filter( + (w: Widget) => w.id !== widget.id + ); + console.log('updatedWidgets: ', updatedWidgets); + setSelectedZone((prevZone: any) => ({ + ...prevZone, + widgets: updatedWidgets, + })); + setOpenKebabId(null); + + // const response = await deleteWidgetApi(widget.id, organization); + // if (response?.message === "Widget deleted successfully") { + // const updatedWidgets = selectedZone.widgets.filter( + // (w: Widget) => w.id !== widget.id + // ); + // setSelectedZone((prevZone: any) => ({ + // ...prevZone, + // widgets: updatedWidgets, + // })); + // } } catch (error) { } finally { @@ -249,7 +269,7 @@ export const DraggableWidget = ({ )} {/* Render charts based on widget type */} - + {widget.type === "progress" && ( )} @@ -260,14 +280,14 @@ export const DraggableWidget = ({ title={widget.title} fontSize={widget.fontSize} fontWeight={widget.fontWeight} - // data={{ - // measurements: [ - // { name: "testDevice", fields: "powerConsumption" }, - // { name: "furnace", fields: "powerConsumption" }, - // ], - // interval: 1000, - // duration: "1h", - // }} + // data={{ + // measurements: [ + // { name: "testDevice", fields: "powerConsumption" }, + // { name: "furnace", fields: "powerConsumption" }, + // ], + // interval: 1000, + // duration: "1h", + // }} /> )} {widget.type === "bar" && ( @@ -277,14 +297,14 @@ export const DraggableWidget = ({ title={widget.title} fontSize={widget.fontSize} fontWeight={widget.fontWeight} - // data={{ - // measurements: [ - // { name: "testDevice", fields: "powerConsumption" }, - // { name: "furnace", fields: "powerConsumption" }, - // ], - // interval: 1000, - // duration: "1h", - // }} + // data={{ + // measurements: [ + // { name: "testDevice", fields: "powerConsumption" }, + // { name: "furnace", fields: "powerConsumption" }, + // ], + // interval: 1000, + // duration: "1h", + // }} /> )} {widget.type === "pie" && ( @@ -294,14 +314,14 @@ export const DraggableWidget = ({ title={widget.title} fontSize={widget.fontSize} fontWeight={widget.fontWeight} - // data={{ - // measurements: [ - // { name: "testDevice", fields: "powerConsumption" }, - // { name: "furnace", fields: "powerConsumption" }, - // ], - // interval: 1000, - // duration: "1h", - // }} + // data={{ + // measurements: [ + // { name: "testDevice", fields: "powerConsumption" }, + // { name: "furnace", fields: "powerConsumption" }, + // ], + // interval: 1000, + // duration: "1h", + // }} /> )} {widget.type === "doughnut" && ( diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index b970872..7ce1617 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -35,6 +35,7 @@ export default function Dropped3dWidgets() { async function get3dWidgetData() { let result = await get3dWidgetZoneData(selectedZone.zoneId, organization); + console.log('result: ', result); setWidgets3D(result) // Ensure the extracted data has id, type, and position correctly mapped const formattedWidgets = result.map((widget: any) => ({ @@ -107,6 +108,7 @@ export default function Dropped3dWidgets() { // Get widgets for the currently active zone const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; + console.log('activeZoneWidgets: ', activeZoneWidgets); return ( <> diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index cc9883d..9c3f4c4 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -79,21 +79,21 @@ const DroppedObjects: React.FC = () => { } }; }, []); - // useEffect(() => { - // const handleClickOutside = (event: MouseEvent) => { - // if (kebabRef.current && !kebabRef.current.contains(event.target as Node)) { - // setOpenKebabId(null); - // } - // }; - - // // Add event listener when component mounts - // document.addEventListener("mousedown", handleClickOutside); - - // // Clean up event listener when component unmounts - // return () => { - // document.removeEventListener("mousedown", handleClickOutside); - // }; - // }, []); + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (kebabRef.current && !kebabRef.current.contains(event.target as Node)) { + setOpenKebabId(null); + } + }; + + // Add event listener when component mounts + document.addEventListener("mousedown", handleClickOutside); + + // Clean up event listener when component unmounts + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, []); const zoneEntries = Object.entries(zones); if (zoneEntries.length === 0) return null; @@ -378,7 +378,7 @@ const DroppedObjects: React.FC = () => {
{openKebabId === obj.id && ( -
+
{ event.stopPropagation(); handleDuplicate(zoneName, index); // Call the duplicate handler diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index 61956b9..56cdc06 100644 --- a/app/src/components/ui/componets/Panel.tsx +++ b/app/src/components/ui/componets/Panel.tsx @@ -4,7 +4,7 @@ import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import { DraggableWidget } from "./DraggableWidget"; import { arrayMove } from "@dnd-kit/sortable"; import { addingWidgets } from "../../../services/realTimeVisulization/zoneData/addWidgets"; -import { useAsset3dWidget } from "../../../store/store"; +import { useAsset3dWidget, useSocketStore } from "../../../store/store"; type Side = "top" | "bottom" | "left" | "right"; @@ -62,6 +62,7 @@ const Panel: React.FC = ({ const [openKebabId, setOpenKebabId] = useState(null); const { isPlaying } = usePlayButtonStore(); + const { visualizationSocket } = useSocketStore(); const getPanelStyle = useMemo( () => (side: Side) => { @@ -102,10 +103,7 @@ const Panel: React.FC = ({ ); const handleDrop = (e: React.DragEvent, panel: Side) => { - - e.preventDefault(); - setWidgetSelect("") const { draggedAsset } = useWidgetStore.getState(); if (!draggedAsset) return; if (isPanelLocked(panel)) return; @@ -114,7 +112,6 @@ const Panel: React.FC = ({ const maxCapacity = calculatePanelCapacity(panel); if (currentWidgetsCount >= maxCapacity) return; - addWidgetToPanel(draggedAsset, panel); }; @@ -151,18 +148,33 @@ const Panel: React.FC = ({ id: generateUniqueId(), panel, }; - try { - let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); - - if (response.message === "Widget created successfully") { - setSelectedZone((prev) => ({ - ...prev, - widgets: [...prev.widgets, newWidget], - })); - } - } catch (error) { - console.error("Error adding widget:", error); + let addWidget = { + organization: organization, + zoneId: selectedZone.zoneId, + widget: newWidget } + console.log('newWidget: ', newWidget); + console.log('addWidget: ', addWidget); + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-widget:add", addWidget) + } + setSelectedZone((prev) => ({ + ...prev, + widgets: [...prev.widgets, newWidget], + })); + + // try { + // let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); + + // if (response.message === "Widget created successfully") { + // setSelectedZone((prev) => ({ + // ...prev, + // widgets: [...prev.widgets, newWidget], + // })); + // } + // } catch (error) { + // console.error("Error adding widget:", error); + // } }; diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index 387729d..4a40270 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -11,6 +11,7 @@ import DroppedObjects from "./DroppedFloatingWidgets"; import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; import { useAsset3dWidget, + useSocketStore, useWidgetSubOption, useZones, } from "../../../store/store"; @@ -18,6 +19,7 @@ import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/g import { generateUniqueId } from "../../../functions/generateUniqueId"; import { determinePosition } from "./functions/determinePosition"; import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets"; +import SocketRealTimeViz from "../../../modules/visualization/realTimeVizSocket.dev"; type Side = "top" | "bottom" | "left" | "right"; @@ -56,6 +58,7 @@ const RealTimeVisulization: React.FC = () => { >({}); const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); + const { visualizationSocket } = useSocketStore(); useEffect(() => { async function GetZoneData() { @@ -204,6 +207,7 @@ const RealTimeVisulization: React.FC = () => {
{activeModule === "visualization" && selectedZone.zoneName !== "" && } + {activeModule === "visualization" && } {/* */} {activeModule === "visualization" && ( <> diff --git a/app/src/modules/visualization/realTimeVizSocket.dev.tsx b/app/src/modules/visualization/realTimeVizSocket.dev.tsx new file mode 100644 index 0000000..4210d01 --- /dev/null +++ b/app/src/modules/visualization/realTimeVizSocket.dev.tsx @@ -0,0 +1,65 @@ +import { useEffect } from "react"; +import { useSocketStore } from "../../store/store"; +import { useSelectedZoneStore } from "../../store/useZoneStore"; + +export default function SocketRealTimeViz() { + const { visualizationSocket } = useSocketStore(); + const { selectedZone, setSelectedZone } = useSelectedZoneStore(); + 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) => { + if (addPanel.success) { + let addPanelData = addPanel.data.data + setSelectedZone(addPanelData) + } + }) + //delete panel response + visualizationSocket.on("viz-panel:response:delete", (deletePanel: any) => { + if (deletePanel.success) { + let deletePanelData = deletePanel.data.data + setSelectedZone(deletePanelData) + } + }) + // add 2dWidget + visualizationSocket.on("viz-widget:response:updates", (response: any) => { + console.log('response: ', response); + if (response.success && response.data) { + setSelectedZone((prev) => { + const isWidgetAlreadyAdded = prev.widgets.some( + (widget) => widget.id === response.data.widgetData.id + ); + if (isWidgetAlreadyAdded) return prev; // Prevent duplicate addition + return { + ...prev, + zoneId: response.data.zoneId, + zoneName: response.data.zoneName, + widgets: [...prev.widgets, response.data.widgetData], // Append new widget + }; + }); + } + }); + //delete 2D Widget + visualizationSocket.on("viz-widget:response:delete", (deleteWidget: any) => { + console.log('deleteWidget: ', deleteWidget); + if (deleteWidget?.success && deleteWidget.data) { + setSelectedZone((prevZone: any) => ({ + ...prevZone, + zoneId: deleteWidget.data.zoneId, + zoneName: deleteWidget.data.zoneName, + widgets: deleteWidget.data.widgetDeleteDatas, // Replace with new widget list + })); + } + }); + } + }, []) + + useEffect(() => { + + }, [selectedZone]) + return ( + <> + ) +} \ No newline at end of file diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 16064e1..152fa9d 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -11,22 +11,28 @@ export const useSocketStore = create((set: any, get: any) => ({ return; } - const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`, { - reconnection: false, - auth: { email, organization }, - }); + const socket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`, + { + reconnection: false, + auth: { email, organization }, + } + ); - const VisualizationSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, { - reconnection: false, - auth: { email, organization }, - }); + const visualizationSocket = io( + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, + { + reconnection: false, + auth: { email, organization }, + } + ); - set({ socket, VisualizationSocket }); + set({ socket, visualizationSocket }); }, disconnectSocket: () => { set((state: any) => { state.socket?.disconnect(); - state.VisualizationSocket?.disconnect(); + state.visualizationSocket?.disconnect(); return { socket: null }; }); }, @@ -211,7 +217,9 @@ export const useActiveLayer = create((set: any) => ({ interface RefTextUpdateState { refTextupdate: number; - setRefTextUpdate: (callback: (currentValue: number) => number | number) => void; + setRefTextUpdate: ( + callback: (currentValue: number) => number | number + ) => void; } export const useRefTextUpdate = create((set) => ({ @@ -219,7 +227,9 @@ export const useRefTextUpdate = create((set) => ({ setRefTextUpdate: (callback) => set((state) => ({ refTextupdate: - typeof callback === "function" ? callback(state.refTextupdate) : callback, + typeof callback === "function" + ? callback(state.refTextupdate) + : callback, })), })); @@ -399,4 +409,3 @@ export const useWidgetSubOption = create((set: any) => ({ widgetSubOption: "2D", setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), })); - From f0f7064b0ae87754b0276141651787d40ac7be5f Mon Sep 17 00:00:00 2001 From: gabriel Date: Wed, 2 Apr 2025 18:06:51 +0530 Subject: [PATCH 10/14] added iot data and input card for 3D widget --- .../3D-cards/cards/ProductionCapacity.tsx | 113 ++++++++++- .../3D-cards/cards/ReturnOfInvestment.tsx | 110 ++++++++++- .../layout/3D-cards/cards/StateWorking.tsx | 133 +++++++++++-- .../layout/3D-cards/cards/Throughput.tsx | 109 ++++++++++- .../IotInputCards/InputSelecterComponent.tsx | 39 ++++ .../IotInputCards/Widget2InputCard3D.tsx | 165 ++++++++++++++++ .../IotInputCards/Widget3InputCard3D.tsx | 158 ++++++++++++++++ .../IotInputCards/Widget4InputCard3D.tsx | 178 ++++++++++++++++++ .../ui/componets/Dropped3dWidget.tsx | 8 +- 9 files changed, 982 insertions(+), 31 deletions(-) create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx create mode 100644 app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx diff --git a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx index 4da32bc..05c2814 100644 --- a/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx +++ b/app/src/components/layout/3D-cards/cards/ProductionCapacity.tsx @@ -1,5 +1,5 @@ import { Html } from "@react-three/drei"; -import React from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { Bar } from "react-chartjs-2"; import { Chart as ChartJS, @@ -11,6 +11,11 @@ import { Legend, TooltipItem, // Import TooltipItem for typing } from "chart.js"; +import { ThroughputIcon } from "../../../icons/3dChartIcons"; +import { useWidgetStore } from "../../../../store/useWidgetStore"; +import useChartStore from "../../../../store/useChartStore"; +import axios from "axios"; +import io from "socket.io-client"; // Register ChartJS components ChartJS.register( @@ -22,12 +27,28 @@ ChartJS.register( Legend ); interface ProductionCapacityProps { + id: string; + type: string; position: [number, number, number]; } -const ProductionCapacity : React.FC = ({ position }) => { +const ProductionCapacity : React.FC = ({ id, type, position }) => { + + const { selectedChartId,setSelectedChartId } = useWidgetStore(); + + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h") + const [name, setName] = useState("Widget") + const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + labels: [], + datasets: [], + }); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] // Chart data for a week - const chartData = { + const defaultChartData = { labels: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], // Days of the week datasets: [ { @@ -78,12 +99,94 @@ const ProductionCapacity : React.FC = ({ position }) => }, }; + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + + const socket = io(`http://${iotApiUrl}`); + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + + const startStream = () => { + socket.emit("lineInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lineOutput", (response) => { + const responseData = response.data; + + // Extract timestamps and values + const labels = responseData.time; + const datasets = Object.keys(measurements).map((key) => { + const measurement = measurements[key]; + const datasetKey = `${measurement.name}.${measurement.fields}`; + return { + label: datasetKey, + data: responseData[datasetKey]?.values ?? [], + backgroundColor: "#6f42c1", // Theme color + borderColor: "#6f42c1", + borderWidth: 1, + borderRadius: 8, // Rounded corners for the bars + borderSkipped: false, // Ensure all corners are rounded + }; + }); + + setChartData({ labels, datasets }); + }); + + return () => { + socket.off("lineOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [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}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === id) { + fetchSavedInputes(); + } + } + ,[chartMeasurements, chartDuration, widgetName]) + return ( -
+
setSelectedChartId({ + id: id, + type: type + }) + }>
Production Capacity
@@ -104,7 +207,7 @@ const ProductionCapacity : React.FC = ({ position }) =>
{" "}
{/* Bar Chart */} - + 0 ? chartData : defaultChartData } options={chartOptions} />
diff --git a/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx b/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx index 8e8c444..5750bfd 100644 --- a/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx +++ b/app/src/components/layout/3D-cards/cards/ReturnOfInvestment.tsx @@ -1,5 +1,5 @@ import { Html } from "@react-three/drei"; -import React from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { Line } from "react-chartjs-2"; import { Chart as ChartJS, @@ -12,6 +12,10 @@ import { ChartOptions, } from "chart.js"; import { WavyIcon } from "../../../icons/3dChartIcons"; +import { useWidgetStore } from "../../../../store/useWidgetStore"; +import useChartStore from "../../../../store/useChartStore"; +import axios from "axios"; +import io from "socket.io-client"; // Register Chart.js components ChartJS.register( @@ -36,9 +40,24 @@ const SmoothLineGraphComponent: React.FC = ({ return ; }; interface ReturnOfInvestmentProps { + id: string; + type: string; position: [number, number, number]; } -const ReturnOfInvestment: React.FC = ({ position }) => { +const ReturnOfInvestment: React.FC = ({ id, type, position }) => { + + const { selectedChartId,setSelectedChartId } = useWidgetStore(); + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h") + const [name, setName] = useState("Widget") + const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + labels: [], + datasets: [], + }); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] // Improved sample data for the smooth curve graph (single day) const graphData: ChartData<"line"> = { labels: [ @@ -107,16 +126,99 @@ const ReturnOfInvestment: React.FC = ({ position }) => }, }; + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + + const socket = io(`http://${iotApiUrl}`); + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + + const startStream = () => { + socket.emit("lineInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lineOutput", (response) => { + const responseData = response.data; + + // Extract timestamps and values + const labels = responseData.time; + const datasets = Object.keys(measurements).map((key, index) => { + const measurement = measurements[key]; + const datasetKey = `${measurement.name}.${measurement.fields}`; + 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)", + fill: true, + tension: 0.4, // Smooth curve effect + pointRadius: 0, // Hide dots + pointHoverRadius: 0, // Hide hover dots + }; + }); + + setChartData({ labels, datasets }); + }); + + return () => { + socket.off("lineOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [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}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === id) { + fetchSavedInputes(); + } + } + ,[chartMeasurements, chartDuration, widgetName]) + return ( -
+
setSelectedChartId({ + id: id, + type: type + }) + }>
Return of Investment
{/* Smooth curve graph with two datasets */} - + 0 ? chartData : graphData} options={graphOptions} />
diff --git a/app/src/components/layout/3D-cards/cards/StateWorking.tsx b/app/src/components/layout/3D-cards/cards/StateWorking.tsx index 25ee39b..d293406 100644 --- a/app/src/components/layout/3D-cards/cards/StateWorking.tsx +++ b/app/src/components/layout/3D-cards/cards/StateWorking.tsx @@ -1,28 +1,111 @@ import { Html } from "@react-three/drei"; +import React, { useEffect, useMemo, useState } from "react"; +import { useWidgetStore } from "../../../../store/useWidgetStore"; +import useChartStore from "../../../../store/useChartStore"; +import axios from "axios"; +import io from "socket.io-client"; + // import image from "../../../../assets/image/temp/image.png"; interface StateWorkingProps { + id:string; + type: string; position: [number, number, number]; } -const StateWorking: React.FC = ({ position }) => { - const datas = [ - { key: "Oil Tank:", value: "24/341" }, - { key: "Oil Refin:", value: 36.023 }, - { key: "Transmission:", value: 36.023 }, - { key: "Fuel:", value: 36732 }, - { key: "Power:", value: 1300 }, - { key: "Time:", value: 13 - 9 - 2023 }, - ]; +const StateWorking: React.FC = ({ id, type, position }) => { + const { selectedChartId, setSelectedChartId } = useWidgetStore(); + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h") + const [name, setName] = useState("Widget") + const [datas, setDatas] = useState({}); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + // const datas = [ + // { key: "Oil Tank:", value: "24/341" }, + // { key: "Oil Refin:", value: 36.023 }, + // { key: "Transmission:", value: 36.023 }, + // { key: "Fuel:", value: 36732 }, + // { key: "Power:", value: 1300 }, + // { key: "Time:", value: 13 - 9 - 2023 }, + // ]; + + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + const socket = io(`http://${iotApiUrl}`); + const inputData = { + measurements, + duration, + interval: 1000, + }; + const startStream = () => { + socket.emit("lastInput", inputData); + }; + socket.on("connect", startStream); + socket.on("lastOutput", (response) => { + const responseData = response; + console.log("responceeeeeeeeeee",response); + + setDatas(responseData); + }); + + return () => { + socket.off("lastOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [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}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + console.log("dataaaaa",datas); + + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === id) { + fetchSavedInputes(); + } + } + ,[chartMeasurements, chartDuration, widgetName]) + + return ( -
+
setSelectedChartId({ + id: id, + type: type + }) + }>
State - Working . + {datas?.input1 ? datas.input1 : 'input1'} .
@@ -31,12 +114,36 @@ const StateWorking: React.FC = ({ position }) => {
{/* Data */}
- {datas.map((data, index) => ( + {/* {datas.map((data, index) => (
{data.key}
{data.value}
- ))} + ))} */} +
+
{measurements?.input2?.fields ? measurements.input2.fields : 'input2'}
+
{datas?.input2 ? datas.input2 : 'data'}
+
+
+
{measurements?.input3?.fields ? measurements.input3.fields : 'input3'}
+
{datas?.input3 ? datas.input3 : 'data'}
+
+
+
{measurements?.input4?.fields ? measurements.input4.fields : 'input4'}
+
{datas?.input4 ? datas.input4 : 'data'}
+
+
+
{measurements?.input5?.fields ? measurements.input5.fields : 'input5'}
+
{datas?.input5 ? datas.input5 : 'data'}
+
+
+
{measurements?.input6?.fields ? measurements.input6.fields : 'input6'}
+
{datas?.input6 ? datas.input6 : 'data'}
+
+
+
{measurements?.input7?.fields ? measurements.input7.fields : 'input7'}
+
{datas?.input7 ? datas.input7 : 'data'}
+
diff --git a/app/src/components/layout/3D-cards/cards/Throughput.tsx b/app/src/components/layout/3D-cards/cards/Throughput.tsx index 220c2a2..700914c 100644 --- a/app/src/components/layout/3D-cards/cards/Throughput.tsx +++ b/app/src/components/layout/3D-cards/cards/Throughput.tsx @@ -1,5 +1,5 @@ import { Html } from "@react-three/drei"; -import React from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { Line } from "react-chartjs-2"; import { Chart as ChartJS, @@ -14,6 +14,10 @@ import { ChartOptions, } from "chart.js"; import { ThroughputIcon } from "../../../icons/3dChartIcons"; +import { useWidgetStore } from "../../../../store/useWidgetStore"; +import useChartStore from "../../../../store/useChartStore"; +import axios from "axios"; +import io from "socket.io-client"; // Register Chart.js components ChartJS.register( @@ -38,10 +42,25 @@ const LineGraphComponent: React.FC = ({ data, options }) => { }; interface ThroughputProps { + id: string; + type: string; position: [number, number, number]; } -const Throughput: React.FC = ({ position }) => { +const Throughput: React.FC = ({ id, type, position }) => { + + const { selectedChartId,setSelectedChartId } = useWidgetStore(); + const { measurements: chartMeasurements, duration: chartDuration, name: widgetName } = useChartStore(); + const [measurements, setmeasurements] = useState({}); + const [duration, setDuration] = useState("1h") + const [name, setName] = useState("Widget") + const [chartData, setChartData] = useState<{ labels: string[]; datasets: any[] }>({ + labels: [], + datasets: [], + }); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] // Sample data for the line graph const graphData: ChartData<"line"> = { @@ -90,13 +109,93 @@ const Throughput: React.FC = ({ position }) => { }, }; + useEffect(() => { + if (!iotApiUrl || !measurements || Object.keys(measurements).length === 0) return; + + const socket = io(`http://${iotApiUrl}`); + + const inputData = { + measurements, + duration, + interval: 1000, + }; + + + const startStream = () => { + socket.emit("lineInput", inputData); + }; + + socket.on("connect", startStream); + + socket.on("lineOutput", (response) => { + const responseData = response.data; + + // Extract timestamps and values + const labels = responseData.time; + const datasets = Object.keys(measurements).map((key) => { + const measurement = measurements[key]; + const datasetKey = `${measurement.name}.${measurement.fields}`; + return { + label: datasetKey, + data: responseData[datasetKey]?.values ?? [], + borderColor: "rgba(75, 192, 192, 1)", + backgroundColor: "rgba(75, 192, 192, 0.2)", + fill: true, + }; + }); + + setChartData({ labels, datasets }); + }); + + return () => { + socket.off("lineOutput"); + socket.emit("stop_stream"); // Stop streaming when component unmounts + socket.disconnect(); + }; + }, [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}`); + if (response.status === 200) { + setmeasurements(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + useEffect(() => { + fetchSavedInputes(); + }, []); + + useEffect(() => { + if (selectedChartId?.id === id) { + fetchSavedInputes(); + } + } + ,[chartMeasurements, chartDuration, widgetName]) + return ( -
-
Throughput
+
setSelectedChartId({ + id: id, + type: type + }) + }> +
{name}
@@ -119,7 +218,7 @@ const Throughput: React.FC = ({ position }) => {
{/* Line graph using react-chartjs-2 */} - + 0 ? chartData : graphData} options={graphOptions} />
You made an extra $1256.13 this month diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx index 04451d6..3b44fc2 100644 --- a/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/InputSelecterComponent.tsx @@ -6,6 +6,9 @@ import FlotingWidgetInput from './FlotingWidgetInput' import FleetEfficiencyInputComponent from './FleetEfficiencyInputComponent' import Progress1Input from './Progress1Input' import Progress2Input from './Progress2Input' +import Widget2InputCard3D from './Widget2InputCard3D' +import Widget3InputCard3D from './Widget3InputCard3D' +import Widget4InputCard3D from './Widget4InputCard3D' import WarehouseThroughputInputComponent from './WarehouseThroughputInputComponent' import { useWidgetStore } from '../../../../../store/useWidgetStore' @@ -104,6 +107,42 @@ const InputSelecterComponent = () => { ) } + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 1' ) { + return ( + <> +
3D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 2' ) { + return ( + <> +
3D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 3' ) { + return ( + <> +
3D Widget Input
+ + + ) + } + + else if (selectedChartId && selectedChartId.type && selectedChartId.type === 'ui-Widget 4' ) { + return ( + <> +
3D Widget Input
+ + + ) + } + else { return (
No chart selected
diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx new file mode 100644 index 0000000..bad0afc --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget2InputCard3D.tsx @@ -0,0 +1,165 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +type Props = {}; + +const Widget2InputCard3D = (props: Props) => { + const { selectedChartId } = useWidgetStore(); + const [widgetName, setWidgetName] = useState("untited"); + const { setMeasurements, updateDuration, updateName } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + console.log(selectedChartId); + + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setMeasurements(selections); + updateDuration(duration); + updateName(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/3dwidget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; + // }; + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + // setDuration(option); + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(2)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+ + ); +}; + +export default Widget2InputCard3D; \ No newline at end of file diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx new file mode 100644 index 0000000..c720e66 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget3InputCard3D.tsx @@ -0,0 +1,158 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +const Widget3InputCard3D = () => { + const { selectedChartId } = useWidgetStore(); + const [widgetName, setWidgetName] = useState("untited"); + const { setMeasurements, updateDuration, updateName } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + console.log(selectedChartId); + + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + useEffect(() => { + setMeasurements(selections); + updateDuration(duration); + updateName(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/3dwidget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(7)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+ + ); +}; + +export default Widget3InputCard3D; diff --git a/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx new file mode 100644 index 0000000..0be5489 --- /dev/null +++ b/app/src/components/layout/sidebarRight/visualization/IotInputCards/Widget4InputCard3D.tsx @@ -0,0 +1,178 @@ +import React, { useEffect, useState } from "react"; +import MultiLevelDropdown from "../../../../ui/inputs/MultiLevelDropDown"; +import { AddIcon } from "../../../../icons/ExportCommonIcons"; +import RegularDropDown from "../../../../ui/inputs/RegularDropDown"; +import useChartStore from "../../../../../store/useChartStore"; +import { useSelectedZoneStore } from "../../../../../store/useZoneStore"; +import { useWidgetStore } from "../../../../../store/useWidgetStore"; +import axios from "axios"; +import RenameInput from "../../../../ui/inputs/RenameInput"; + +type Props = {}; + +const Widget4InputCard3D = (props: Props) => { + const { selectedChartId } = useWidgetStore(); + const [widgetName, setWidgetName] = useState("untited"); + const { setMeasurements, updateDuration, updateName } = useChartStore(); + const [duration, setDuration] = useState('1h') + const [dropDowndata, setDropDownData] = useState({}); + const [selections, setSelections] = useState>({}); + const { selectedZone } = useSelectedZoneStore(); + const iotApiUrl = process.env.REACT_APP_IOT_SOCKET_SERVER_URL; + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0] + console.log(selectedChartId); + + + useEffect(() => { + const fetchZoneData = async () => { + try { + const response = await axios.get(`http://${iotApiUrl}/getinput`); + if (response.status === 200) { + // console.log("dropdown data:", response.data); + setDropDownData(response.data); + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + }; + fetchZoneData(); + }, []); + + useEffect(() => { + const fetchSavedInputes = async () => { + if (selectedChartId.id !== "") { + try { + const response = await axios.get(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/widget3D/${selectedChartId.id}/${organization}`); + if (response.status === 200) { + setSelections(response.data.Data.measurements) + setDuration(response.data.Data.duration) + setWidgetName(response.data.widgetName) + } else { + console.log("Unexpected response:", response); + } + } catch (error) { + console.error("There was an error!", error); + } + } + } + + fetchSavedInputes(); + + }, [selectedChartId.id]); + + // Sync Zustand state when component mounts + useEffect(() => { + setMeasurements(selections); + updateDuration(duration); + updateName(widgetName); + }, [selections, duration, widgetName]); + + + const sendInputes = async (inputMeasurement: any, inputDuration: any, inputName: any) => { + try { + const response = await axios.post(`http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}/api/v2/3dwidget/save`, { + organization: organization, + zoneId: selectedZone.zoneId, + widget: { + id: selectedChartId.id, + widgetName: inputName, + Data: { + measurements: inputMeasurement, + duration: inputDuration + } + } + } as any); + if (response.status === 200) { + return true + } else { + console.log("Unexpected response:", response); + return false + } + } catch (error) { + console.error("There was an error!", error); + return false + } + } + + const handleSelect = async (inputKey: string, selectedData: { name: string; fields: string } | null) => { + + // async() => { + const newSelections = { ...selections }; + if (selectedData === null) { + delete newSelections[inputKey]; + } else { + newSelections[inputKey] = selectedData; + } + // setMeasurements(newSelections); // Update Zustand store + console.log(newSelections); + if (await sendInputes(newSelections, duration, widgetName)) { + setSelections(newSelections); + } + // sendInputes(newSelections, duration); // Send data to server + // return newSelections; + // }; + }; + + const handleSelectDuration = async (option: string) => { + if (await sendInputes(selections, option, widgetName)) { + setDuration(option); + } + // setDuration(option); + }; + + const handleNameChange = async (name:any) => { + console.log('name change requested',name); + + if (await sendInputes(selections, duration, name)) { + setWidgetName(name); + } + } + + return ( + <> +
+
+
Title
+ +
+ {[...Array(1)].map((_, index) => { + const inputKey = `input${index + 1}`; + return ( +
+
Input {index + 1}
+
+ handleSelect(inputKey, selectedData)} + onUnselect={() => handleSelect(inputKey, null)} + selectedValue={selections[inputKey]} // Load from Zustand + /> +
+ +
+
+
+ ); + })} +
+
+
+
Duration
+
+ +
+
+
+ + ); +}; + +export default Widget4InputCard3D; diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index 0a3534a..dbb1cba 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -129,13 +129,13 @@ export default function Dropped3dWidgets() { console.log('Typeeeeeeeeeeee',type); switch (type) { case "ui-Widget 1": - return ; + return ; case "ui-Widget 2": - return ; + return ; case "ui-Widget 3": - return ; + return ; case "ui-Widget 4": - return ; + return ; default: return null; } From 09963d3337b7319e82d7f0ab555b5ef1505eed00 Mon Sep 17 00:00:00 2001 From: gabriel Date: Wed, 2 Apr 2025 18:17:26 +0530 Subject: [PATCH 11/14] resolved conflict and merged to main --- app/src/store/store.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 23af16c..87f937c 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -409,3 +409,22 @@ export const useWidgetSubOption = create((set: any) => ({ widgetSubOption: "2D", setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), })); +export const useLimitDistance = create((set: any) => ({ + limitDistance: true, + setLimitDistance: (x: any) => set({ limitDistance: x }), +})); + +export const useTileDistance = create((set: any) => ({ + gridValue: { size: 300, divisions: 75 }, + planeValue: { height: 300, width: 300 }, + + setGridValue: (value: any) => + set((state: any) => ({ + gridValue: { ...state.gridValue, ...value }, + })), + + setPlaneValue: (value: any) => + set((state: any) => ({ + planeValue: { ...state.planeValue, ...value }, + })), +})); From 238f76cb4c8f31832fbd651d4a77ac8599710bf1 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Wed, 2 Apr 2025 18:49:18 +0530 Subject: [PATCH 12/14] socket added for 3d and floating Widget --- .../sidebarLeft/visualization/Templates.tsx | 35 +++- app/src/components/ui/Tools.tsx | 4 +- .../ui/componets/DraggableWidget.tsx | 28 +++- .../ui/componets/Dropped3dWidget.tsx | 80 ++++----- .../ui/componets/DroppedFloatingWidgets.tsx | 65 ++++++-- app/src/components/ui/componets/Panel.tsx | 24 ++- .../ui/componets/RealTimeVisulization.tsx | 37 +++-- .../visualization/handleSaveTemplate.ts | 22 ++- .../visualization/realTimeVizSocket.dev.tsx | 155 ++++++++++++++++-- .../zoneData/deleteWidgetApi.ts | 9 +- app/src/store/useDroppedObjectsStore.ts | 43 +++-- app/src/store/useZone3DWidgetStore.ts | 33 ++++ 12 files changed, 401 insertions(+), 134 deletions(-) create mode 100644 app/src/store/useZone3DWidgetStore.ts diff --git a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx index 4b13429..b99b297 100644 --- a/app/src/components/layout/sidebarLeft/visualization/Templates.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/Templates.tsx @@ -5,11 +5,13 @@ import { useSelectedZoneStore } from "../../../../store/useZoneStore"; import { getTemplateData } from "../../../../services/realTimeVisulization/zoneData/getTemplate"; import { deleteTemplateApi } from "../../../../services/realTimeVisulization/zoneData/deleteTemplate"; import { loadTempleteApi } from "../../../../services/realTimeVisulization/zoneData/loadTemplate"; +import { useSocketStore } from "../../../../store/store"; const Templates = () => { const { templates, removeTemplate } = useTemplateStore(); const { setTemplates } = useTemplateStore(); const { setSelectedZone, selectedZone } = useSelectedZoneStore(); + const { visualizationSocket } = useSocketStore(); useEffect(() => { async function templateData() { @@ -30,12 +32,18 @@ const Templates = () => { try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - - let response = await deleteTemplateApi(id, organization); - - if (response.message === "Template deleted successfully") { - removeTemplate(id); + let deleteTemplate = { + organization: organization, + templateID: id, } + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-template:deleteTemplate", deleteTemplate) + } + removeTemplate(id); + // let response = await deleteTemplateApi(id, organization); + + // if (response.message === "Template deleted successfully") { + // } } catch (error) { console.error("Error deleting template:", error); } @@ -48,9 +56,20 @@ const Templates = () => { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - let response = await loadTempleteApi(template.id, selectedZone.zoneId, organization); + let loadingTemplate = { + organization: organization, + zoneId: selectedZone.zoneId, + templateID: template.id, + } + console.log('template: ', template); + console.log('loadingTemplate: ', loadingTemplate); - if (response.message === "Template placed in Zone") { + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-template:addToZone", loadingTemplate) + } + // let response = await loadTempleteApi(template.id, selectedZone.zoneId, organization); + + // if (response.message === "Template placed in Zone") { setSelectedZone({ panelOrder: template.panelOrder, activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides` @@ -64,7 +83,7 @@ const Templates = () => { useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, val); }); } - } + // } } catch (error) { console.error("Error loading template:", error); } diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 71ebfe3..bb3928d 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -27,6 +27,7 @@ import { useMovePoint, useRefTextUpdate, useSelectedWallItem, + useSocketStore, useToggleView, useToolMode, useTransformMode, @@ -42,7 +43,7 @@ const Tools: React.FC = () => { const dropdownRef = useRef(null); const [openDrop, setOpenDrop] = useState(false); - + const { visualizationSocket } = useSocketStore(); const { activeModule } = useModuleStore(); const { isPlaying, setIsPlaying } = usePlayButtonStore(); const { addTemplate } = useTemplateStore(); @@ -397,6 +398,7 @@ const Tools: React.FC = () => { widgets3D, selectedZone, templates, + visualizationSocket }) } } diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx index 096779e..21fdf53 100644 --- a/app/src/components/ui/componets/DraggableWidget.tsx +++ b/app/src/components/ui/componets/DraggableWidget.tsx @@ -92,6 +92,7 @@ export const DraggableWidget = ({ widgetID: widget.id, organization: organization } + console.log('deleteWidget: ', deleteWidget); if (visualizationSocket) { visualizationSocket.emit("v2:viz-widget:delete", deleteWidget) } @@ -160,14 +161,27 @@ export const DraggableWidget = ({ id: `${widget.id}-copy-${Date.now()}`, }; - const response = await duplicateWidgetApi(selectedZone.zoneId, organization, duplicatedWidget); - - if (response?.message === "Widget created successfully") { - setSelectedZone((prevZone: any) => ({ - ...prevZone, - widgets: [...prevZone.widgets, duplicatedWidget], - })); + let duplicateWidget = { + organization: organization, + zoneId: selectedZone.zoneId, + widget: duplicatedWidget } + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-widget:add", duplicateWidget) + } + setSelectedZone((prevZone: any) => ({ + ...prevZone, + widgets: [...prevZone.widgets, duplicatedWidget], + })); + + // const response = await duplicateWidgetApi(selectedZone.zoneId, organization, duplicatedWidget); + + // if (response?.message === "Widget created successfully") { + // setSelectedZone((prevZone: any) => ({ + // ...prevZone, + // widgets: [...prevZone.widgets, duplicatedWidget], + // })); + // } } catch (error) { } finally { diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index 7ce1617..7da8039 100644 --- a/app/src/components/ui/componets/Dropped3dWidget.tsx +++ b/app/src/components/ui/componets/Dropped3dWidget.tsx @@ -1,7 +1,7 @@ import { useThree } from "@react-three/fiber"; import React, { useState, useEffect } from "react"; -import { useAsset3dWidget, useWidgetSubOption } from "../../../store/store"; +import { useAsset3dWidget, useSocketStore, useWidgetSubOption } from "../../../store/store"; import useModuleStore from "../../../store/useModuleStore"; import { ThreeState } from "../../../types/world/worldTypes"; import * as THREE from "three"; @@ -14,21 +14,23 @@ import { generateUniqueId } from "../../../functions/generateUniqueId"; import { adding3dWidgets } from "../../../services/realTimeVisulization/zoneData/add3dWidget"; import { get3dWidgetZoneData } from "../../../services/realTimeVisulization/zoneData/get3dWidgetData"; import { use3DWidget } from "../../../store/useDroppedObjectsStore"; +import { useZoneWidgetStore } from "../../../store/useZone3DWidgetStore"; export default function Dropped3dWidgets() { const { widgetSelect } = useAsset3dWidget(); const { activeModule } = useModuleStore(); const { raycaster, gl, scene }: ThreeState = useThree(); - const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); - const { selectedZone } = useSelectedZoneStore(); // Get the currently active zone - // 🔥 Store widget data (id, type, position) based on the selected zone - const [zoneWidgetData, setZoneWidgetData] = useState< - Record - >({}); - const { setWidgets3D } = use3DWidget() + const { widgetSubOption } = useWidgetSubOption(); + const { selectedZone } = useSelectedZoneStore(); + + // ✅ Use Zustand Store instead of useState + const { zoneWidgetData, setZoneWidgetData, addWidget } = useZoneWidgetStore(); + const { setWidgets3D } = use3DWidget(); + const { visualizationSocket } = useSocketStore(); + useEffect(() => { - if (activeModule !== "visualization") return - if (selectedZone.zoneName === "") return; + if (activeModule !== "visualization") return; + if (!selectedZone.zoneId) return; const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; @@ -36,37 +38,36 @@ export default function Dropped3dWidgets() { async function get3dWidgetData() { let result = await get3dWidgetZoneData(selectedZone.zoneId, organization); console.log('result: ', result); - setWidgets3D(result) - // Ensure the extracted data has id, type, and position correctly mapped + setWidgets3D(result); + const formattedWidgets = result.map((widget: any) => ({ id: widget.id, type: widget.type, position: widget.position, })); - setZoneWidgetData((prev) => ({ - ...prev, - [selectedZone.zoneId]: formattedWidgets, - })); + setZoneWidgetData(selectedZone.zoneId, formattedWidgets); } get3dWidgetData(); - }, [selectedZone.zoneId, activeModule]); useEffect(() => { if (activeModule !== "visualization") return; - if (widgetSubOption === "Floating") return; - if (widgetSubOption === "2D") return; - if (selectedZone.zoneName === "") return + if (widgetSubOption === "Floating" || widgetSubOption === "2D") return; + if (selectedZone.zoneName === "") return; + const canvasElement = gl.domElement; + const onDrop = async (event: DragEvent) => { - event.preventDefault(); // Prevent default browser behavior + event.preventDefault(); + const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; if (!widgetSelect.startsWith("ui")) return; const group1 = scene.getObjectByName("itemsGroup"); if (!group1) return; + const intersects = raycaster.intersectObjects(scene.children, true).filter( (intersect) => !intersect.object.name.includes("Roof") && @@ -75,40 +76,41 @@ export default function Dropped3dWidgets() { !intersect.object.userData.isPathObject && !(intersect.object.type === "GridHelper") ); + if (intersects.length > 0) { const { x, y, z } = intersects[0].point; - - // ✅ Explicitly define position as a tuple - const newWidget: { id: string; type: string; position: [number, number, number] } = { + const newWidget = { id: generateUniqueId(), type: widgetSelect, - position: [x, y, z], // Ensures TypeScript recognizes it as a tuple + position: [x, y, z] as [number, number, number], }; - - let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget) - console.log('response: ', response); - - if (response.message === "Widget created successfully") { - // ✅ Store widgets uniquely for each zone - setZoneWidgetData((prev) => ({ - ...prev, - [selectedZone.zoneId]: [...(prev[selectedZone.zoneId] || []), newWidget], - })); + let add3dWidget = { + organization: organization, + widget: newWidget, + zoneId: selectedZone.zoneId } + console.log('add3dWidget: ', add3dWidget); + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-3D-widget:add", add3dWidget) + } + + // let response = await adding3dWidgets(selectedZone.zoneId, organization, newWidget); + // console.log('response: ', response); + + // if (response.message === "Widget created successfully") { + addWidget(selectedZone.zoneId, newWidget); + // } } }; - canvasElement.addEventListener("drop", onDrop); return () => { canvasElement.removeEventListener("drop", onDrop); }; }, [widgetSelect, activeModule, selectedZone.zoneId, widgetSubOption]); - // Get widgets for the currently active zone const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; - console.log('activeZoneWidgets: ', activeZoneWidgets); return ( <> @@ -130,5 +132,3 @@ export default function Dropped3dWidgets() { ); } - - diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index 9c3f4c4..d80fd7c 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -21,6 +21,7 @@ import TotalCardComponent from "../realTimeVis/floating/TotalCardComponent"; import WarehouseThroughputComponent from "../realTimeVis/floating/WarehouseThroughputComponent"; import FleetEfficiencyComponent from "../realTimeVis/floating/FleetEfficiencyComponent"; import { useWidgetStore } from "../../../store/useWidgetStore"; +import { useSocketStore } from "../../../store/store"; interface DraggingState { zone: string; index: number; @@ -43,6 +44,7 @@ interface DraggingState { }; } const DroppedObjects: React.FC = () => { + const { visualizationSocket } = useSocketStore(); const zones = useDroppedObjectsStore((state) => state.zones); const [openKebabId, setOpenKebabId] = useState(null); const updateObjectPosition = useDroppedObjectsStore( @@ -98,29 +100,41 @@ const DroppedObjects: React.FC = () => { const zoneEntries = Object.entries(zones); if (zoneEntries.length === 0) return null; const [zoneName, zone] = zoneEntries[0]; + function handleDuplicate(zoneName: string, index: number) { setOpenKebabId(null) duplicateObject(zoneName, index); // Call the duplicateObject method from the store } - async function handleDelete(zoneName: string, id: string, index: number) { + async function handleDelete(zoneName: string, id: string) { try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - - let res = await deleteFloatingWidgetApi(id, organization); - console.log('res: ', res); - - if (res.message === "FloatingWidget deleted successfully") { - deleteObject(zoneName, id, index); // Call the deleteObject method from the store + + + let deleteFloatingWidget = { + floatWidgetID: id, + organization: organization, + zoneId: zone.zoneId } + + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-float:delete", deleteFloatingWidget) + } + deleteObject(zoneName, id); + + // let res = await deleteFloatingWidgetApi(id, organization); + // s + + // if (res.message === "FloatingWidget deleted successfully") { + // deleteObject(zoneName, id, index); // Call the deleteObject method from the store + // } } catch (error) { - console.error("Error deleting floating widget:", error); + } } - const handlePointerDown = (event: React.PointerEvent, index: number) => { if ((event.target as HTMLElement).closest(".kebab-options") || (event.target as HTMLElement).closest(".kebab")) { return; // Prevent dragging when clicking on the kebab menu or its options @@ -278,15 +292,30 @@ const DroppedObjects: React.FC = () => { // Save to backend const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; - const response = await addingFloatingWidgets(zone.zoneId, organization, { - ...zone.objects[draggingIndex.index], - position: boundedPosition, - }); - console.log('response: ', response); + // const response = await addingFloatingWidgets(zone.zoneId, organization, { + // ...zone.objects[draggingIndex.index], + // position: boundedPosition, + // }); + - if (response.message === "Widget updated successfully") { - updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); + let updateFloatingWidget = { + organization: organization, + widget: { + ...zone.objects[draggingIndex.index], + position: boundedPosition, + }, + index:draggingIndex.index, + zoneId: zone.zoneId } + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-float:add", updateFloatingWidget) + } + + // if (response.message === "Widget updated successfully") { + + console.log('boundedPosition: ', boundedPosition); + updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); + // } // // Clean up // setDraggingIndex(null); @@ -298,7 +327,7 @@ const DroppedObjects: React.FC = () => { // animationRef.current = null; // } } catch (error) { - console.error("Error in handlePointerUp:", error); + } finally { // Clean up regardless of success or failure setDraggingIndex(null); @@ -390,7 +419,7 @@ const DroppedObjects: React.FC = () => {
{ event.stopPropagation(); - handleDelete(zoneName, obj.id, index); // Call the delete handler + handleDelete(zoneName, obj.id); // Call the delete handler }}>
diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index 56cdc06..ea0d576 100644 --- a/app/src/components/ui/componets/Panel.tsx +++ b/app/src/components/ui/componets/Panel.tsx @@ -153,8 +153,6 @@ const Panel: React.FC = ({ zoneId: selectedZone.zoneId, widget: newWidget } - console.log('newWidget: ', newWidget); - console.log('addWidget: ', addWidget); if (visualizationSocket) { visualizationSocket.emit("v2:viz-widget:add", addWidget) } @@ -163,18 +161,18 @@ const Panel: React.FC = ({ widgets: [...prev.widgets, newWidget], })); - // try { - // let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); + try { + // let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); - // if (response.message === "Widget created successfully") { - // setSelectedZone((prev) => ({ - // ...prev, - // widgets: [...prev.widgets, newWidget], - // })); - // } - // } catch (error) { - // console.error("Error adding widget:", error); - // } + // if (response.message === "Widget created successfully") { + // setSelectedZone((prev) => ({ + // ...prev, + // widgets: [...prev.widgets, newWidget], + // })); + // } + } catch (error) { + console.error("Error adding widget:", error); + } }; diff --git a/app/src/components/ui/componets/RealTimeVisulization.tsx b/app/src/components/ui/componets/RealTimeVisulization.tsx index 4a40270..0b9ba4a 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -144,12 +144,6 @@ const RealTimeVisulization: React.FC = () => { }; console.log('newObject: ', newObject); - let response = await addingFloatingWidgets( - selectedZone.zoneId, - organization, - newObject - ); - // Only set zone if it’s not already in the store (prevents overwriting objects) const existingZone = useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; @@ -159,12 +153,28 @@ const RealTimeVisulization: React.FC = () => { .setZone(selectedZone.zoneName, selectedZone.zoneId); } - // 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); + let addFloatingWidget = { + organization: organization, + widget: newObject, + zoneId: selectedZone.zoneId } + console.log('newObject: ', newObject); + + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-float:add", addFloatingWidget) + } + + // let response = await addingFloatingWidgets( + // selectedZone.zoneId, + // organization, + // newObject + // ); + // 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) => ({ @@ -209,6 +219,11 @@ const RealTimeVisulization: React.FC = () => { {activeModule === "visualization" && selectedZone.zoneName !== "" && } {activeModule === "visualization" && } {/* */} + {/* + + */} {activeModule === "visualization" && ( <> => { try { // Check if the selected zone has any widgets @@ -47,7 +50,7 @@ export const handleSaveTemplate = async ({ // Capture visualization snapshot const snapshot = await captureVisualization(); - console.log("snapshot: ", snapshot); + // if (!snapshot) { // return; // } @@ -72,18 +75,25 @@ export const handleSaveTemplate = async ({ console.error("Organization could not be determined from email."); return; } + let saveTemplate = { + organization: organization, + template: newTemplate, + }; + if (visualizationSocket) { + visualizationSocket.emit("v2:viz-template:add", saveTemplate); + } // Save the template try { - const response = await saveTemplateApi(organization, newTemplate); - console.log("Save API Response:", response); + addTemplate(newTemplate); + // const response = await saveTemplateApi(organization, newTemplate); + // console.log("Save API Response:", response); // Add template only if API call succeeds - addTemplate(newTemplate); } catch (apiError) { - console.error("Error saving template to API:", apiError); + // console.error("Error saving template to API:", apiError); } } catch (error) { - console.error("Error in handleSaveTemplate:", 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 4210d01..ad5e226 100644 --- a/app/src/modules/visualization/realTimeVizSocket.dev.tsx +++ b/app/src/modules/visualization/realTimeVizSocket.dev.tsx @@ -1,16 +1,27 @@ import { useEffect } from "react"; import { useSocketStore } from "../../store/store"; import { useSelectedZoneStore } from "../../store/useZoneStore"; +import { useDroppedObjectsStore } from "../../store/useDroppedObjectsStore"; +import { useZoneWidgetStore } from "../../store/useZone3DWidgetStore"; +import useTemplateStore from "../../store/useTemplateStore"; export default function SocketRealTimeViz() { const { visualizationSocket } = useSocketStore(); const { selectedZone, 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 { setTemplates } = useTemplateStore(); + 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) @@ -18,32 +29,35 @@ 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) } }) - // add 2dWidget - visualizationSocket.on("viz-widget:response:updates", (response: any) => { - console.log('response: ', response); - if (response.success && response.data) { + // add 2dWidget response + visualizationSocket.on("viz-widget:response:updates", (add2dWidget: any) => { + console.log('add2dWidget: ', add2dWidget); + + if (add2dWidget.success && add2dWidget.data) { setSelectedZone((prev) => { const isWidgetAlreadyAdded = prev.widgets.some( - (widget) => widget.id === response.data.widgetData.id + (widget) => widget.id === add2dWidget.data.widgetData.id ); if (isWidgetAlreadyAdded) return prev; // Prevent duplicate addition return { ...prev, - zoneId: response.data.zoneId, - zoneName: response.data.zoneName, - widgets: [...prev.widgets, response.data.widgetData], // Append new widget + zoneId: add2dWidget.data.zoneId, + zoneName: add2dWidget.data.zoneName, + widgets: [...prev.widgets, add2dWidget.data.widgetData], // Append new widget }; }); } }); - //delete 2D Widget + //delete 2D Widget response visualizationSocket.on("viz-widget:response:delete", (deleteWidget: any) => { console.log('deleteWidget: ', deleteWidget); + if (deleteWidget?.success && deleteWidget.data) { setSelectedZone((prevZone: any) => ({ ...prevZone, @@ -53,12 +67,127 @@ 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") { + const state = useDroppedObjectsStore.getState(); + const zone = state.zones[addFloatingWidget.data.zoneName]; + if (!zone) { + state.setZone(addFloatingWidget.data.zoneName, addFloatingWidget.data.zoneId); + } + const existingObjects = zone ? zone.objects : []; + const newWidget = addFloatingWidget.data.widget; + // ✅ Check if the widget ID already exists before adding + const isAlreadyAdded = existingObjects.some(obj => obj.id === newWidget.id); + if (isAlreadyAdded) { + + return; // Don't add the widget if it already exists + } + // Add widget only if it doesn't exist + state.addObject(addFloatingWidget.data.zoneName, newWidget); + } + if (addFloatingWidget.message === "Widget updated successfully") { + updateObjectPosition(addFloatingWidget.data.zoneName, addFloatingWidget.data.index, addFloatingWidget.data.position); + } + } + }); + //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) => { + const zone = state.zones[duplicateFloatingWidget.data.zoneName]; + if (!zone) return state; // Zone doesn't exist, return state as is + const existingObjects = zone.objects; + const newWidget = duplicateFloatingWidget.data.widget; + // ✅ Check if the object with the same ID already exists + const isAlreadyAdded = existingObjects.some(obj => obj.id === newWidget.id); + if (isAlreadyAdded) { + + return state; // Don't update state if it's already there + } + return { + zones: { + ...state.zones, + [duplicateFloatingWidget.data.zoneName]: { + ...zone, + objects: [...existingObjects, newWidget], // Append only if it's not a duplicate + }, + }, + }; + }); + } + }); + //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); + } + }); + //add 3D Widget response + visualizationSocket.on("viz-widget3D:response:updates", (add3DWidget: any) => { + console.log('add3DWidget: ', add3DWidget); + + if (add3DWidget.success) { + if (add3DWidget.message === "Widget created successfully") { + addWidget(add3DWidget.data.zoneId, add3DWidget.data.widget); + } + } + }); + // add Template response + visualizationSocket.on("viz-template:response:add", (addingTemplate: any) => { + console.log('addingTemplate: ', addingTemplate); + + if (addingTemplate.success) { + if (addingTemplate.message === "Template saved successfully") { + setTemplates(addingTemplate.data); + } + } + }); + //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") { + let template = loadTemplate.data.template + setSelectedZone({ + panelOrder: template.panelOrder, + activeSides: Array.from(new Set(template.panelOrder)), // No merging with previous `activeSides` + widgets: template.widgets, + }); + useDroppedObjectsStore.getState().setZone(template.zoneName, template.zoneId); + + if (Array.isArray(template.floatingWidget)) { + template.floatingWidget.forEach((val: any) => { + useDroppedObjectsStore.getState().addObject(template.zoneName, val); + }); + } + } + + } + }); + //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); + } + + + } + }); } - }, []) + }, [visualizationSocket]) - useEffect(() => { - - }, [selectedZone]) return ( <> ) diff --git a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts index e57e8cb..7607c95 100644 --- a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts +++ b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts @@ -3,21 +3,24 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_UR export const deleteWidgetApi = async ( widgetID: string, - organization: string + organization: string, + zoneId:string ) => { + console.log('zoneId: ', zoneId); + console.log('organization: ', organization); + console.log('widgetID: ', widgetID); try { const response = await fetch(`${url_Backend_dwinzo}/api/v2/delete/widget`, { method: "PATCH", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ organization, widgetID }), + body: JSON.stringify({ organization, widgetID,zoneId }), }); if (!response.ok) { throw new Error("Failed to delete widget in the zone"); } - const result = await response.json(); return result; } catch (error) { diff --git a/app/src/store/useDroppedObjectsStore.ts b/app/src/store/useDroppedObjectsStore.ts index 45f40e0..8f0067e 100644 --- a/app/src/store/useDroppedObjectsStore.ts +++ b/app/src/store/useDroppedObjectsStore.ts @@ -1,5 +1,6 @@ import { create } from "zustand"; import { addingFloatingWidgets } from "../services/realTimeVisulization/zoneData/addFloatingWidgets"; +import { useSocketStore } from "./store"; type DroppedObject = { className: string; @@ -36,7 +37,7 @@ type DroppedObjectsState = { bottom: number | "auto"; } ) => void; - deleteObject: (zoneName: string, id: string, index: number) => void; // Add this line + deleteObject: (zoneName: string, id: string) => void; // Add this line duplicateObject: (zoneName: string, index: number) => void; // Add this line }; @@ -77,10 +78,10 @@ export const useDroppedObjectsStore = create((set) => ({ }; }), - deleteObject: (zoneName: string, id: string, index: number) => + deleteObject: (zoneName: string, id: string) => set((state) => { const zone = state.zones[zoneName]; - console.log("zone: ", zone); + if (!zone) return state; return { zones: { @@ -94,6 +95,8 @@ export const useDroppedObjectsStore = create((set) => ({ duplicateObject: async (zoneName: string, index: number) => { const state = useDroppedObjectsStore.getState(); // Get the current state const zone = state.zones[zoneName]; + let socketState = useSocketStore.getState(); + let visualizationSocket = socketState.visualizationSocket; if (!zone) return; @@ -120,8 +123,28 @@ export const useDroppedObjectsStore = create((set) => ({ }, }; - console.log("zone: ", zone.zoneId); - console.log("duplicatedObject: ", duplicatedObject); + let duplicateFloatingWidget = { + organization: organization, + widget: duplicatedObject, + zoneId: zone.zoneId, + index: index, + }; + + if (visualizationSocket) { + visualizationSocket.emit( + "v2:viz-float:addDuplicate", + duplicateFloatingWidget + ); + } + useDroppedObjectsStore.setState((state) => ({ + zones: { + ...state.zones, + [zoneName]: { + ...state.zones[zoneName], + objects: [...state.zones[zoneName].objects, duplicatedObject], // Append duplicated object + }, + }, + })); // Make async API call outside of Zustand set function // let response = await addingFloatingWidgets( @@ -132,15 +155,7 @@ export const useDroppedObjectsStore = create((set) => ({ // if (response.message === "FloatWidget created successfully") { // Update the state inside `set` - useDroppedObjectsStore.setState((state) => ({ - zones: { - ...state.zones, - [zoneName]: { - ...state.zones[zoneName], - objects: [...state.zones[zoneName].objects, duplicatedObject], // Append duplicated object - }, - }, - })); + // } }, })); diff --git a/app/src/store/useZone3DWidgetStore.ts b/app/src/store/useZone3DWidgetStore.ts new file mode 100644 index 0000000..fbb8e74 --- /dev/null +++ b/app/src/store/useZone3DWidgetStore.ts @@ -0,0 +1,33 @@ +import { create } from "zustand"; + +type WidgetData = { + id: string; + type: string; + position: [number, number, number]; +}; + +type ZoneWidgetStore = { + zoneWidgetData: Record; + setZoneWidgetData: (zoneId: string, widgets: WidgetData[]) => void; + addWidget: (zoneId: string, widget: WidgetData) => void; +}; + +export const useZoneWidgetStore = create((set) => ({ + zoneWidgetData: {}, + + setZoneWidgetData: (zoneId, widgets) => + set((state) => ({ + zoneWidgetData: { + ...state.zoneWidgetData, + [zoneId]: widgets, + }, + })), + + addWidget: (zoneId, widget) => + set((state) => ({ + zoneWidgetData: { + ...state.zoneWidgetData, + [zoneId]: [...(state.zoneWidgetData[zoneId] || []), widget], + }, + })), +})); From f5f74f35adbf736d6053aa34c11890957b80a79c Mon Sep 17 00:00:00 2001 From: Poovizhi99 Date: Wed, 2 Apr 2025 19:12:14 +0530 Subject: [PATCH 13/14] added avg paths --- app/src/components/ui/Tools.tsx | 86 ++- app/src/modules/builder/agv/agv.tsx | 98 ++- .../modules/builder/agv/navMeshDetails.tsx | 10 +- app/src/modules/builder/agv/pathNavigator.tsx | 153 +++-- app/src/modules/scene/world/world.tsx | 5 +- .../modules/simulation/path/pathCreation.tsx | 625 ++++++++++-------- app/src/modules/simulation/simulation.tsx | 79 +-- 7 files changed, 632 insertions(+), 424 deletions(-) diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 71ebfe3..02a6d82 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -32,7 +32,10 @@ import { useTransformMode, } from "../../store/store"; import useToggleStore from "../../store/useUIToggleStore"; -import { use3DWidget, useFloatingWidget } from "../../store/useDroppedObjectsStore"; +import { + use3DWidget, + useFloatingWidget, +} from "../../store/useDroppedObjectsStore"; const Tools: React.FC = () => { const { templates } = useTemplateStore(); @@ -47,8 +50,8 @@ const Tools: React.FC = () => { const { isPlaying, setIsPlaying } = usePlayButtonStore(); const { addTemplate } = useTemplateStore(); const { selectedZone } = useSelectedZoneStore(); - const { floatingWidget } = useFloatingWidget() - const { widgets3D } = use3DWidget() + const { floatingWidget } = useFloatingWidget(); + const { widgets3D } = use3DWidget(); // wall options const { toggleView, setToggleView } = useToggleView(); @@ -71,7 +74,7 @@ const Tools: React.FC = () => { : true ); }, []); - useEffect(() => { }, [activeModule]); + useEffect(() => {}, [activeModule]); useEffect(() => { setActiveTool(activeSubTool); setActiveSubTool(activeSubTool); @@ -213,8 +216,9 @@ const Tools: React.FC = () => {
{activeSubTool == "cursor" && (
{ setActiveTool("cursor"); }} @@ -224,8 +228,9 @@ const Tools: React.FC = () => { )} {activeSubTool == "free-hand" && (
{ setActiveTool("free-hand"); }} @@ -235,8 +240,9 @@ const Tools: React.FC = () => { )} {activeSubTool == "delete" && (
{ setActiveTool("delete"); }} @@ -308,8 +314,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-wall"); }} @@ -318,8 +325,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-zone"); }} @@ -328,8 +336,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-aisle"); }} @@ -338,8 +347,9 @@ const Tools: React.FC = () => {
{ setActiveTool("draw-floor"); }} @@ -355,8 +365,9 @@ const Tools: React.FC = () => {
{ setActiveTool("measure"); }} @@ -372,8 +383,9 @@ const Tools: React.FC = () => {
{ setActiveTool("pen"); }} @@ -390,16 +402,14 @@ const Tools: React.FC = () => {
{ - handleSaveTemplate({ addTemplate, floatingWidget, widgets3D, selectedZone, templates, - }) - } - } + }); + }} >
@@ -409,8 +419,9 @@ const Tools: React.FC = () => {
{ setActiveTool("comment"); }} @@ -419,10 +430,12 @@ const Tools: React.FC = () => {
{toggleThreeD && (
{ setIsPlaying(!isPlaying); + setActiveTool("play"); }} > @@ -433,14 +446,19 @@ const Tools: React.FC = () => { <>
-
+
2d
-
+
3d
diff --git a/app/src/modules/builder/agv/agv.tsx b/app/src/modules/builder/agv/agv.tsx index 37c4f4e..ace2e3e 100644 --- a/app/src/modules/builder/agv/agv.tsx +++ b/app/src/modules/builder/agv/agv.tsx @@ -5,22 +5,83 @@ import * as THREE from "three"; import * as Types from "../../../types/world/worldTypes"; import PathNavigator from "./pathNavigator"; import NavMeshDetails from "./navMeshDetails"; +import { + useSelectedActionSphere, + useSimulationPaths, +} from "../../../store/store"; -const Agv = ({ lines, plane }: { lines: Types.RefLines; plane: Types.RefMesh; }) => { - const pathPoints = useMemo(() => [ - [ - { x: 8.477161935339709, y: 0, z: 17.41343083550102 }, - { x: 9.175416491482693, y: 0, z: -12.361001232663693 }, - ], - // [ - // { x: 13.508213355232144, y: 0, z: -15.456970649652018 }, - // { x: -30.464866520869617, y: 0, z: 9.779806557688929 }, - // ], - [ - { x: 16.792040856420844, y: 0, z: 15.86281907549489 }, - { x: -42.77173264503395, y: 0, z: -15.821322764400804 }, - ], - ], []); +const Agv = ({ + lines, + plane, +}: { + lines: Types.RefLines; + plane: Types.RefMesh; +}) => { + const [pathPoints, setPathPoints] = useState< + { + uuid: string; + points: { x: number; y: number; z: number }[]; + }[] + >([]); + const { simulationPaths } = useSimulationPaths(); + const { selectedActionSphere } = useSelectedActionSphere(); + useEffect(() => { + if (!Array.isArray(simulationPaths)) { + } else { + let agvModels = simulationPaths.filter( + (val: any) => val.modelName === "agv" + ); + + let findMesh = agvModels.filter( + (val: any) => + val.modeluuid === selectedActionSphere?.path?.modeluuid && + val.type === "Vehicle" + ); + + const result = + findMesh.length > 0 && + findMesh[0].type === "Vehicle" && + typeof findMesh[0].point?.actions.start === "object" && + typeof findMesh[0].point?.actions.end === "object" && + "x" in findMesh[0].point.actions.start && + "y" in findMesh[0].point.actions.start && + "x" in findMesh[0].point.actions.end && + "y" in findMesh[0].point.actions.end + ? [ + { + uuid: findMesh[0].modeluuid, // Ensure it's a number + + points: [ + { + x: findMesh[0].position[0], + y: findMesh[0].position[1], + z: findMesh[0].position[2], + }, + { + x: findMesh[0].point.actions.start.x, + y: 0, + z: findMesh[0].point.actions.start.y, + }, + { + x: findMesh[0].point.actions.end.x, + y: 0, + z: findMesh[0].point.actions.end.y, + }, + ], + }, + ] + : []; + if (result.length > 0) { + setPathPoints((prev) => { + const existingUUIDs = new Set(prev.map((item) => item.uuid)); + const newItems = result.filter( + (item) => !existingUUIDs.has(item.uuid) + ); + return [...prev, ...newItems]; + }); + } + } + }, [simulationPaths, selectedActionSphere]); let groupRef = useRef() as Types.RefGroup; const [navMesh, setNavMesh] = useState(); @@ -35,7 +96,12 @@ const Agv = ({ lines, plane }: { lines: Types.RefLines; plane: Types.RefMesh; }) plane={plane} /> {pathPoints.map((pair, i) => ( - + ))} diff --git a/app/src/modules/builder/agv/navMeshDetails.tsx b/app/src/modules/builder/agv/navMeshDetails.tsx index 571be5a..ecb539b 100644 --- a/app/src/modules/builder/agv/navMeshDetails.tsx +++ b/app/src/modules/builder/agv/navMeshDetails.tsx @@ -35,10 +35,14 @@ export default function NavMeshDetails({ const [positions, indices] = getPositionsAndIndices(meshes); const cs = 0.25; - const ch = 0.5; + const ch = 0.69; const walkableRadius = 0.5; - const { success, navMesh } = generateSoloNavMesh(positions, indices, { cs, ch, walkableRadius: Math.round(walkableRadius / ch), }); + const { success, navMesh } = generateSoloNavMesh(positions, indices, { + cs, + ch, + walkableRadius: Math.round(walkableRadius / ch), + }); if (!success || !navMesh) { return; @@ -49,7 +53,7 @@ export default function NavMeshDetails({ const debugDrawer = new DebugDrawer(); debugDrawer.drawNavMesh(navMesh); // scene.add(debugDrawer); - } catch (error) { } + } catch (error) {} }; initializeNavigation(); diff --git a/app/src/modules/builder/agv/pathNavigator.tsx b/app/src/modules/builder/agv/pathNavigator.tsx index 25d3af0..9da0d59 100644 --- a/app/src/modules/builder/agv/pathNavigator.tsx +++ b/app/src/modules/builder/agv/pathNavigator.tsx @@ -1,98 +1,149 @@ import React, { useEffect, useState, useRef } from "react"; import * as THREE from "three"; -import { useFrame } from "@react-three/fiber"; +import { useFrame, useThree } from "@react-three/fiber"; import { NavMeshQuery } from "@recast-navigation/core"; import { Line } from "@react-three/drei"; +import { useTh } from "leva/dist/declarations/src/styles"; +import { useActiveTool } from "../../../store/store"; // Define interface for props interface PathNavigatorProps { navMesh: any; selectedPoints: any; + id: string; } export default function PathNavigator({ navMesh, selectedPoints, + id, }: PathNavigatorProps) { const [path, setPath] = useState<[number, number, number][]>([]); const progressRef = useRef(0); + const distancesRef = useRef([]); + const totalDistanceRef = useRef(0); + const currentSegmentIndex = useRef(0); + const { scene } = useThree(); + const { activeTool } = useActiveTool(); + const [startPoint, setStartPoint] = useState(new THREE.Vector3()); const meshRef = useRef(null); - useEffect(() => { - if (selectedPoints.length === 2 && navMesh) { - const [start, end] = selectedPoints; - if (!start || !end) return; + if (!scene || !id || path.length < 2) return; - const navMeshQuery = new NavMeshQuery(navMesh); - - const { path: computedPath } = navMeshQuery.computePath(start, end); - - if (computedPath.length > 0) { - setPath(computedPath.map(({ x, y, z }) => [x, y + 0.1, z])); - progressRef.current = 0; - } + let totalDistance = 0; + const distances: number[] = []; + for (let i = 0; i < path.length - 1; i++) { + const start = new THREE.Vector3(...path[i]); + const end = new THREE.Vector3(...path[i + 1]); + const segmentDistance = start.distanceTo(end); + distances.push(segmentDistance); + totalDistance += segmentDistance; } - }, [selectedPoints, navMesh]); + + distancesRef.current = distances; + totalDistanceRef.current = totalDistance; + progressRef.current = 0; // Reset progress when the path changes + }, [path]); + useEffect(() => { + if (!navMesh || selectedPoints.length === 0) return; + + // Flatten the selectedPoints array into a single list of points + const allPoints = selectedPoints.flat(); + + // Compute paths between consecutive points + const computedPath: [number, number, number][] = []; + for (let i = 0; i < allPoints.length - 1; i++) { + const start = allPoints[i]; + setStartPoint( + new THREE.Vector3(allPoints[0].x, allPoints[0].y, allPoints[0].z) + ); + + const end = allPoints[i + 1]; + + try { + const navMeshQuery = new NavMeshQuery(navMesh); + const { path: segmentPath } = navMeshQuery.computePath(start, end); + + if (segmentPath && segmentPath.length > 0) { + computedPath.push( + ...segmentPath.map(({ x, y, z }): [number, number, number] => [ + x, + y + 0.1, + z, + ]) + ); + } + } catch (error) {} + } + + // Set the full computed path + + if (computedPath.length > 0) { + setPath(computedPath); + currentSegmentIndex.current = 0; // Reset to the first segment + } + }, [selectedPoints, navMesh, path]); useFrame((_, delta) => { - if (path.length > 1 && meshRef.current) { - const speed = 3; - progressRef.current += delta * speed; + if (!scene || !id || path.length < 2) return; - let totalDistance = 0; - const distances: number[] = []; - for (let i = 0; i < path.length - 1; i++) { - const start = new THREE.Vector3(...path[i]); - const end = new THREE.Vector3(...path[i + 1]); - const segmentDistance = start.distanceTo(end); - distances.push(segmentDistance); - totalDistance += segmentDistance; - } + // Find the object in the scene + const findObject = scene.getObjectByProperty("uuid", id); + if (activeTool === "play") { + if (!findObject) return; + + const speed = 5; + progressRef.current += delta * speed; let coveredDistance = progressRef.current; let accumulatedDistance = 0; let index = 0; + // Determine the current segment of the path while ( - index < distances.length && - coveredDistance > accumulatedDistance + distances[index] + index < distancesRef.current.length && + coveredDistance > accumulatedDistance + distancesRef.current[index] ) { - accumulatedDistance += distances[index]; + accumulatedDistance += distancesRef.current[index]; index++; } - if (index < distances.length) { - const start = new THREE.Vector3(...path[index]); - const end = new THREE.Vector3(...path[index + 1]); - const segmentDistance = distances[index]; - - const t = (coveredDistance - accumulatedDistance) / segmentDistance; - const position = start.clone().lerp(end, t); // Use clone() to avoid mutating the original vector - meshRef.current.position.copy(position); - - const direction = new THREE.Vector3() - .subVectors(end, start) - .normalize(); - const targetQuaternion = new THREE.Quaternion().setFromUnitVectors( - new THREE.Vector3(0, 0, 1), - direction - ); - meshRef.current.quaternion.slerp(targetQuaternion, 0.1); - } else { - progressRef.current = totalDistance; + // If the object has reached the end of the path, stop moving + if (index >= distancesRef.current.length) { + progressRef.current = totalDistanceRef.current; + return; } + + // Interpolate position within the current segment + const start = new THREE.Vector3(...path[index]); + const end = new THREE.Vector3(...path[index + 1]); + const segmentDistance = distancesRef.current[index]; + + const t = (coveredDistance - accumulatedDistance) / segmentDistance; + const position = start.clone().lerp(end, t); + findObject.position.copy(position); + + // Rotate the object to face the direction of movement + const direction = new THREE.Vector3().subVectors(end, start).normalize(); + const targetQuaternion = new THREE.Quaternion().setFromUnitVectors( + new THREE.Vector3(0, 0, 1), // Assuming forward direction is (0, 0, 1) + direction + ); + findObject.quaternion.slerp(targetQuaternion, 0.1); // Smoothly interpolate rotation + } else if (activeTool === "cursor") { + findObject?.position.copy(startPoint); } }); return ( <> - {/* {path.length > 0 && } */} - {path.length > 0 && ( + {path.length > 0 && } + {/* {path.length > 0 && ( 0 ? path[0] : [0, 0.1, 0]}> - )} + )} */} ); } diff --git a/app/src/modules/scene/world/world.tsx b/app/src/modules/scene/world/world.tsx index 76cf539..7fe2979 100644 --- a/app/src/modules/scene/world/world.tsx +++ b/app/src/modules/scene/world/world.tsx @@ -52,6 +52,7 @@ import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibilit import DrieHtmlTemp from "../mqttTemp/drieHtmlTemp"; import ZoneGroup from "../../builder/groups/zoneGroup"; import Agv from "../../builder/agv/agv"; +import useModuleStore from "../../../store/useModuleStore"; export default function World() { const state = useThree(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. @@ -120,6 +121,7 @@ export default function World() { const { updateScene, setUpdateScene } = useUpdateScene(); const { walls, setWalls } = useWalls(); const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); + const { activeModule } = useModuleStore(); // const loader = new GLTFLoader(); // const dracoLoader = new DRACOLoader(); @@ -359,8 +361,7 @@ export default function World() { /> {/* */} - - + {activeModule === "simulation" && } ); } diff --git a/app/src/modules/simulation/path/pathCreation.tsx b/app/src/modules/simulation/path/pathCreation.tsx index 84c3b78..7af4afd 100644 --- a/app/src/modules/simulation/path/pathCreation.tsx +++ b/app/src/modules/simulation/path/pathCreation.tsx @@ -1,299 +1,362 @@ -import * as THREE from 'three'; -import * as Types from '../../../types/world/worldTypes'; -import { useRef, useState, useEffect, useMemo } from 'react'; -import { Sphere, TransformControls } from '@react-three/drei'; -import { useEditingPoint, useEyeDropMode, useIsConnecting, usePreviewPosition, useRenderDistance, useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../../store/store'; -import { useFrame, useThree } from '@react-three/fiber'; -import { useSubModuleStore } from '../../../store/useModuleStore'; +import * as THREE from "three"; +import * as Types from "../../../types/world/worldTypes"; +import { useRef, useState, useEffect, useMemo } from "react"; +import { Sphere, TransformControls } from "@react-three/drei"; +import { + useEditingPoint, + useEyeDropMode, + useIsConnecting, + usePreviewPosition, + useRenderDistance, + useSelectedActionSphere, + useSelectedPath, + useSimulationPaths, +} from "../../../store/store"; +import { useFrame, useThree } from "@react-three/fiber"; +import { useSubModuleStore } from "../../../store/useModuleStore"; -function PathCreation({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject }) { - const { renderDistance } = useRenderDistance(); - const { setSubModule } = useSubModuleStore(); - const { setSelectedActionSphere, selectedActionSphere } = useSelectedActionSphere(); - const { eyeDropMode, setEyeDropMode } = useEyeDropMode(); - const { editingPoint, setEditingPoint } = useEditingPoint(); - const { previewPosition, setPreviewPosition } = usePreviewPosition(); - const { raycaster, camera, pointer, gl } = useThree(); - const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); - const { setSelectedPath } = useSelectedPath(); - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); - const { isConnecting } = useIsConnecting(); - - const groupRefs = useRef<{ [key: string]: THREE.Group }>({}); - const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); - const isMovingRef = useRef(false); - const transformRef = useRef(null); - const [transformMode, setTransformMode] = useState<'translate' | 'rotate' | null>(null); +function PathCreation({ + pathsGroupRef, +}: { + pathsGroupRef: React.MutableRefObject; +}) { + const { renderDistance } = useRenderDistance(); + const { setSubModule } = useSubModuleStore(); + const { setSelectedActionSphere, selectedActionSphere } = + useSelectedActionSphere(); + const { eyeDropMode, setEyeDropMode } = useEyeDropMode(); + const { editingPoint, setEditingPoint } = useEditingPoint(); + const { previewPosition, setPreviewPosition } = usePreviewPosition(); + const { raycaster, camera, pointer, gl } = useThree(); + const plane = useMemo( + () => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), + [] + ); + const { setSelectedPath } = useSelectedPath(); + const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const { isConnecting } = useIsConnecting(); - useEffect(() => { - setTransformMode(null); - const handleKeyDown = (e: KeyboardEvent) => { - if (!selectedActionSphere) return; - if (e.key === 'g') { - setTransformMode(prev => prev === 'translate' ? null : 'translate'); - } - if (e.key === 'r') { - setTransformMode(prev => prev === 'rotate' ? null : 'rotate'); - } - }; + const groupRefs = useRef<{ [key: string]: THREE.Group }>({}); + const sphereRefs = useRef<{ [key: string]: THREE.Mesh }>({}); + const isMovingRef = useRef(false); + const transformRef = useRef(null); + const [transformMode, setTransformMode] = useState< + "translate" | "rotate" | null + >(null); - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); - }, [selectedActionSphere]); - - useFrame(() => { - Object.values(groupRefs.current).forEach(group => { - if (group) { - const distance = new THREE.Vector3(...group.position.toArray()).distanceTo(camera.position); - group.visible = distance <= renderDistance; - } - }); - }); - - const updateSimulationPaths = () => { - if (!selectedActionSphere) return; - - const updatedPaths = simulationPaths.map((path) => { - if (path.type === "Conveyor") { - return { - ...path, - points: path.points.map((point) => - point.uuid === selectedActionSphere.point.uuid - ? { - ...point, - position: [ - selectedActionSphere.point.position.x, - selectedActionSphere.point.position.y, - selectedActionSphere.point.position.z, - ], - rotation: [ - selectedActionSphere.point.rotation.x, - selectedActionSphere.point.rotation.y, - selectedActionSphere.point.rotation.z, - ] - } - : point - ), - }; - } - return path; - }) as Types.ConveyorEventsSchema[]; - - setSimulationPaths(updatedPaths); + useEffect(() => { + setTransformMode(null); + const handleKeyDown = (e: KeyboardEvent) => { + if (!selectedActionSphere) return; + if (e.key === "g") { + setTransformMode((prev) => (prev === "translate" ? null : "translate")); + } + if (e.key === "r") { + setTransformMode((prev) => (prev === "rotate" ? null : "rotate")); + } }; - useFrame(() => { - if (eyeDropMode) { - raycaster.setFromCamera(pointer, camera); - const intersectionPoint = new THREE.Vector3(); - const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [selectedActionSphere]); - if (point) { - setPreviewPosition({ x: point.x, y: point.z }); - } - } else { - setPreviewPosition(null); + useFrame(() => { + Object.values(groupRefs.current).forEach((group) => { + if (group) { + const distance = new THREE.Vector3( + ...group.position.toArray() + ).distanceTo(camera.position); + group.visible = distance <= renderDistance; + } + }); + }); + + const updateSimulationPaths = () => { + if (!selectedActionSphere) return; + + const updatedPaths = simulationPaths.map((path) => { + if (path.type === "Conveyor") { + return { + ...path, + points: path.points.map((point) => + point.uuid === selectedActionSphere.point.uuid + ? { + ...point, + position: [ + selectedActionSphere.point.position.x, + selectedActionSphere.point.position.y, + selectedActionSphere.point.position.z, + ], + rotation: [ + selectedActionSphere.point.rotation.x, + selectedActionSphere.point.rotation.y, + selectedActionSphere.point.rotation.z, + ], + } + : point + ), + }; + } + return path; + }) as Types.ConveyorEventsSchema[]; + + setSimulationPaths(updatedPaths); + }; + + useFrame(() => { + if (eyeDropMode) { + raycaster.setFromCamera(pointer, camera); + const intersectionPoint = new THREE.Vector3(); + const point = raycaster.ray.intersectPlane(plane, intersectionPoint); + + if (point) { + setPreviewPosition({ x: point.x, y: point.z }); + } + } else { + setPreviewPosition(null); + } + }); + + useEffect(() => { + if (!camera) return; + const canvasElement = gl.domElement; + canvasElement.tabIndex = 0; + + const onPointerDown = () => { + isMovingRef.current = false; + }; + + const onPointerMove = () => { + isMovingRef.current = true; + }; + + const onPointerUp = (event: PointerEvent) => { + if ( + !isMovingRef.current && + eyeDropMode && + event.button === 0 && + previewPosition + ) { + event.preventDefault(); + if (editingPoint) { + handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y); + setEditingPoint(null); + setEyeDropMode(false); } + } + }; + + if (eyeDropMode) { + canvasElement.addEventListener("pointerdown", onPointerDown); + canvasElement.addEventListener("pointermove", onPointerMove); + canvasElement.addEventListener("pointerup", onPointerUp); + } + + return () => { + canvasElement.removeEventListener("pointerdown", onPointerDown); + canvasElement.removeEventListener("pointermove", onPointerMove); + canvasElement.removeEventListener("pointerup", onPointerUp); + }; + }, [eyeDropMode, editingPoint, previewPosition]); + + const handlePointUpdate = ( + pointType: "start" | "end", + x: number, + z: number + ) => { + if (!selectedActionSphere?.point?.uuid) return; + + const updatedPaths = simulationPaths.map((path) => { + if ( + path.type === "Vehicle" && + path.point.uuid === selectedActionSphere.point.uuid + ) { + return { + ...path, + point: { + ...path.point, + actions: { + ...path.point.actions, + [pointType]: { + ...path.point.actions[pointType], + x: x, + y: z, + }, + }, + }, + }; + } + return path; }); - useEffect(() => { - if (!camera) return; - const canvasElement = gl.domElement; - canvasElement.tabIndex = 0; + setSimulationPaths(updatedPaths); + }; + return ( + + {simulationPaths.map((path) => { + if (path.type === "Conveyor") { + const points = path.points.map( + (point) => new THREE.Vector3(...point.position) + ); - const onPointerDown = () => { - isMovingRef.current = false; - }; - - const onPointerMove = () => { - isMovingRef.current = true; - }; - - const onPointerUp = (event: PointerEvent) => { - if (!isMovingRef.current && eyeDropMode && event.button === 0 && previewPosition) { - event.preventDefault(); - if (editingPoint) { - handlePointUpdate(editingPoint, previewPosition.x, previewPosition.y); - setEditingPoint(null); - setEyeDropMode(false); - } - } - }; - - if (eyeDropMode) { - canvasElement.addEventListener("pointerdown", onPointerDown); - canvasElement.addEventListener("pointermove", onPointerMove); - canvasElement.addEventListener("pointerup", onPointerUp); - } - - return () => { - canvasElement.removeEventListener("pointerdown", onPointerDown); - canvasElement.removeEventListener("pointermove", onPointerMove); - canvasElement.removeEventListener("pointerup", onPointerUp); - }; - }, [eyeDropMode, editingPoint, previewPosition]); - - const handlePointUpdate = (pointType: 'start' | 'end', x: number, z: number) => { - if (!selectedActionSphere?.point?.uuid) return; - - const updatedPaths = simulationPaths.map((path) => { - if (path.type === "Vehicle" && path.point.uuid === selectedActionSphere.point.uuid) { - return { - ...path, - point: { - ...path.point, - actions: { - ...path.point.actions, - [pointType]: { - ...path.point.actions[pointType], - x: x, - y: z - } - } + return ( + (groupRefs.current[path.modeluuid] = el!)} + position={path.position} + rotation={path.rotation} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedPath({ + path, + group: groupRefs.current[path.modeluuid], + }); + setSelectedActionSphere(null); + setTransformMode(null); + setSubModule("mechanics"); + }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSelectedPath(null); + setSubModule("properties"); + }} + > + {path.points.map((point, index) => ( + (sphereRefs.current[point.uuid] = el!)} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedActionSphere({ + path, + point: sphereRefs.current[point.uuid], + }); + setSubModule("mechanics"); + setSelectedPath(null); + }} + userData={{ point, path }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSubModule("properties"); + setSelectedActionSphere(null); + }} + > + + + ))} - setSimulationPaths(updatedPaths); - }; + {points.slice(0, -1).map((point, index) => { + const nextPoint = points[index + 1]; + const segmentCurve = new THREE.CatmullRomCurve3([ + point, + nextPoint, + ]); + const tubeGeometry = new THREE.TubeGeometry( + segmentCurve, + 20, + 0.1, + 16, + false + ); - return ( - - {simulationPaths.map((path) => { - if (path.type === 'Conveyor') { - const points = path.points.map(point => new THREE.Vector3(...point.position)); + return ( + + + + ); + })} + + ); + } else if (path.type === "Vehicle") { + return ( + (groupRefs.current[path.modeluuid] = el!)} + position={path.position} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedPath({ + path, + group: groupRefs.current[path.modeluuid], + }); + setSelectedActionSphere(null); + setTransformMode(null); + setSubModule("mechanics"); + }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSelectedPath(null); + setSubModule("properties"); + }} + > + (sphereRefs.current[path.point.uuid] = el!)} + onClick={(e) => { + if (isConnecting || eyeDropMode) return; + e.stopPropagation(); + setSelectedActionSphere({ + path, + point: sphereRefs.current[path.point.uuid], + }); + setSubModule("mechanics"); + setSelectedPath(null); + }} + userData={{ point: path.point, path }} + onPointerMissed={() => { + if (eyeDropMode) return; + setSubModule("properties"); + setSelectedActionSphere(null); + }} + > + + + + ); + } + return null; + })} - return ( - (groupRefs.current[path.modeluuid] = el!)} - position={path.position} - rotation={path.rotation} - onClick={(e) => { - if (isConnecting || eyeDropMode) return; - e.stopPropagation(); - setSelectedPath({ path, group: groupRefs.current[path.modeluuid] }); - setSelectedActionSphere(null); - setTransformMode(null); - setSubModule('mechanics'); - }} - onPointerMissed={() => { - if (eyeDropMode) return; - setSelectedPath(null); - setSubModule('properties'); - }} - > - {path.points.map((point, index) => ( - (sphereRefs.current[point.uuid] = el!)} - onClick={(e) => { - if (isConnecting || eyeDropMode) return; - e.stopPropagation(); - setSelectedActionSphere({ - path, - point: sphereRefs.current[point.uuid] - }); - setSubModule('mechanics'); - setSelectedPath(null); - }} - userData={{ point, path }} - onPointerMissed={() => { - if (eyeDropMode) return; - setSubModule('properties'); - setSelectedActionSphere(null); - }} - > - - - ))} - - {points.slice(0, -1).map((point, index) => { - const nextPoint = points[index + 1]; - const segmentCurve = new THREE.CatmullRomCurve3([point, nextPoint]); - const tubeGeometry = new THREE.TubeGeometry(segmentCurve, 20, 0.1, 16, false); - - return ( - - - - ); - })} - - ); - } else if (path.type === 'Vehicle') { - return ( - (groupRefs.current[path.modeluuid] = el!)} - position={path.position} - onClick={(e) => { - if (isConnecting || eyeDropMode) return; - e.stopPropagation(); - setSelectedPath({ path, group: groupRefs.current[path.modeluuid] }); - setSelectedActionSphere(null); - setTransformMode(null); - setSubModule('mechanics'); - }} - onPointerMissed={() => { - if (eyeDropMode) return; - setSelectedPath(null); - setSubModule('properties'); - }} - > - (sphereRefs.current[path.point.uuid] = el!)} - onClick={(e) => { - if (isConnecting || eyeDropMode) return; - e.stopPropagation(); - setSelectedActionSphere({ - path, - point: sphereRefs.current[path.point.uuid] - }); - setSubModule('mechanics'); - setSelectedPath(null); - }} - userData={{ point: path.point, path }} - onPointerMissed={() => { - if (eyeDropMode) return; - setSubModule('properties'); - setSelectedActionSphere(null); - }} - > - - - - ); - } - return null; - })} - - {selectedActionSphere && transformMode && ( - - )} - - ); + {selectedActionSphere && transformMode && ( + + )} + + ); } export default PathCreation; diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx index 0212d50..fd8b520 100644 --- a/app/src/modules/simulation/simulation.tsx +++ b/app/src/modules/simulation/simulation.tsx @@ -1,47 +1,52 @@ -import { useState, useEffect, useRef, useMemo } from 'react'; -import { useSelectedActionSphere, useSelectedPath, useSimulationPaths } from '../../store/store'; -import * as THREE from 'three'; -import Behaviour from './behaviour/behaviour'; -import PathCreation from './path/pathCreation'; -import PathConnector from './path/pathConnector'; -import useModuleStore from '../../store/useModuleStore'; -import ProcessContainer from './process/processContainer'; +import { useState, useEffect, useRef, useMemo } from "react"; +import { + useSelectedActionSphere, + useSelectedPath, + useSimulationPaths, +} from "../../store/store"; +import * as THREE from "three"; +import Behaviour from "./behaviour/behaviour"; +import PathCreation from "./path/pathCreation"; +import PathConnector from "./path/pathConnector"; +import useModuleStore from "../../store/useModuleStore"; +import ProcessContainer from "./process/processContainer"; +import Agv from "../builder/agv/agv"; function Simulation() { - const { activeModule } = useModuleStore(); - const pathsGroupRef = useRef() as React.MutableRefObject; - const { simulationPaths, setSimulationPaths } = useSimulationPaths(); - const [processes, setProcesses] = useState([]); + const { activeModule } = useModuleStore(); + const pathsGroupRef = useRef() as React.MutableRefObject; + const { simulationPaths, setSimulationPaths } = useSimulationPaths(); + const [processes, setProcesses] = useState([]); - useEffect(() => { - // console.log('simulationPaths: ', simulationPaths); - }, [simulationPaths]); + useEffect(() => { + // console.log('simulationPaths: ', simulationPaths); + }, [simulationPaths]); - // useEffect(() => { - // if (selectedActionSphere) { - // console.log('selectedActionSphere: ', selectedActionSphere); - // } - // }, [selectedActionSphere]); + // useEffect(() => { + // if (selectedActionSphere) { + // console.log('selectedActionSphere: ', selectedActionSphere); + // } + // }, [selectedActionSphere]); - // useEffect(() => { - // if (selectedPath) { - // console.log('selectedPath: ', selectedPath); - // } - // }, [selectedPath]); + // useEffect(() => { + // if (selectedPath) { + // console.log('selectedPath: ', selectedPath); + // } + // }, [selectedPath]); - - return ( + return ( + <> + + {activeModule === "simulation" && ( <> - - {activeModule === 'simulation' && ( - <> - - - - - )} + + + + {/* */} - ); + )} + + ); } -export default Simulation; \ No newline at end of file +export default Simulation; From 6d639edc43483f2f22f3ad4d23a1291754b065b2 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Thu, 3 Apr 2025 09:58:55 +0530 Subject: [PATCH 14/14] update socket connection URL to include '/Builder' path --- app/src/store/store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 87f937c..bd903f2 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -12,7 +12,7 @@ export const useSocketStore = create((set: any, get: any) => ({ } const socket = io( - `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`, + `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder`, { reconnection: false, auth: { email, organization },