import React, { useEffect, useState, useRef } from "react"; import { usePlayButtonStore } from "../../store/usePlayButtonStore"; import Panel from "./widgets/panel/Panel"; import AddButtons from "./widgets/panel/AddButtons"; import { useSelectedZoneStore } from "../../store/useZoneStore"; import DisplayZone from "./DisplayZone"; import Scene from "../scene/scene"; import useModuleStore from "../../store/useModuleStore"; import { useDroppedObjectsStore, useFloatingWidget, } from "../../store/useDroppedObjectsStore"; import { useAsset3dWidget, useSocketStore, 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"; import SocketRealTimeViz from "./socket/realTimeVizSocket.dev"; import RenderOverlay from "../../components/templates/Overlay"; import ConfirmationPopup from "../../components/layout/confirmationPopup/ConfirmationPopup"; import DroppedObjects from "./widgets/floating/DroppedFloatingWidgets"; import EditWidgetOption from "../../components/ui/menu/EditWidgetOption"; import { useEditWidgetOptionsStore, useRightClickSelected, useRightSelected, } from "../../store/useZone3DWidgetStore"; import Dropped3dWidgets from "./widgets/3d/Dropped3dWidget"; import OuterClick from "../../utils/outerClick"; import { useWidgetStore } from "../../store/useWidgetStore"; type Side = "top" | "bottom" | "left" | "right"; type FormattedZoneData = Record< string, { activeSides: Side[]; panelOrder: Side[]; points: []; lockedPanels: Side[]; zoneId: string; zoneViewPortTarget: number[]; zoneViewPortPosition: number[]; widgets: Widget[]; } >; type Widget = { id: string; type: string; title: string; panel: Side; data: any; }; // Define the type for HiddenPanels, where keys are zone IDs and values are arrays of hidden sides interface HiddenPanels { [zoneId: string]: Side[]; } const RealTimeVisulization: React.FC = () => { const [hiddenPanels, setHiddenPanels] = React.useState({}); const containerRef = useRef(null); const { isPlaying } = usePlayButtonStore(); const { activeModule } = useModuleStore(); const [droppedObjects, setDroppedObjects] = useState([]); const [zonesData, setZonesData] = useState({}); const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { rightSelect, setRightSelect } = useRightSelected(); const { editWidgetOptions, setEditWidgetOptions } = useEditWidgetOptionsStore(); const { rightClickSelected, setRightClickSelected } = useRightClickSelected(); const [openConfirmationPopup, setOpenConfirmationPopup] = useState(false); // const [floatingWidgets, setFloatingWidgets] = useState>({}); const { floatingWidget, setFloatingWidget } = useFloatingWidget(); const { widgetSelect, setWidgetSelect } = useAsset3dWidget(); const { widgetSubOption, setWidgetSubOption } = useWidgetSubOption(); const { visualizationSocket } = useSocketStore(); const { setSelectedChartId } = useWidgetStore(); OuterClick({ contextClassName: [ "chart-container", "floating", "sidebar-right-wrapper", "card", "dropdown-menu", ], setMenuVisible: () => setSelectedChartId(null), }); useEffect(() => { async function GetZoneData() { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; try { const response = await getZone2dData(organization); // console.log('response: ', response); if (!Array.isArray(response)) { return; } const formattedData = response.reduce( (acc, zone) => { acc[zone.zoneName] = { activeSides: [], panelOrder: [], lockedPanels: [], points: zone.points, zoneId: zone.zoneId, zoneViewPortTarget: zone.viewPortCenter, zoneViewPortPosition: zone.viewPortposition, widgets: [], }; return acc; }, {} ); setZonesData(formattedData); } catch (error) {} } GetZoneData(); }, [activeModule]); // Removed `zones` from dependencies useEffect(() => { setZonesData((prev) => { if (!selectedZone) return prev; return { ...prev, [selectedZone.zoneName]: { ...prev[selectedZone.zoneName], // Keep existing properties activeSides: selectedZone.activeSides || [], panelOrder: selectedZone.panelOrder || [], lockedPanels: selectedZone.lockedPanels || [], points: selectedZone.points || [], zoneId: selectedZone.zoneId || "", zoneViewPortTarget: selectedZone.zoneViewPortTarget || [], zoneViewPortPosition: selectedZone.zoneViewPortPosition || [], widgets: selectedZone.widgets || [], }, }; }); }, [selectedZone]); // useEffect(() => {}, [floatingWidgets]); const handleDrop = async (event: React.DragEvent) => { event.preventDefault(); try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; const data = event.dataTransfer.getData("text/plain"); if (widgetSubOption === "3D") return; if (!data || selectedZone.zoneName === "") return; const droppedData = JSON.parse(data); const canvasElement = document.getElementById("real-time-vis-canvas"); if (!canvasElement) throw new Error("Canvas element not found"); // Get canvas dimensions and mouse position const rect = canvasElement.getBoundingClientRect(); let relativeX = (event.clientX - rect.left) ; let relativeY = event.clientY - rect.top; // Widget dimensions (with defaults) const widgetWidth = droppedData.width || 125; // 250/2 as default const widgetHeight = droppedData.height || 100; // 83/2 as default // Clamp to ensure widget stays fully inside canvas const clampedX = Math.max( 0, // Prevent going beyond left edge Math.min( relativeX, rect.width - widgetWidth // Prevent going beyond right edge ) ); console.log('clampedX: ', clampedX); const clampedY = Math.max( 0, // Prevent going beyond top edge Math.min( relativeY, rect.height - widgetHeight // Prevent going beyond bottom edge ) ); // Debug logging (optional) console.log("Drop coordinates:", { rawX: relativeX, rawY: relativeY, clampedX, clampedY, canvasWidth: rect.width, canvasHeight: rect.height, widgetWidth, widgetHeight }); const finalPosition = determinePosition(rect, clampedX, clampedY); const newObject = { ...droppedData, id: generateUniqueId(), position: finalPosition, }; // Zone management const existingZone = useDroppedObjectsStore.getState().zones[selectedZone.zoneName]; if (!existingZone) { useDroppedObjectsStore.getState().setZone(selectedZone.zoneName, selectedZone.zoneId); } // Socket emission const addFloatingWidget = { organization, widget: newObject, zoneId: selectedZone.zoneId, }; if (visualizationSocket) { visualizationSocket.emit("v2:viz-float:add", addFloatingWidget); } // Store update useDroppedObjectsStore.getState().addObject(selectedZone.zoneName, newObject); // Post-drop verification const droppedObjectsStore = useDroppedObjectsStore.getState(); const currentZone = droppedObjectsStore.zones[selectedZone.zoneName]; if (currentZone && currentZone.zoneId === selectedZone.zoneId) { console.log(`Objects for Zone ${selectedZone.zoneId}:`, currentZone.objects); setFloatingWidget(currentZone.objects); } else { console.warn("Zone not found or zoneId mismatch"); } } catch (error) { console.error("Error in handleDrop:", error); // Consider adding user feedback here (e.g., toast notification) } }; useEffect(() => { const handleClickOutside = (event: MouseEvent) => { const editWidgetOptions = document.querySelector( ".editWidgetOptions-wrapper" ); if ( editWidgetOptions && !editWidgetOptions.contains(event.target as Node) ) { setRightClickSelected(null); setRightSelect(null); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [setRightClickSelected]); return ( <>
{openConfirmationPopup && ( console.log("Confirmed")} onCancel={() => setOpenConfirmationPopup(false)} /> )}
handleDrop(event)} onDragOver={(event) => event.preventDefault()} >
{activeModule === "visualization" && selectedZone.zoneName !== "" && ( )} {activeModule === "visualization" && } {activeModule === "visualization" && editWidgetOptions && rightClickSelected && ( )} {activeModule === "visualization" && ( <> {!isPlaying && selectedZone?.zoneName !== "" && ( )} )}
); }; export default RealTimeVisulization;