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 }), })); -