import { WalletIcon } from "../../icons/3dChartIcons"; import { useEffect, useRef, useState } from "react"; 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"; import { DublicateIcon, KebabIcon, DeleteIcon, } from "../../icons/ExportCommonIcons"; import DistanceLines from "./DistanceLines"; // Import the DistanceLines component import { deleteFloatingWidgetApi } from "../../../services/realTimeVisulization/zoneData/deleteFloatingWidget"; import TotalCardComponent from "../realTimeVis/floating/TotalCardComponent"; import WarehouseThroughputComponent from "../realTimeVis/floating/WarehouseThroughputComponent"; import FleetEfficiencyComponent from "../realTimeVis/floating/FleetEfficiencyComponent"; import { useWidgetStore } from "../../../store/useWidgetStore"; interface DraggingState { zone: string; index: number; initialPosition: { top: number | "auto"; left: number | "auto"; right: number | "auto"; bottom: number | "auto"; }; } interface DraggingState { zone: string; index: number; initialPosition: { top: number | "auto"; left: number | "auto"; right: number | "auto"; bottom: number | "auto"; }; } const DroppedObjects: React.FC = () => { const zones = useDroppedObjectsStore((state) => state.zones); const [openKebabId, setOpenKebabId] = useState(null); const updateObjectPosition = useDroppedObjectsStore( (state) => state.updateObjectPosition ); const deleteObject = useDroppedObjectsStore((state) => state.deleteObject); const duplicateObject = useDroppedObjectsStore((state) => state.duplicateObject); const [draggingIndex, setDraggingIndex] = useState( null ); const [offset, setOffset] = useState<[number, number] | null>(null); const { setSelectedChartId } = useWidgetStore(); const [activeEdges, setActiveEdges] = useState<{ vertical: "top" | "bottom"; horizontal: "left" | "right"; } | null>(null); // State to track active edges for distance lines const [currentPosition, setCurrentPosition] = useState<{ top: number | "auto"; left: number | "auto"; right: number | "auto"; bottom: number | "auto"; } | null>(null); // State to track the current position during drag const animationRef = useRef(null); const { activeModule } = useModuleStore(); // Clean up animation frame on unmount useEffect(() => { return () => { if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, []); const zoneEntries = Object.entries(zones); if (zoneEntries.length === 0) return null; const [zoneName, zone] = zoneEntries[0]; function handleDuplicate(zoneName: string, index: number) { setOpenKebabId(null) duplicateObject(zoneName, index); // Call the duplicateObject method from the store } async function handleDelete(zoneName: string, id: string, index: number) { try { const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; let res = await deleteFloatingWidgetApi(id, organization); console.log('res: ', res); if (res.message === "FloatingWidget deleted successfully") { deleteObject(zoneName,id, index); // Call the deleteObject method from the store } } catch (error) { console.error("Error deleting floating widget:", error); } } const handlePointerDown = (event: React.PointerEvent, index: number) => { const obj = zone.objects[index]; 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 active properties for the initial position const [activeProp1, activeProp2] = getActiveProperties(obj.position); // Set active edges for distance lines const vertical = activeProp1 === "top" ? "top" : "bottom"; const horizontal = activeProp2 === "left" ? "left" : "right"; setActiveEdges({ vertical, horizontal }); // Store the initial position strategy and active edges setDraggingIndex({ zone: zoneName, index, initialPosition: { ...obj.position }, }); // Calculate offset from mouse to object edges let offsetX = 0; let offsetY = 0; if (activeProp1 === "top") { offsetY = relativeY - (obj.position.top as number); } else { offsetY = rect.height - relativeY - (obj.position.bottom as number); } if (activeProp2 === "left") { offsetX = relativeX - (obj.position.left as number); } else { offsetX = rect.width - relativeX - (obj.position.right as number); } setOffset([offsetY, offsetX]); }; const handlePointerMove = (event: React.PointerEvent) => { if (!draggingIndex || !offset) return; 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; // Dynamically determine the current position strategy const newPositionStrategy = determinePosition(rect, relativeX, relativeY); const [activeProp1, activeProp2] = getActiveProperties(newPositionStrategy); // Update active edges for distance lines const vertical = activeProp1 === "top" ? "top" : "bottom"; const horizontal = activeProp2 === "left" ? "left" : "right"; setActiveEdges({ vertical, horizontal }); // Calculate new position based on the active properties let newY = 0; let newX = 0; if (activeProp1 === "top") { newY = relativeY - offset[0]; } else { newY = rect.height - (relativeY + offset[0]); } if (activeProp2 === "left") { newX = relativeX - offset[1]; } else { newX = rect.width - (relativeX + offset[1]); } // Apply boundaries newX = Math.max(0, Math.min(rect.width - 50, newX)); newY = Math.max(0, Math.min(rect.height - 50, newY)); // Create new position object const newPosition = { ...newPositionStrategy, [activeProp1]: newY, [activeProp2]: newX, // Clear opposite properties [activeProp1 === "top" ? "bottom" : "top"]: "auto", [activeProp2 === "left" ? "right" : "left"]: "auto", }; // Update the current position state for DistanceLines setCurrentPosition(newPosition); if (!animationRef.current) { animationRef.current = requestAnimationFrame(() => { updateObjectPosition(zoneName, draggingIndex.index, newPosition); animationRef.current = null; }); } }; const handlePointerUp = async (event: React.PointerEvent) => { try { if (!draggingIndex || !offset) return; 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; // Only now determine the final position strategy const finalPosition = determinePosition(rect, relativeX, relativeY); const [activeProp1, activeProp2] = getActiveProperties(finalPosition); // Calculate final position using the new strategy let finalY = 0; let finalX = 0; if (activeProp1 === "top") { finalY = relativeY - offset[0]; } else { finalY = rect.height - (relativeY + offset[0]); } if (activeProp2 === "left") { finalX = relativeX - offset[1]; } else { finalX = rect.width - (relativeX + offset[1]); } // Apply boundaries finalX = Math.max(0, Math.min(rect.width - 50, finalX)); finalY = Math.max(0, Math.min(rect.height - 50, finalY)); const boundedPosition = { ...finalPosition, [activeProp1]: finalY, [activeProp2]: finalX, }; // Save to backend const email = localStorage.getItem("email") || ""; const organization = email?.split("@")[1]?.split(".")[0]; const response = await addingFloatingWidgets(zone.zoneId, organization, { ...zone.objects[draggingIndex.index], position: boundedPosition, }); console.log('response: ', response); if (response.message === "Widget updated successfully") { updateObjectPosition(zoneName, draggingIndex.index, boundedPosition); } // Clean up setDraggingIndex(null); setOffset(null); setActiveEdges(null); // Clear active edges setCurrentPosition(null); // Reset current position if (animationRef.current) { cancelAnimationFrame(animationRef.current); animationRef.current = null; } } catch (error) { console.error("Error in handlePointerUp:", error); } }; const handleKebabClick = (id: string, event: React.MouseEvent) => { event.stopPropagation(); setOpenKebabId((prevId) => (prevId === id ? null : id)); }; const renderObjectContent = (obj: any) => { switch (obj.className) { case "floating total-card": return ( <>
{obj.header}
{obj.value}
{obj.per}
); case "warehouseThroughput floating": return ( <>

Warehouse Throughput

(+5) more in 2025

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

Fleet Efficiency

0%
{obj.per}%
Optimal
100%
); default: return null; } }; return (
{zone.objects.map((obj, index) => (
handlePointerDown(event, index)} onClick={() => { setSelectedChartId(obj) }} > {obj.className === "floating total-card" ? ( <> ) : obj.className === "warehouseThroughput floating" ? ( <> ) : obj.className === "fleetEfficiency floating" ? ( <> ) : null} {/* {renderObjectContent(obj)} */}
{ event.stopPropagation(); handleKebabClick(obj.id, event) }} >
{openKebabId === obj.id && (
{ event.stopPropagation(); handleDuplicate(zoneName, index); // Call the duplicate handler }}>
Duplicate
{ event.stopPropagation(); handleDelete(zoneName, obj.id, index); // Call the delete handler }}>
Delete
)}
))} {/* Render DistanceLines component during drag */} {draggingIndex !== null && activeEdges !== null && currentPosition !== null && ( )}
); }; export default DroppedObjects;