socket added for 2d widget

This commit is contained in:
2025-04-01 19:35:11 +05:30
parent 900723c14a
commit b828cb2437
12 changed files with 245 additions and 110 deletions

View File

@@ -79,9 +79,10 @@ const ProductionCapacity: React.FC<ProductionCapacityProps> = ({ position }) =>
}; };
return ( return (
<Html position={[position[0], position[1], position[2]]} <Html position={[position[0], position[1], position[2]] }
scale={[0.5, 0.5, 0.5]} scale={[0.5, 0.5, 0.5]}
transform transform
zIndexRange={[1,0]}
sprite> sprite>
<div className="productionCapacity-wrapper card"> <div className="productionCapacity-wrapper card">
<div className="headeproductionCapacityr-wrapper"> <div className="headeproductionCapacityr-wrapper">

View File

@@ -111,6 +111,7 @@ const ReturnOfInvestment: React.FC<ReturnOfInvestmentProps> = ({ position }) =>
<Html position={[position[0], position[1], position[2]]} <Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]} scale={[0.5, 0.5, 0.5]}
transform transform
zIndexRange={[1,0]}
sprite> sprite>
<div className="returnOfInvestment card"> <div className="returnOfInvestment card">
<div className="header">Return of Investment</div> <div className="header">Return of Investment</div>

View File

@@ -16,6 +16,7 @@ const StateWorking: React.FC<StateWorkingProps> = ({ position }) => {
<Html position={[position[0], position[1], position[2]]} <Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]} scale={[0.5, 0.5, 0.5]}
transform transform
zIndexRange={[1,0]}
sprite> sprite>
<div className="stateWorking-wrapper card"> <div className="stateWorking-wrapper card">
<div className="header-wrapper"> <div className="header-wrapper">

View File

@@ -94,6 +94,7 @@ const Throughput: React.FC<ThroughputProps> = ({ position }) => {
<Html position={[position[0], position[1], position[2]]} <Html position={[position[0], position[1], position[2]]}
scale={[0.5, 0.5, 0.5]} scale={[0.5, 0.5, 0.5]}
transform transform
zIndexRange={[1, 0]}
sprite> sprite>
<div className="throughput-wrapper"> <div className="throughput-wrapper">
<div className="header">Throughput</div> <div className="header">Throughput</div>

View File

@@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect } from "react";
import { import {
CleanPannel, CleanPannel,
EyeIcon, EyeIcon,
@@ -7,6 +7,7 @@ import {
import { panelData } from "../../../services/realTimeVisulization/zoneData/panel"; import { panelData } from "../../../services/realTimeVisulization/zoneData/panel";
import { AddIcon } from "../../icons/ExportCommonIcons"; import { AddIcon } from "../../icons/ExportCommonIcons";
import { deletePanelApi } from "../../../services/realTimeVisulization/zoneData/deletePanel"; import { deletePanelApi } from "../../../services/realTimeVisulization/zoneData/deletePanel";
import { useSocketStore } from "../../../store/store";
// Define the type for `Side` // Define the type for `Side`
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
@@ -17,7 +18,6 @@ interface ButtonsProps {
zoneName: string; zoneName: string;
activeSides: Side[]; activeSides: Side[];
panelOrder: Side[]; panelOrder: Side[];
lockedPanels: Side[]; lockedPanels: Side[];
zoneId: string; zoneId: string;
zoneViewPortTarget: number[]; zoneViewPortTarget: number[];
@@ -59,6 +59,9 @@ const AddButtons: React.FC<ButtonsProps> = ({
setHiddenPanels, setHiddenPanels,
hiddenPanels, hiddenPanels,
}) => { }) => {
const { visualizationSocket } = useSocketStore();
// Local state to track hidden panels // Local state to track hidden panels
// Function to toggle lock/unlock a panel // Function to toggle lock/unlock a panel
@@ -123,24 +126,33 @@ const AddButtons: React.FC<ButtonsProps> = ({
panelOrder: newActiveSides, panelOrder: newActiveSides,
}; };
// API call to delete the panel let deletePanel = {
try { organization: organization,
const response = await deletePanelApi(selectedZone.zoneId, side, organization); panelName: side,
console.log('response: ', response); zoneId: selectedZone.zoneId
if (response.message === "Panel deleted successfully") {
setSelectedZone(updatedZone);
} else {
console.error("Unexpected response:", response);
}
} catch (error) {
console.error("Error deleting panel:", error);
} }
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 { } else {
// Panel does not exist: Create panel // Panel does not exist: Create panel
try { try {
// Get email and organization safely with a default fallback // Get email and organization safely with a default fallback
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0] ; const organization = email?.split("@")[1]?.split(".")[0];
// Prevent duplicate side entries // Prevent duplicate side entries
const newActiveSides = selectedZone.activeSides.includes(side) const newActiveSides = selectedZone.activeSides.includes(side)
@@ -152,18 +164,25 @@ const AddButtons: React.FC<ButtonsProps> = ({
activeSides: newActiveSides, activeSides: newActiveSides,
panelOrder: newActiveSides, panelOrder: newActiveSides,
}; };
let addPanel = {
// API call to create panels organization: organization,
const response = await panelData(organization, selectedZone.zoneId, newActiveSides); zoneId: selectedZone.zoneId,
console.log('response: ', response); panelOrder: newActiveSides
if (response.message === "Panels created successfully") {
setSelectedZone(updatedZone);
} else {
console.error("Unexpected response:", response);
} }
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) { } catch (error) {
console.error("Error creating panels:", error);
} }
} }
}; };

