From 6ccdb28f52a51a129d3ce03ca8a68814906f1190 Mon Sep 17 00:00:00 2001 From: Gomathi9520 Date: Sat, 29 Mar 2025 19:21:20 +0530 Subject: [PATCH] floatingwidgets Api and 3dwidget frontend and 2d widget delete Api and zonecameraUpdation --- app/package-lock.json | 48 +++- .../visualization/widgets/Widgets.tsx | 12 +- .../visualization/widgets/Widgets3D.tsx | 7 +- .../properties/ZoneProperties.tsx | 28 +- app/src/components/ui/ModuleToggle.tsx | 9 +- .../components/ui/componets/AddButtons.tsx | 8 +- .../components/ui/componets/DisplayZone.tsx | 50 ++-- .../ui/componets/DraggableWidget.tsx | 67 +++-- .../ui/componets/Dropped3dWidget.tsx | 83 +++--- .../ui/componets/DroppedFloatingWidgets.tsx | 254 ++++++++++-------- app/src/components/ui/componets/Panel.tsx | 2 +- .../ui/componets/RealTimeVisulization.tsx | 94 ++++--- .../functions/convertAutoToNumeric.ts | 41 +++ .../componets/functions/determinePosition.ts | 64 +++++ .../functions/getActiveProperties.ts | 17 ++ .../ui/componets/zoneCameraTarget.tsx | 33 +-- app/src/components/ui/list/DropDownList.tsx | 13 +- app/src/components/ui/list/List.tsx | 64 +++-- .../realTimeVis/charts/PieGraphComponent.tsx | 2 +- .../realTimeVis/floating/FleetEfficiency.tsx | 2 - .../ui/realTimeVis/floating/SimpleCard.tsx | 1 + app/src/modules/scene/scene.tsx | 6 +- .../zoneData/addFloatingWidgets.ts | 33 +++ .../zoneData/addWidgets.ts | 2 +- .../zoneData/deleteWidgetApi.ts | 30 +++ .../zoneData/duplicateWidget.ts | 30 +++ .../zoneData/getFloatingData.ts | 26 ++ .../zoneData/getSelect2dZoneData.ts | 2 +- .../zoneData/getZoneData.ts | 2 +- .../realTimeVisulization/zoneData/getZones.ts | 3 + .../realTimeVisulization/zoneData/panel.ts | 2 +- .../zoneData/zoneCameraUpdation.ts | 29 ++ app/src/store/store.ts | 13 +- app/src/store/useDroppedObjectsStore.ts | 42 ++- 34 files changed, 792 insertions(+), 327 deletions(-) create mode 100644 app/src/components/ui/componets/functions/convertAutoToNumeric.ts create mode 100644 app/src/components/ui/componets/functions/determinePosition.ts create mode 100644 app/src/components/ui/componets/functions/getActiveProperties.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/getFloatingData.ts create mode 100644 app/src/services/realTimeVisulization/zoneData/zoneCameraUpdation.ts diff --git a/app/package-lock.json b/app/package-lock.json index c8210e0..736405a 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -2017,7 +2017,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2029,7 +2029,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -4128,6 +4128,26 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@testing-library/jest-dom": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.17.0.tgz", @@ -4239,25 +4259,25 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "devOptional": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "devOptional": true }, "node_modules/@turf/along": { "version": "7.2.0", @@ -8864,7 +8884,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "devOptional": true }, "node_modules/cross-env": { "version": "7.0.3", @@ -9729,7 +9749,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -15073,7 +15093,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "devOptional": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -20516,7 +20536,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20559,7 +20579,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "devOptional": true, "dependencies": { "acorn": "^8.11.0" }, @@ -20571,7 +20591,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "devOptional": true }, "node_modules/tsconfig-paths": { "version": "3.15.0", @@ -21058,7 +21078,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "devOptional": true }, "node_modules/v8-to-istanbul": { "version": "8.1.1", @@ -22117,7 +22137,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "engines": { "node": ">=6" } diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets.tsx index 15bc313..d4a64ae 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets.tsx @@ -3,24 +3,26 @@ import ToggleHeader from "../../../../ui/inputs/ToggleHeader"; import Widgets2D from "./Widgets2D"; import Widgets3D from "./Widgets3D"; import WidgetsFloating from "./WidgetsFloating"; +import { useWidgetSubOption } from "../../../../../store/store"; const Widgets = () => { const [activeOption, setActiveOption] = useState("2D"); + const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); const handleToggleClick = (option: string) => { - setActiveOption(option); + setWidgetSubOption(option); }; return (
- {activeOption === "2D" && } - {activeOption === "3D" && } - {activeOption === "Floating" && } + {widgetSubOption === "2D" && } + {widgetSubOption === "3D" && } + {widgetSubOption === "Floating" && }
); }; diff --git a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets3D.tsx b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets3D.tsx index 849c051..6872497 100644 --- a/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets3D.tsx +++ b/app/src/components/layout/sidebarLeft/visualization/widgets/Widgets3D.tsx @@ -24,9 +24,8 @@ const Widgets3D = () => { let crt = e.target if (crt instanceof HTMLElement) { const widget = crt.cloneNode(true) as HTMLElement; - console.log('widget: ', widget); - e.dataTransfer.setDragImage(widget,0,0) - e.dataTransfer.effectAllowed="move" + e.dataTransfer.setDragImage(widget, 0, 0) + e.dataTransfer.effectAllowed = "move" } }} onPointerDown={() => { @@ -41,7 +40,7 @@ const Widgets3D = () => { className="widget-image" src={widget.img} alt={widget.name} - // draggable={false} + // draggable={false} /> ))} diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index c707f14..9234cc5 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -3,6 +3,7 @@ import RenameInput from "../../../ui/inputs/RenameInput"; import Vector3Input from "../customInput/Vector3Input"; import { useSelectedZoneStore } from "../../../../store/useZoneStore"; import { useEditPosition, usezonePosition, usezoneTarget } from "../../../../store/store"; +import { zoneCameraUpdate } from "../../../../services/realTimeVisulization/zoneData/zoneCameraUpdation"; const ZoneProperties: React.FC = () => { const { Edit, setEdit } = useEditPosition(); @@ -15,12 +16,25 @@ const ZoneProperties: React.FC = () => { setZoneTarget(selectedZone.zoneViewPortTarget) }, [selectedZone?.zoneViewPortPosition, selectedZone?.zoneViewPortTarget]) - function handleSetView() { - console.log("setApi"); - - console.log('zoneTarget: ', zoneTarget); - console.log('zonePosition: ', zonePosition); - setEdit(false); + async function handleSetView() { + try { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + + let zonesdata = { + zoneId: selectedZone.zoneId, + viewPortposition: zonePosition, + viewPortCenter: zoneTarget + }; + + let response = await zoneCameraUpdate(zonesdata, organization); + console.log('response: ', response); + + + setEdit(false); + } catch (error) { + console.error("Error in handleSetView:", error); + } } function handleEditView() { @@ -36,7 +50,7 @@ const ZoneProperties: React.FC = () => { } useEffect(() => { - console.log("Updated selectedZone: ", selectedZone); + }, [selectedZone]); return ( diff --git a/app/src/components/ui/ModuleToggle.tsx b/app/src/components/ui/ModuleToggle.tsx index e364f52..3f028c2 100644 --- a/app/src/components/ui/ModuleToggle.tsx +++ b/app/src/components/ui/ModuleToggle.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import useModuleStore from "../../store/useModuleStore"; import { BuilderIcon, @@ -7,11 +7,13 @@ import { VisualizationIcon, } from "../icons/ExportModuleIcons"; import useToggleStore from "../../store/useUIToggleStore"; +import { useSelectedZoneStore } from "../../store/useZoneStore"; const ModuleToggle: React.FC = () => { const { activeModule, setActiveModule } = useModuleStore(); const { setToggleUI } = useToggleStore(); + return (
{
Simulation
{ setActiveModule("visualization"); setToggleUI(true); diff --git a/app/src/components/ui/componets/AddButtons.tsx b/app/src/components/ui/componets/AddButtons.tsx index 11a1d80..4f3f9b7 100644 --- a/app/src/components/ui/componets/AddButtons.tsx +++ b/app/src/components/ui/componets/AddButtons.tsx @@ -119,7 +119,7 @@ const AddButtons: React.FC = ({ }; // Delete the selectedZone state - console.log("updatedZone: ", updatedZone); + setSelectedZone(updatedZone); } else { const updatePanelData = async () => { @@ -141,13 +141,13 @@ const AddButtons: React.FC = ({ // API call const response = await panelData(organization, selectedZone.zoneId, newActiveSides); - console.log("response: ", response); + // Update state - console.log("updatedZone: ", updatedZone); + setSelectedZone(updatedZone); } catch (error) { - console.error("Error updating panel data:", error); + } }; diff --git a/app/src/components/ui/componets/DisplayZone.tsx b/app/src/components/ui/componets/DisplayZone.tsx index dafddba..d0dce1f 100644 --- a/app/src/components/ui/componets/DisplayZone.tsx +++ b/app/src/components/ui/componets/DisplayZone.tsx @@ -4,6 +4,7 @@ import { MoveArrowLeft, MoveArrowRight } from "../../icons/SimulationIcons"; import { InfoIcon } from "../../icons/ExportCommonIcons"; import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; import { getSelect2dZoneData } from "../../../services/realTimeVisulization/zoneData/getSelect2dZoneData"; +import { getFloatingZoneData } from "../../../services/realTimeVisulization/zoneData/getFloatingData"; // Define the type for `Side` type Side = "top" | "bottom" | "left" | "right"; @@ -147,23 +148,41 @@ const DisplayZone: React.FC = ({ }; async function handleSelect2dZoneData(zoneId: string, zoneName: string) { - const email = localStorage.getItem("email") || ""; - const organization = email?.split("@")[1]?.split(".")[0] - let response = await getSelect2dZoneData(zoneId, organization) - setSelectedZone({ - zoneName, - activeSides: response.activeSides, - panelOrder: response.panelOrder, - lockedPanels: response.lockedPanels, - widgets: response.widgets, - zoneId: zoneId, - zoneViewPortTarget: - response.viewPortCenter, - zoneViewPortPosition: - response.viewPortposition, - }); + try { + if (selectedZone?.zoneId === zoneId) { + console.log("Zone is already selected:", zoneName); + return; + } + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + // Fetch data from backend + let response = await getSelect2dZoneData(zoneId, organization); + let res = await getFloatingZoneData(zoneId, organization); + // Set the selected zone in the store + useDroppedObjectsStore.getState().setZone(zoneName, zoneId); + if (Array.isArray(res)) { + res.forEach((val) => { + useDroppedObjectsStore.getState().addObject(zoneName, val); + }); + } + // Update selected zone state + setSelectedZone({ + zoneName, + activeSides: response.activeSides || [], + panelOrder: response.panelOrder || [], + lockedPanels: response.lockedPanels || [], + widgets: response.widgets || [], + zoneId: zoneId, + zoneViewPortTarget: response.viewPortCenter || {}, + zoneViewPortPosition: response.viewPortposition || {}, + }); + } catch (error) { + console.log('error: ', error); + + } } + return (
= ({ className={`zone ${selectedZone.zoneName === zoneName ? "active" : "" }`} onClick={() => { - useDroppedObjectsStore.getState().setZone(zoneName, zonesData[zoneName]?.zoneId); handleSelect2dZoneData(zonesData[zoneName]?.zoneId, zoneName) }} > diff --git a/app/src/components/ui/componets/DraggableWidget.tsx b/app/src/components/ui/componets/DraggableWidget.tsx index 5666af8..83ba518 100644 --- a/app/src/components/ui/componets/DraggableWidget.tsx +++ b/app/src/components/ui/componets/DraggableWidget.tsx @@ -11,6 +11,8 @@ import { KebabIcon, } from "../../icons/ExportCommonIcons"; import { useEffect, useRef, useState } from "react"; +import { duplicateWidgetApi } from "../../../services/realTimeVisulization/zoneData/duplicateWidget"; +import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteWidgetApi"; type Side = "top" | "bottom" | "left" | "right"; @@ -34,9 +36,9 @@ export const DraggableWidget = ({ }: { selectedZone: { zoneName: string; + zoneId: string; activeSides: Side[]; panelOrder: Side[]; - lockedPanels: Side[]; widgets: Widget[]; }; @@ -79,21 +81,28 @@ export const DraggableWidget = ({ const isPanelHidden = hiddenPanels.includes(widget.panel); - const deleteSelectedChart = () => { - console.log('widget.id: ', widget.id); - const updatedWidgets = selectedZone.widgets.filter( - (w: Widget) => w.id !== widget.id - ); - console.log('updatedWidgets: ', updatedWidgets); + const deleteSelectedChart = async () => { + 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, + })); + } + } catch (error) { - setSelectedZone((prevZone: any) => ({ - ...prevZone, - widgets: updatedWidgets, - })); - - setOpenKebabId(null); + } finally { + setOpenKebabId(null); + } }; + const getCurrentWidgetCount = (panel: Side) => selectedZone.widgets.filter((w) => w.panel === panel).length; @@ -121,21 +130,32 @@ export const DraggableWidget = ({ return currentWidgetCount >= panelCapacity; }; - const duplicateWidget = () => { - const duplicatedWidget: Widget = { - ...widget, - id: `${widget.id}-copy-${Date.now()}`, - }; - setSelectedZone((prevZone: any) => ({ - ...prevZone, - widgets: [...prevZone.widgets, duplicatedWidget], - })); + const duplicateWidget = async () => { + try { + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; - setOpenKebabId(null); + const duplicatedWidget: Widget = { + ...widget, + 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], + })); + } + } catch (error) { + + } finally { + setOpenKebabId(null); + } }; + const handleKebabClick = (event: React.MouseEvent) => { event.stopPropagation(); if (openKebabId === widget.id) { @@ -176,7 +196,6 @@ export const DraggableWidget = ({ }; const handleDrop = (event: React.DragEvent) => { - event.preventDefault(); const fromIndex = parseInt(event.dataTransfer.getData("text/plain"), 10); // Get the dragged widget's index const toIndex = index; // The index of the widget where the drop occurred diff --git a/app/src/components/ui/componets/Dropped3dWidget.tsx b/app/src/components/ui/componets/Dropped3dWidget.tsx index e0e2a7d..10dd343 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 } from "../../../store/store"; +import { useAsset3dWidget, useWidgetSubOption } from "../../../store/store"; import useModuleStore from "../../../store/useModuleStore"; import { ThreeState } from "../../../types/world/worldTypes"; import * as THREE from "three"; @@ -9,71 +9,80 @@ import Throughput from "../../layout/3D-cards/cards/Throughput"; import ProductionCapacity from "../../layout/3D-cards/cards/ProductionCapacity"; import ReturnOfInvestment from "../../layout/3D-cards/cards/ReturnOfInvestment"; import StateWorking from "../../layout/3D-cards/cards/StateWorking"; +import { useSelectedZoneStore } from "../../../store/useZoneStore"; export default function Dropped3dWidgets() { - const { widgetSelect } = useAsset3dWidget(); + const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); const { activeModule } = useModuleStore(); const { raycaster, gl, scene }: ThreeState = useThree(); + const { selectedZone } = useSelectedZoneStore(); // Get currently selected zone + const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption() + // πŸ”₯ Store widget positions per zone + const [zoneWidgets, setZoneWidgets] = useState // Widget type -> Positions array + >>({}); - // πŸ”₯ Store multiple instances per widget type - const [widgetPositions, setWidgetPositions] = useState>({}); useEffect(() => { - if (activeModule !== "visualization") return; + if (widgetSubOption === "Floating") return + // if (activeModule !== "visualization") return; const canvasElement = gl.domElement; - const onDrop = (event: DragEvent) => { event.preventDefault(); // Prevent default browser behavior + if (widgetSubOption === "3D") { + if (selectedZone.zoneName === "") return + if (!widgetSelect?.startsWith("ui")) return; + const group1 = scene.getObjectByName("itemsGroup"); + if (!group1) return; + const Assets = group1.children + .map((val) => scene.getObjectByProperty("uuid", val.uuid)) + .filter(Boolean) as THREE.Object3D[]; + const intersects = raycaster.intersectObjects(scene.children, true).filter( + (intersect) => + !intersect.object.name.includes("Roof") && + !intersect.object.name.includes("agv-collider") && + !intersect.object.name.includes("MeasurementReference") && + !intersect.object.userData.isPathObject && + !(intersect.object.type === "GridHelper") + ); + if (intersects.length > 0) { + const { x, y, z } = intersects[0].point; - if (!widgetSelect.startsWith("ui")) return; - - - const group1 = scene.getObjectByName("itemsGroup"); - if (!group1) return; - - - - const Assets = group1.children - .map((val) => scene.getObjectByProperty("uuid", val.uuid)) - .filter(Boolean) as THREE.Object3D[]; - - - const intersects = raycaster.intersectObjects(Assets); - - if (intersects.length > 0) { - const { x, y, z } = intersects[0].point; - - - // βœ… Allow multiple instances by storing positions in an array - setWidgetPositions((prev) => ({ - ...prev, - [widgetSelect]: [...(prev[widgetSelect] || []), [x, y, z]], - })); + setZoneWidgets((prev) => ({ + ...prev, + [selectedZone.zoneId]: { + ...(prev[selectedZone.zoneId] || {}), + [widgetSelect]: [...(prev[selectedZone.zoneId]?.[widgetSelect] || []), [x, y, z]], + }, + })); + } } }; canvasElement.addEventListener("drop", onDrop); - return () => { - canvasElement.removeEventListener("drop", onDrop); + canvasElement.removeEventListener("drop", onDrop) + // setWidgetSelect() }; - }, [widgetSelect, activeModule]); + }, [widgetSelect, activeModule, widgetSubOption]); return ( <> - {widgetPositions["ui-Widget 1"]?.map((pos, index) => ( + {zoneWidgets[selectedZone.zoneId]?.["ui-Widget 1"]?.map((pos, index) => ( ))} - {widgetPositions["ui-Widget 2"]?.map((pos, index) => ( + {zoneWidgets[selectedZone.zoneId]?.["ui-Widget 2"]?.map((pos, index) => ( ))} - {widgetPositions["ui-Widget 3"]?.map((pos, index) => ( + {zoneWidgets[selectedZone.zoneId]?.["ui-Widget 3"]?.map((pos, index) => ( ))} - {widgetPositions["ui-Widget 4"]?.map((pos, index) => ( + {zoneWidgets[selectedZone.zoneId]?.["ui-Widget 4"]?.map((pos, index) => ( ))} ); } + diff --git a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx index ffddc23..bf19bb9 100644 --- a/app/src/components/ui/componets/DroppedFloatingWidgets.tsx +++ b/app/src/components/ui/componets/DroppedFloatingWidgets.tsx @@ -1,59 +1,79 @@ - - - import { WalletIcon } from "../../icons/3dChartIcons"; import { useEffect, useRef, useState } from "react"; import { Line } from "react-chartjs-2"; -import { useDroppedObjectsStore, Zones } from "../../../store/useDroppedObjectsStore"; +import { + useDroppedObjectsStore, + Zones, +} from "../../../store/useDroppedObjectsStore"; +import useModuleStore from "../../../store/useModuleStore"; +import { determinePosition } from "./functions/determinePosition"; +import { getActiveProperties } from "./functions/getActiveProperties"; +import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets"; const DroppedObjects: React.FC = () => { const zones = useDroppedObjectsStore((state) => state.zones); - const updateObjectPosition = useDroppedObjectsStore((state) => state.updateObjectPosition); - const [draggingIndex, setDraggingIndex] = useState<{ zone: string; index: number } | null>(null); + + const updateObjectPosition = useDroppedObjectsStore( + (state) => state.updateObjectPosition + ); + const [draggingIndex, setDraggingIndex] = useState<{ + zone: string; + index: number; + } | null>(null); const [offset, setOffset] = useState<[number, number] | null>(null); const positionRef = useRef<[number, number] | null>(null); const animationRef = useRef(null); + const { activeModule } = useModuleStore(); - // useEffect(() => { - // const initialZones: Record = { - // "Zone 1": { - // zoneName: "Zone 1", - // zoneId: "2e996073-546c-470c-8323-55bd3700c6aa", - // objects: [ - // { - // header: "Today’s Money", - // value: 53000, // βœ… Converted to number - // per: "+55%", - // className: "floating total-card", - // position: [146, 214], // βœ… No need for 'as' here - // }, - // { - // header: "New Clients", - // value: 250, // βœ… Converted to number - // per: "+12%", - // className: "floating total-card", - // position: [344, 295], - // }, - // ], - // }, - // }; - - // useDroppedObjectsStore.setState({ zones: initialZones }); - // }, []); - + // Get the first zone and its objects const zoneEntries = Object.entries(zones); if (zoneEntries.length === 0) return null; // No zone, nothing to render const [zoneName, zone] = zoneEntries[0]; // Only render the first zone + // Handle pointer down event function handlePointerDown(event: React.PointerEvent, index: number) { const obj = zone.objects[index]; - const offsetX = event.clientX - obj.position[1]; - const offsetY = event.clientY - obj.position[0]; + const container = document.getElementById("real-time-vis-canvas"); + if (!container) return; + + const rect = container.getBoundingClientRect(); + const relativeX = event.clientX - rect.left; + const relativeY = event.clientY - rect.top; + + // Determine which properties are active for this object + const [activeProp1, activeProp2] = getActiveProperties(obj.position); + + // Calculate the offset based on the active properties + let offsetX = 0; + let offsetY = 0; + + if (activeProp1 === "top") { + offsetY = + relativeY - + (typeof obj.position.top === "number" ? obj.position.top : 0); + } else if (activeProp1 === "bottom") { + offsetY = + rect.height - + relativeY - + (typeof obj.position.bottom === "number" ? obj.position.bottom : 0); + } + + if (activeProp2 === "left") { + offsetX = + relativeX - + (typeof obj.position.left === "number" ? obj.position.left : 0); + } else if (activeProp2 === "right") { + offsetX = + rect.width - + relativeX - + (typeof obj.position.right === "number" ? obj.position.right : 0); + } setDraggingIndex({ zone: zoneName, index }); setOffset([offsetY, offsetX]); } + // Handle pointer move event function handlePointerMove(event: React.PointerEvent) { if (!draggingIndex || !offset) return; @@ -61,34 +81,92 @@ const DroppedObjects: React.FC = () => { if (!container) return; const rect = container.getBoundingClientRect(); + const relativeX = event.clientX - rect.left; + const relativeY = event.clientY - rect.top; - let newX = event.clientX - offset[1]; - let newY = event.clientY - offset[0]; + // Determine which properties are active for the dragged object + const obj = zone.objects[draggingIndex.index]; + const [activeProp1, activeProp2] = getActiveProperties(obj.position); + // Calculate the new position based on the active properties + let newX = 0; + let newY = 0; + + if (activeProp2 === "left") { + newX = relativeX - offset[1]; + } else if (activeProp2 === "right") { + newX = rect.width - (relativeX + offset[1]); + } + + if (activeProp1 === "top") { + newY = relativeY - offset[0]; + } else if (activeProp1 === "bottom") { + newY = rect.height - (relativeY + offset[0]); + } + + // Ensure the object stays within the canvas boundaries newX = Math.max(0, Math.min(rect.width - 50, newX)); newY = Math.max(0, Math.min(rect.height - 50, newY)); + // Update the position reference positionRef.current = [newY, newX]; + // Update the object's position using requestAnimationFrame for smoother animations if (!animationRef.current) { animationRef.current = requestAnimationFrame(() => { if (positionRef.current) { - updateObjectPosition(zoneName, draggingIndex.index, positionRef.current); + updateObjectPosition(zoneName, draggingIndex.index, { + ...obj.position, + [activeProp1]: positionRef.current[0], + [activeProp2]: positionRef.current[1], + }); } animationRef.current = null; }); } } - function handlePointerUp() { - setDraggingIndex(null); - setOffset(null); - if (animationRef.current) { - cancelAnimationFrame(animationRef.current); - animationRef.current = null; + // Handle pointer up event + async function handlePointerUp(event: React.MouseEvent) { + try { + if (!draggingIndex || !offset) return; + + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; + const container = document.getElementById("real-time-vis-canvas"); + if (!container) throw new Error("Canvas container not found"); + + const rect = container.getBoundingClientRect(); + const relativeX = event.clientX - rect.left; + const relativeY = event.clientY - rect.top; + + // Recalculate the position using determinePosition + const newPosition = determinePosition(rect, relativeX, relativeY); + + // Validate the dragging index and get the object + if (!zone.objects[draggingIndex.index]) { + throw new Error("Dragged object not found in the zone"); + } + const obj = { ...zone.objects[draggingIndex.index], position: newPosition }; + let response = await addingFloatingWidgets(zone.zoneId, organization, obj); + if (response.message === "Widget updated successfully") { + updateObjectPosition(zoneName, draggingIndex.index, newPosition); + } + + // Reset states + setDraggingIndex(null); + setOffset(null); + + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + animationRef.current = null; + } + } catch (error) { + } } + return (
{zone.objects.map((obj, index) => ( @@ -96,14 +174,29 @@ const DroppedObjects: React.FC = () => { key={`${zoneName}-${index}`} className={obj.className} style={{ - top: obj.position[0] + "px", - left: obj.position[1] + "px", - transition: draggingIndex?.index === index ? "none" : "transform 0.1s ease-out", + position: "absolute", + top: + typeof obj.position.top !== "string" + ? `${obj.position.top}px` + : "auto", + left: + typeof obj.position.left !== "string" + ? `${obj.position.left}px` + : "auto", + right: + typeof obj.position.right !== "string" + ? `${obj.position.right}px` + : "auto", + bottom: + typeof obj.position.bottom !== "string" + ? `${obj.position.bottom}px` + : "auto", + // transition: draggingIndex?.index === index ? "none" : "transform 0.1s ease-out", }} onPointerDown={(event) => handlePointerDown(event, index)} > {obj.className === "floating total-card" ? ( -
+ <>
{obj.header}
@@ -114,9 +207,9 @@ const DroppedObjects: React.FC = () => {
-
+ ) : obj.className === "warehouseThroughput floating" ? ( -
+ <>

Warehouse Throughput

@@ -126,9 +219,9 @@ const DroppedObjects: React.FC = () => {

{/* */}
-
+ ) : obj.className === "fleetEfficiency floating" ? ( -
+ <>

Fleet Efficiency

@@ -148,7 +241,7 @@ const DroppedObjects: React.FC = () => {
100%
-
+ ) : null}
))} @@ -156,59 +249,4 @@ const DroppedObjects: React.FC = () => { ); }; - - - - export default DroppedObjects; - - - - - - - - - - - - - - - - -// import { Html } from "@react-three/drei"; -// import { useDroppedObjectsStore } from "../../../store/store"; -// import { CartIcon, DocumentIcon, GlobeIcon, WalletIcon } from "../../icons/3dChartIcons"; -// import SimpleCard from "../realTimeVis/floating/SimpleCard"; - -// const ICON_MAP: Record>> = { -// WalletIcon, -// GlobeIcon, -// DocumentIcon, -// CartIcon -// }; -// const DroppedObjects: React.FC = () => { -// const objects = useDroppedObjectsStore((state) => state.objects); // Get objects from Zustand store -// - -// return ( -// <> -// {objects.map((obj, index) => { -// const IconComponent = obj.Icon || WalletIcon; // Use obj.Icon directly if it exists -// return ( -// -// ); -// })} -// -// ); -// }; - -// export default DroppedObjects; diff --git a/app/src/components/ui/componets/Panel.tsx b/app/src/components/ui/componets/Panel.tsx index 1d4cc44..6500119 100644 --- a/app/src/components/ui/componets/Panel.tsx +++ b/app/src/components/ui/componets/Panel.tsx @@ -149,7 +149,7 @@ const Panel: React.FC = ({ }; try { let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); - console.log("response: ", response); + 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 27044b1..d378345 100644 --- a/app/src/components/ui/componets/RealTimeVisulization.tsx +++ b/app/src/components/ui/componets/RealTimeVisulization.tsx @@ -9,9 +9,11 @@ import useModuleStore from "../../../store/useModuleStore"; import DroppedObjects from "./DroppedFloatingWidgets"; import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; -import { useAsset3dWidget, useZones } from "../../../store/store"; -import { getZoneData } from "../../../services/realTimeVisulization/zoneData/getZones"; +import { useAsset3dWidget, useWidgetSubOption, useZones } from "../../../store/store"; import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/getZoneData"; +import { generateUniqueId } from "../../../functions/generateUniqueId"; +import { determinePosition } from "./functions/determinePosition"; +import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets"; type Side = "top" | "bottom" | "left" | "right"; @@ -48,6 +50,8 @@ const RealTimeVisulization: React.FC = () => { const { zones } = useZones() const [floatingWidgets, setFloatingWidgets] = useState>({}); const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); + const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption() + useEffect(() => { async function GetZoneData() { const email = localStorage.getItem("email") || ""; @@ -72,12 +76,12 @@ const RealTimeVisulization: React.FC = () => { setZonesData(formattedData); } catch (error) { console.log('error: ', error); + } } GetZoneData(); - }, []); // Removed `zones` from dependencies - + }, [activeModule]); // Removed `zones` from dependencies useEffect(() => { setZonesData((prev) => { @@ -97,48 +101,68 @@ const RealTimeVisulization: React.FC = () => { }; }); }, [selectedZone]); - + useEffect(() => { }, [floatingWidgets]) - const handleDrop = (event: React.DragEvent) => { - event.preventDefault(); - const data = event.dataTransfer.getData("text/plain"); - if (widgetSelect !== "") return; - if (!data || selectedZone.zoneName === "") return; + const handleDrop = async (event: React.DragEvent) => { + try { + event.preventDefault(); + const email = localStorage.getItem("email") || ""; + const organization = email?.split("@")[1]?.split(".")[0]; - const droppedData = JSON.parse(data); - const canvasElement = document.getElementById("real-time-vis-canvas"); - if (!canvasElement) return; + const data = event.dataTransfer.getData("text/plain"); + // if (widgetSelect !== "") return; + if (widgetSubOption === "3D") return + if (!data || selectedZone.zoneName === "") return; - const canvasRect = canvasElement.getBoundingClientRect(); - const relativeX = event.clientX - canvasRect.left; - const relativeY = event.clientY - canvasRect.top; + const droppedData = JSON.parse(data); + const canvasElement = document.getElementById("real-time-vis-canvas"); + if (!canvasElement) throw new Error("Canvas element not found"); + + const canvasRect = canvasElement.getBoundingClientRect(); + const relativeX = event.clientX - canvasRect.left; + const relativeY = event.clientY - canvasRect.top; + + const newObject = { + ...droppedData, + id: generateUniqueId(), + position: determinePosition(canvasRect, relativeX, relativeY), + }; + + 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]; + if (!existingZone) { + useDroppedObjectsStore.getState().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); + } + + // Update floating widgets state + setFloatingWidgets((prevWidgets) => ({ + ...prevWidgets, + [selectedZone.zoneName]: { + ...prevWidgets[selectedZone.zoneName], + zoneName: selectedZone.zoneName, + zoneId: selectedZone.zoneId, + objects: [...(prevWidgets[selectedZone.zoneName]?.objects || []), newObject], + }, + })); + } catch (error) { - const newObject = { - ...droppedData, - position: [relativeY, relativeX], // Y first because of top/left style - }; - // Only set zone if it’s not already in the store (prevents overwriting objects) - const existingZone = useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; - if (!existingZone) { - useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId); } - // Add the dropped object to the zone - useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, newObject); - setFloatingWidgets((prevWidgets) => ({ - ...prevWidgets, - [selectedZone.zoneName]: { - ...prevWidgets[selectedZone.zoneName], - zoneName: selectedZone.zoneName, - zoneId: selectedZone.zoneId, - objects: [...(prevWidgets[selectedZone.zoneName]?.objects || []), newObject], - }, - })); }; + return (
{ + const { width, height } = canvasRect; + + // Determine which properties are active + const [activeProp1, activeProp2] = getActiveProperties(position); + + let top = typeof position.top !== "string" ? position.top : 0; + let left = typeof position.left !== "string" ? position.left : 0; + let right = typeof position.right !== "string" ? position.right : 0; + let bottom = typeof position.bottom !== "string" ? position.bottom : 0; + + // Calculate missing properties based on active properties + if (activeProp1 === "top") { + bottom = height - top; + } else if (activeProp1 === "bottom") { + top = height - bottom; + } + + if (activeProp2 === "left") { + right = width - left; + } else if (activeProp2 === "right") { + left = width - right; + } + + return { + top, + left, + right, + bottom, + }; +}; diff --git a/app/src/components/ui/componets/functions/determinePosition.ts b/app/src/components/ui/componets/functions/determinePosition.ts new file mode 100644 index 0000000..0fcd727 --- /dev/null +++ b/app/src/components/ui/componets/functions/determinePosition.ts @@ -0,0 +1,64 @@ +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; +} diff --git a/app/src/components/ui/componets/functions/getActiveProperties.ts b/app/src/components/ui/componets/functions/getActiveProperties.ts new file mode 100644 index 0000000..2cb0b1b --- /dev/null +++ b/app/src/components/ui/componets/functions/getActiveProperties.ts @@ -0,0 +1,17 @@ +export const getActiveProperties = (position: { + top: number | "auto"; + left: number | "auto"; + right: number | "auto"; + bottom: number | "auto"; +}) => { + let activeProps: ["top", "left"] | ["bottom", "right"] = ["top", "left"]; // Default to top-left + + if ( + typeof position.bottom !== "string" && + typeof position.right !== "string" + ) { + activeProps = ["bottom", "right"]; + } + + return activeProps; +}; diff --git a/app/src/components/ui/componets/zoneCameraTarget.tsx b/app/src/components/ui/componets/zoneCameraTarget.tsx index 57804b9..f022b32 100644 --- a/app/src/components/ui/componets/zoneCameraTarget.tsx +++ b/app/src/components/ui/componets/zoneCameraTarget.tsx @@ -14,6 +14,7 @@ export default function ZoneCentreTarget() { const { Edit, setEdit } = useEditPosition(); + useEffect(() => { if ( selectedZone.zoneViewPortTarget && @@ -39,22 +40,22 @@ export default function ZoneCentreTarget() { if (centrePoint.length > 0) { - let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition); - let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget); + // let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition); + // let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget); - const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize(); + // const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize(); - const worldUp = new THREE.Vector3(0, 0, 1); - const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize(); - const up = new THREE.Vector3().crossVectors(direction, right).normalize(); - const offsetPosition = up.clone().multiplyScalar(20); - camPosition.add(offsetPosition); + // const worldUp = new THREE.Vector3(0, 0, 1); + // const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize(); + // const up = new THREE.Vector3().crossVectors(direction, right).normalize(); + // const offsetPosition = up.clone().multiplyScalar(20); + // camPosition.add(offsetPosition); const setCam = async () => { controls.setLookAt(centrePoint[0], 100, centrePoint[2], ...centrePoint, true); setTimeout(() => { controls?.setLookAt( - ...camPosition.toArray(), + ...selectedZone.zoneViewPortPosition, selectedZone.zoneViewPortTarget[0], selectedZone.zoneViewPortTarget[1], selectedZone.zoneViewPortTarget[2], @@ -65,21 +66,9 @@ export default function ZoneCentreTarget() { setCam(); } else { - let camPosition = new THREE.Vector3(...selectedZone.zoneViewPortPosition); - let CamTarget = new THREE.Vector3(...selectedZone.zoneViewPortTarget); - - const direction = new THREE.Vector3().subVectors(CamTarget, camPosition).normalize(); - - const worldUp = new THREE.Vector3(0, 0, 1); - const right = new THREE.Vector3().crossVectors(worldUp, direction).normalize(); - const up = new THREE.Vector3().crossVectors(direction, right).normalize(); - - const offsetPosition = up.clone().multiplyScalar(20); - - camPosition.add(offsetPosition); const setCam = async () => { controls?.setLookAt( - ...camPosition.toArray(), + ...selectedZone.zoneViewPortPosition, selectedZone.zoneViewPortTarget[0], selectedZone.zoneViewPortTarget[1], selectedZone.zoneViewPortTarget[2], diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index 4ff51ca..e77f35b 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -32,7 +32,7 @@ const DropDownList: React.FC = ({ listType = "default", remove, }) => { - + const [isOpen, setIsOpen] = useState(defaultOpen); const { zones, setZones } = useZones() @@ -43,6 +43,17 @@ const DropDownList: React.FC = ({ const { selectedZone, setSelectedZone } = useSelectedZoneStore(); useEffect(() => { + // console.log(zones); + // setZoneDataList([ + // { id: "2e996073-546c-470c-8323-55bd3700c6aa", name: "zone1" }, + // { id: "3f473bf0-197c-471c-a71f-943fc9ca2b47", name: "zone2" }, + // { id: "905e8fb6-9e18-469b-9474-e0478fb9601b", name: "zone3" }, + // { id: "9d9efcbe-8e96-47eb-bfad-128a9e4c532e", name: "zone4" }, + // { id: "884f3d29-eb5a-49a5-abe9-d11971c08e85", name: "zone5" }, + // { id: "70fa55cd-b5c9-4f80-a8c4-6319af3bfb4e", name: "zone6" }, + // ]) + + const value = (zones || []).map((val: { zoneId: string; zoneName: string }) => ({ id: val.zoneId, name: val.zoneName diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index 7a7da8d..0b2e63b 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -1,9 +1,9 @@ -import React from "react"; +import React, { useEffect } from "react"; import RenameInput from "../inputs/RenameInput"; import { EyeIcon, LockIcon, RmoveIcon } from "../../icons/ExportCommonIcons"; import { useSelectedZoneStore } from "../../../store/useZoneStore"; import { getZoneData } from "../../../services/realTimeVisulization/zoneData/getZones"; -import { useSubModuleStore } from "../../../store/useModuleStore"; +import useModuleStore, { useSubModuleStore } from "../../../store/useModuleStore"; interface ListProps { items?: { id: string; name: string }[]; // Optional array of items to render @@ -12,27 +12,55 @@ interface ListProps { } const List: React.FC = ({ items = [], remove }) => { - const { setSelectedZone } = useSelectedZoneStore(); + const { activeModule, setActiveModule } = useModuleStore(); + const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { setSubModule } = useSubModuleStore(); + useEffect(() => { + useSelectedZoneStore.getState().setSelectedZone({ + zoneName: "", + activeSides: [], + panelOrder: [], + lockedPanels: [], + zoneId: "", + zoneViewPortTarget: [], + zoneViewPortPosition: [], + widgets: [], + }); + }, [activeModule]); + async function handleSelectZone(id: string) { - setSubModule("zoneProperties") - const email = localStorage.getItem('email') - const organization = (email!.split("@")[1]).split(".")[0]; - let response = await getZoneData(id, organization) - setSelectedZone({ - zoneName: response?.zoneName, - activeSides: response?.activeSides || [], - panelOrder: response?.panelOrder || [], - lockedPanels: response?.lockedPanels || [], - widgets: response?.widgets || [], - zoneId: response?.zoneId, - zoneViewPortTarget: response?.viewPortCenter || [], - zoneViewPortPosition: - response?.viewPortposition || [], - }); + try { + // Avoid re-fetching if the same zone is already selected + if (selectedZone?.zoneId === id) { + console.log("Zone is already selected:", selectedZone.zoneName); + return; + } + setSubModule("zoneProperties"); + + const email = localStorage.getItem("email"); + const organization = email?.split("@")[1]?.split(".")[0] || ""; + + let response = await getZoneData(id, organization); + + setSelectedZone({ + zoneName: response?.zoneName, + activeSides: response?.activeSides || [], + panelOrder: response?.panelOrder || [], + lockedPanels: response?.lockedPanels || [], + widgets: response?.widgets || [], + zoneId: response?.zoneId, + zoneViewPortTarget: response?.viewPortCenter || [], + zoneViewPortPosition: response?.viewPortposition || [], + }); + + console.log("Zone selected:", response?.zoneName); + } catch (error) { + console.error("Error selecting zone:", error); + } } + return ( <> {items.length > 0 ? ( diff --git a/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx b/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx index 0066ec3..73d24c7 100644 --- a/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx +++ b/app/src/components/ui/realTimeVis/charts/PieGraphComponent.tsx @@ -53,7 +53,7 @@ const PieChartComponent = ({ .getPropertyValue("--accent-color") .trim(); - console.log("accentColor: ", accentColor); + const options = useMemo( () => ({ responsive: true, diff --git a/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx b/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx index 03c00e8..07e5f19 100644 --- a/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx +++ b/app/src/components/ui/realTimeVis/floating/FleetEfficiency.tsx @@ -14,8 +14,6 @@ const FleetEfficiency = () => { per: progress, }); - - console.log("Dragged Data:", cardData); event.dataTransfer.setData("text/plain", cardData); }; diff --git a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx index ee996bd..0c36977 100644 --- a/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx +++ b/app/src/components/ui/realTimeVis/floating/SimpleCard.tsx @@ -23,6 +23,7 @@ const SimpleCard: React.FC = ({ value, per, icon: Icon, + className: event.currentTarget.className, position: [rect.top, rect.left], // βœ… Store position }); diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index ac74240..74693b4 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -21,6 +21,7 @@ import DroppedObjects from "../../components/ui/componets/DroppedFloatingWidgets import ZoneCentreTarget from "../../components/ui/componets/zoneCameraTarget"; import ProductionCapacity from "../../components/layout/3D-cards/cards/ProductionCapacity"; import Dropped3dWidgets from "../../components/ui/componets/Dropped3dWidget"; +import { useWidgetSubOption } from "../../store/store"; export default function Scene() { @@ -31,9 +32,6 @@ export default function Scene() { { name: "right", keys: ["ArrowRight", "d", "D"] }, ], []) - - - return ( - + diff --git a/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts new file mode 100644 index 0000000..338f26b --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/addFloatingWidgets.ts @@ -0,0 +1,33 @@ +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, + organization: string, + widget: {} +) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/floatwidget/save`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneId, widget }), + } + ); + + if (!response.ok) { + throw new Error("Failed to add Floatingwidget 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/addWidgets.ts b/app/src/services/realTimeVisulization/zoneData/addWidgets.ts index 683943e..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`; export const addingWidgets = async ( zoneId: string, organization: string, diff --git a/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts new file mode 100644 index 0000000..e57e8cb --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/deleteWidgetApi.ts @@ -0,0 +1,30 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; + +export const deleteWidgetApi = async ( + widgetID: string, + organization: string +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/delete/widget`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, widgetID }), + }); + + 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/duplicateWidget.ts b/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts new file mode 100644 index 0000000..f5ec834 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/duplicateWidget.ts @@ -0,0 +1,30 @@ +let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; +export const duplicateWidgetApi = async ( + zoneId: string, + organization: string, + widget: {} +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/widget/save`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ organization, zoneId, widget }), + }); + + if (!response.ok) { + throw new Error("Failed to duplicate 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/getFloatingData.ts b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts new file mode 100644 index 0000000..80d2b19 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/getFloatingData.ts @@ -0,0 +1,26 @@ +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 +) => { + try { + const response = await fetch( + `${url_Backend_dwinzo}/api/v2/floadData/${ZoneId}/${organization}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + + if (!response.ok) { + throw new Error("Failed to fetch ZoneFloatingData"); + } + + return await response.json(); + } catch (error: any) { + throw new Error(error.message); + } +}; diff --git a/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getSelect2dZoneData.ts index 71d9c2f..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}`; -console.log("url_Backend_dwinzo: ", url_Backend_dwinzo); +// let url_Backend_dwinzo = `http://192.168.0.102:5000`; export const getSelect2dZoneData = async ( ZoneId?: string, diff --git a/app/src/services/realTimeVisulization/zoneData/getZoneData.ts b/app/src/services/realTimeVisulization/zoneData/getZoneData.ts index d2df867..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`; 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 39031d8..a760959 100644 --- a/app/src/services/realTimeVisulization/zoneData/getZones.ts +++ b/app/src/services/realTimeVisulization/zoneData/getZones.ts @@ -1,6 +1,8 @@ let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`; export const getZoneData = async (zoneId: string, organization: string) => { + console.log("organization: ", organization); + console.log("zoneId: ", zoneId); try { const response = await fetch( `${url_Backend_dwinzo}/api/v2/A_zone/${zoneId}/${organization}`, @@ -12,6 +14,7 @@ export const getZoneData = async (zoneId: string, organization: string) => { } ); + if (!response.ok) { throw new Error("Failed to fetch zoneData"); } diff --git a/app/src/services/realTimeVisulization/zoneData/panel.ts b/app/src/services/realTimeVisulization/zoneData/panel.ts index 7f89eed..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`; type Side = "top" | "bottom" | "left" | "right"; export const panelData = async ( diff --git a/app/src/services/realTimeVisulization/zoneData/zoneCameraUpdation.ts b/app/src/services/realTimeVisulization/zoneData/zoneCameraUpdation.ts new file mode 100644 index 0000000..d46f6a3 --- /dev/null +++ b/app/src/services/realTimeVisulization/zoneData/zoneCameraUpdation.ts @@ -0,0 +1,29 @@ +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 zoneCameraUpdate = async ( + zonesdata:{},organization:string +) => { + try { + const response = await fetch(`${url_Backend_dwinzo}/api/v2/zone/save`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ zonesdata, organization }), + }); + + if (!response.ok) { + throw new Error("Failed to update camera position in the zone"); + } + + const result = await response.json(); + return result; + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message); + } else { + throw new Error("An unknown error occurred"); + } + } +}; \ No newline at end of file diff --git a/app/src/store/store.ts b/app/src/store/store.ts index 8bbcba1..46c1845 100644 --- a/app/src/store/store.ts +++ b/app/src/store/store.ts @@ -29,7 +29,10 @@ export const useSocketStore = create((set: any, get: any) => ({ }, })); -export const useLoadingProgress = create<{ loadingProgress: number; setLoadingProgress: (x: number) => void }>((set) => ({ +export const useLoadingProgress = create<{ + loadingProgress: number; + setLoadingProgress: (x: number) => void; +}>((set) => ({ loadingProgress: 1, setLoadingProgress: (x: number) => set({ loadingProgress: x }), })); @@ -312,7 +315,9 @@ export const useSelectedPath = create((set: any) => ({ interface SimulationPathsStore { simulationPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]; - setSimulationPaths: (paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[]) => void; + setSimulationPaths: ( + paths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema)[] + ) => void; } export const useSimulationPaths = create((set) => ({ @@ -352,3 +357,7 @@ export const useAsset3dWidget = create((set: any) => ({ widgetSelect: "", setWidgetSelect: (x: any) => set({ widgetSelect: x }), })); +export const useWidgetSubOption = create((set: any) => ({ + widgetSubOption: "2D", + setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), +})); diff --git a/app/src/store/useDroppedObjectsStore.ts b/app/src/store/useDroppedObjectsStore.ts index e47b12f..dc648a9 100644 --- a/app/src/store/useDroppedObjectsStore.ts +++ b/app/src/store/useDroppedObjectsStore.ts @@ -2,10 +2,17 @@ import { create } from "zustand"; type DroppedObject = { className: string; - position: [number, number]; + id: string; + position: { + top: number | "auto"; + left: number | "auto"; + right: number | "auto"; + bottom: number | "auto"; + }; value?: number; per?: string; header?: string; + Data: {}; }; type Zone = { @@ -21,7 +28,12 @@ type DroppedObjectsState = { updateObjectPosition: ( zoneName: string, index: number, - newPosition: [number, number] + newPosition: { + top: number | "auto"; + left: number | "auto"; + right: number | "auto"; + bottom: number | "auto"; + } ) => void; }; @@ -64,15 +76,17 @@ export const useDroppedObjectsStore = create((set) => ({ })); export interface DroppedObjects { - header: string; - value: string | number; // βœ… Allows both numbers and formatted strings - per: string; - className: string; - position: [number, number]; // βœ… Ensures position is a tuple - } - - export interface Zones { - zoneName: string; - zoneId: string; - objects: DroppedObject[]; - } \ No newline at end of file + header: string; + id: string; + Data: {}; + value: string | number; // βœ… Allows both numbers and formatted strings + per: string; + className: string; + position: { top: number; left: number; right: number; bottom: number }; // βœ… Ensures position is a tuple +} + +export interface Zones { + zoneName: string; + zoneId: string; + objects: DroppedObject[]; +}