View File

@@ -13,6 +13,7 @@ import {
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { duplicateWidgetApi } from "../../../services/realTimeVisulization/zoneData/duplicateWidget"; import { duplicateWidgetApi } from "../../../services/realTimeVisulization/zoneData/duplicateWidget";
import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteWidgetApi"; import { deleteWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteWidgetApi";
import { useSocketStore } from "../../../store/store";
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
@@ -69,6 +70,7 @@ export const DraggableWidget = ({
openKebabId: string | null; openKebabId: string | null;
setOpenKebabId: (id: string | null) => void; setOpenKebabId: (id: string | null) => void;
}) => { }) => {
const { visualizationSocket } = useSocketStore();
const { selectedChartId, setSelectedChartId } = useWidgetStore(); const { selectedChartId, setSelectedChartId } = useWidgetStore();
const [panelDimensions, setPanelDimensions] = useState<{ const [panelDimensions, setPanelDimensions] = useState<{
[side in Side]?: { width: number; height: number }; [side in Side]?: { width: number; height: number };
@@ -85,16 +87,34 @@ export const DraggableWidget = ({
try { try {
const email = localStorage.getItem("email") || ""; const email = localStorage.getItem("email") || "";
const organization = email?.split("@")[1]?.split(".")[0]; const organization = email?.split("@")[1]?.split(".")[0];
const response = await deleteWidgetApi(widget.id, organization); let deleteWidget = {
if (response?.message === "Widget deleted successfully") { zoneId: selectedZone.zoneId,
const updatedWidgets = selectedZone.widgets.filter( widgetID: widget.id,
(w: Widget) => w.id !== widget.id organization: organization
);
setSelectedZone((prevZone: any) => ({
...prevZone,
widgets: updatedWidgets,
}));
} }
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) { } catch (error) {
} finally { } finally {
@@ -260,14 +280,14 @@ export const DraggableWidget = ({
title={widget.title} title={widget.title}
fontSize={widget.fontSize} fontSize={widget.fontSize}
fontWeight={widget.fontWeight} fontWeight={widget.fontWeight}
// data={{ // data={{
// measurements: [ // measurements: [
// { name: "testDevice", fields: "powerConsumption" }, // { name: "testDevice", fields: "powerConsumption" },
// { name: "furnace", fields: "powerConsumption" }, // { name: "furnace", fields: "powerConsumption" },
// ], // ],
// interval: 1000, // interval: 1000,
// duration: "1h", // duration: "1h",
// }} // }}
/> />
)} )}
{widget.type === "bar" && ( {widget.type === "bar" && (
@@ -277,14 +297,14 @@ export const DraggableWidget = ({
title={widget.title} title={widget.title}
fontSize={widget.fontSize} fontSize={widget.fontSize}
fontWeight={widget.fontWeight} fontWeight={widget.fontWeight}
// data={{ // data={{
// measurements: [ // measurements: [
// { name: "testDevice", fields: "powerConsumption" }, // { name: "testDevice", fields: "powerConsumption" },
// { name: "furnace", fields: "powerConsumption" }, // { name: "furnace", fields: "powerConsumption" },
// ], // ],
// interval: 1000, // interval: 1000,
// duration: "1h", // duration: "1h",
// }} // }}
/> />
)} )}
{widget.type === "pie" && ( {widget.type === "pie" && (
@@ -294,14 +314,14 @@ export const DraggableWidget = ({
title={widget.title} title={widget.title}
fontSize={widget.fontSize} fontSize={widget.fontSize}
fontWeight={widget.fontWeight} fontWeight={widget.fontWeight}
// data={{ // data={{
// measurements: [ // measurements: [
// { name: "testDevice", fields: "powerConsumption" }, // { name: "testDevice", fields: "powerConsumption" },
// { name: "furnace", fields: "powerConsumption" }, // { name: "furnace", fields: "powerConsumption" },
// ], // ],
// interval: 1000, // interval: 1000,
// duration: "1h", // duration: "1h",
// }} // }}
/> />
)} )}
{widget.type === "doughnut" && ( {widget.type === "doughnut" && (

View File

@@ -35,6 +35,7 @@ export default function Dropped3dWidgets() {
async function get3dWidgetData() { async function get3dWidgetData() {
let result = await get3dWidgetZoneData(selectedZone.zoneId, organization); let result = await get3dWidgetZoneData(selectedZone.zoneId, organization);
console.log('result: ', result);
setWidgets3D(result) setWidgets3D(result)
// Ensure the extracted data has id, type, and position correctly mapped // Ensure the extracted data has id, type, and position correctly mapped
const formattedWidgets = result.map((widget: any) => ({ const formattedWidgets = result.map((widget: any) => ({
@@ -107,6 +108,7 @@ export default function Dropped3dWidgets() {
// Get widgets for the currently active zone // Get widgets for the currently active zone
const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || []; const activeZoneWidgets = zoneWidgetData[selectedZone.zoneId] || [];
console.log('activeZoneWidgets: ', activeZoneWidgets);
return ( return (
<> <>

View File

@@ -79,21 +79,21 @@ const DroppedObjects: React.FC = () => {
} }
}; };
}, []); }, []);
// useEffect(() => { useEffect(() => {
// const handleClickOutside = (event: MouseEvent) => { const handleClickOutside = (event: MouseEvent) => {
// if (kebabRef.current && !kebabRef.current.contains(event.target as Node)) { if (kebabRef.current && !kebabRef.current.contains(event.target as Node)) {
// setOpenKebabId(null); setOpenKebabId(null);
// } }
// }; };
// // Add event listener when component mounts // Add event listener when component mounts
// document.addEventListener("mousedown", handleClickOutside); document.addEventListener("mousedown", handleClickOutside);
// // Clean up event listener when component unmounts // Clean up event listener when component unmounts
// return () => { return () => {
// document.removeEventListener("mousedown", handleClickOutside); document.removeEventListener("mousedown", handleClickOutside);
// }; };
// }, []); }, []);
const zoneEntries = Object.entries(zones); const zoneEntries = Object.entries(zones);
if (zoneEntries.length === 0) return null; if (zoneEntries.length === 0) return null;
@@ -378,7 +378,7 @@ const DroppedObjects: React.FC = () => {
<KebabIcon /> <KebabIcon />
</div> </div>
{openKebabId === obj.id && ( {openKebabId === obj.id && (
<div className="kebab-options"> <div className="kebab-options" ref={kebabRef}>
<div className="dublicate btn" onClick={(event) => { <div className="dublicate btn" onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
handleDuplicate(zoneName, index); // Call the duplicate handler handleDuplicate(zoneName, index); // Call the duplicate handler

View File

@@ -4,7 +4,7 @@ import { usePlayButtonStore } from "../../../store/usePlayButtonStore";
import { DraggableWidget } from "./DraggableWidget"; import { DraggableWidget } from "./DraggableWidget";
import { arrayMove } from "@dnd-kit/sortable"; import { arrayMove } from "@dnd-kit/sortable";
import { addingWidgets } from "../../../services/realTimeVisulization/zoneData/addWidgets"; import { addingWidgets } from "../../../services/realTimeVisulization/zoneData/addWidgets";
import { useAsset3dWidget } from "../../../store/store"; import { useAsset3dWidget, useSocketStore } from "../../../store/store";
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
@@ -62,6 +62,7 @@ const Panel: React.FC<PanelProps> = ({
const [openKebabId, setOpenKebabId] = useState<string | null>(null); const [openKebabId, setOpenKebabId] = useState<string | null>(null);
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { visualizationSocket } = useSocketStore();
const getPanelStyle = useMemo( const getPanelStyle = useMemo(
() => (side: Side) => { () => (side: Side) => {
@@ -102,10 +103,7 @@ const Panel: React.FC<PanelProps> = ({
); );
const handleDrop = (e: React.DragEvent, panel: Side) => { const handleDrop = (e: React.DragEvent, panel: Side) => {
e.preventDefault(); e.preventDefault();
setWidgetSelect("")
const { draggedAsset } = useWidgetStore.getState(); const { draggedAsset } = useWidgetStore.getState();
if (!draggedAsset) return; if (!draggedAsset) return;
if (isPanelLocked(panel)) return; if (isPanelLocked(panel)) return;
@@ -114,7 +112,6 @@ const Panel: React.FC<PanelProps> = ({
const maxCapacity = calculatePanelCapacity(panel); const maxCapacity = calculatePanelCapacity(panel);
if (currentWidgetsCount >= maxCapacity) return; if (currentWidgetsCount >= maxCapacity) return;
addWidgetToPanel(draggedAsset, panel); addWidgetToPanel(draggedAsset, panel);
}; };
@@ -151,18 +148,33 @@ const Panel: React.FC<PanelProps> = ({
id: generateUniqueId(), id: generateUniqueId(),
panel, panel,
}; };
try { let addWidget = {
let response = await addingWidgets(selectedZone.zoneId, organization, newWidget); organization: organization,
zoneId: selectedZone.zoneId,
if (response.message === "Widget created successfully") { widget: newWidget
setSelectedZone((prev) => ({
...prev,
widgets: [...prev.widgets, newWidget],
}));
}
} catch (error) {
console.error("Error adding widget:", error);
} }
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);
// }
}; };

View File

@@ -11,6 +11,7 @@ import DroppedObjects from "./DroppedFloatingWidgets";
import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore"; import { useDroppedObjectsStore } from "../../../store/useDroppedObjectsStore";
import { import {
useAsset3dWidget, useAsset3dWidget,
useSocketStore,
useWidgetSubOption, useWidgetSubOption,
useZones, useZones,
} from "../../../store/store"; } from "../../../store/store";
@@ -18,6 +19,7 @@ import { getZone2dData } from "../../../services/realTimeVisulization/zoneData/g
import { generateUniqueId } from "../../../functions/generateUniqueId"; import { generateUniqueId } from "../../../functions/generateUniqueId";
import { determinePosition } from "./functions/determinePosition"; import { determinePosition } from "./functions/determinePosition";
import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets"; import { addingFloatingWidgets } from "../../../services/realTimeVisulization/zoneData/addFloatingWidgets";
import SocketRealTimeViz from "../../../modules/visualization/realTimeVizSocket.dev";
type Side = "top" | "bottom" | "left" | "right"; type Side = "top" | "bottom" | "left" | "right";
@@ -56,6 +58,7 @@ const RealTimeVisulization: React.FC = () => {
>({}); >({});
const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); const { widgetSelect, setWidgetSelect } = useAsset3dWidget();
const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption();
const { visualizationSocket } = useSocketStore();
useEffect(() => { useEffect(() => {
async function GetZoneData() { async function GetZoneData() {
@@ -204,6 +207,7 @@ const RealTimeVisulization: React.FC = () => {
<Scene /> <Scene />
</div> </div>
{activeModule === "visualization" && selectedZone.zoneName !== "" && <DroppedObjects />} {activeModule === "visualization" && selectedZone.zoneName !== "" && <DroppedObjects />}
{activeModule === "visualization" && <SocketRealTimeViz />}
{/* <DroppedObjects /> */} {/* <DroppedObjects /> */}
{activeModule === "visualization" && ( {activeModule === "visualization" && (
<> <>

View File

@@ -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 (
<></>
)
}

View File

@@ -11,22 +11,28 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
return; return;
} }
const socket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`, { const socket = io(
reconnection: false, `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}`,
auth: { email, organization }, {
}); reconnection: false,
auth: { email, organization },
}
);
const VisualizationSocket = io(`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`, { const visualizationSocket = io(
reconnection: false, `http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization`,
auth: { email, organization }, {
}); reconnection: false,
auth: { email, organization },
}
);
set({ socket, VisualizationSocket }); set({ socket, visualizationSocket });
}, },
disconnectSocket: () => { disconnectSocket: () => {
set((state: any) => { set((state: any) => {
state.socket?.disconnect(); state.socket?.disconnect();
state.VisualizationSocket?.disconnect(); state.visualizationSocket?.disconnect();
return { socket: null }; return { socket: null };
}); });
}, },
@@ -211,7 +217,9 @@ export const useActiveLayer = create<any>((set: any) => ({
interface RefTextUpdateState { interface RefTextUpdateState {
refTextupdate: number; refTextupdate: number;
setRefTextUpdate: (callback: (currentValue: number) => number | number) => void; setRefTextUpdate: (
callback: (currentValue: number) => number | number
) => void;
} }
export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({ export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({
@@ -219,7 +227,9 @@ export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({
setRefTextUpdate: (callback) => setRefTextUpdate: (callback) =>
set((state) => ({ set((state) => ({
refTextupdate: refTextupdate:
typeof callback === "function" ? callback(state.refTextupdate) : callback, typeof callback === "function"
? callback(state.refTextupdate)
: callback,
})), })),
})); }));
@@ -399,4 +409,3 @@ export const useWidgetSubOption = create<any>((set: any) => ({
widgetSubOption: "2D", widgetSubOption: "2D",
setWidgetSubOption: (x: any) => set({ widgetSubOption: x }), setWidgetSubOption: (x: any) => set({ widgetSubOption: x }),
})); }));