import React, { useEffect, useMemo, useRef, useState } from "react"; import { useWidgetStore } from "../../../store/useWidgetStore"; import { usePlayButtonStore } from "../../../store/usePlayButtonStore"; import { DraggableWidget } from "./DraggableWidget"; import { arrayMove } from "@dnd-kit/sortable"; type Side = "top" | "bottom" | "left" | "right"; interface Widget { id: string; type: string; title: string; panel: Side; data: any; } interface PanelProps { selectedZone: { zoneName: string; activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; widgets: Widget[]; }; setSelectedZone: React.Dispatch< React.SetStateAction<{ zoneName: string; activeSides: Side[]; panelOrder: Side[]; lockedPanels: Side[]; widgets: Widget[]; }> >; hiddenPanels: string[]; } const generateUniqueId = () => `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const Panel: React.FC = ({ selectedZone, setSelectedZone, hiddenPanels, }) => { const panelRefs = useRef<{ [side in Side]?: HTMLDivElement }>({}); const [panelDimensions, setPanelDimensions] = useState<{ [side in Side]?: { width: number; height: number }; }>({}); const { isPlaying } = usePlayButtonStore(); const getPanelStyle = useMemo( () => (side: Side) => { const currentIndex = selectedZone.panelOrder.indexOf(side); const previousPanels = selectedZone.panelOrder.slice(0, currentIndex); const leftActive = previousPanels.includes("left"); const rightActive = previousPanels.includes("right"); const topActive = previousPanels.includes("top"); const bottomActive = previousPanels.includes("bottom"); const panelSize = isPlaying ? 300 : 210; switch (side) { case "top": case "bottom": return { width: `calc(100% - ${(leftActive ? panelSize : 0) + (rightActive ? panelSize : 0) }px)`, height: `${panelSize - 2}px`, left: leftActive ? `${panelSize}px` : "0", right: rightActive ? `${panelSize}px` : "0", [side]: "0", }; case "left": case "right": return { width: `${panelSize - 2}px`, height: `calc(100% - ${(topActive ? panelSize : 0) + (bottomActive ? panelSize : 0) }px)`, top: topActive ? `${panelSize}px` : "0", bottom: bottomActive ? `${panelSize}px` : "0", [side]: "0", }; default: return {}; } }, [selectedZone.panelOrder, isPlaying] ); const handleDrop = (e: React.DragEvent, panel: Side) => { e.preventDefault(); const { draggedAsset } = useWidgetStore.getState(); if (!draggedAsset) return; if (isPanelLocked(panel)) return; const currentWidgetsCount = getCurrentWidgetCount(panel); const maxCapacity = calculatePanelCapacity(panel); if (currentWidgetsCount >= maxCapacity) return; console.log('draggedAsset: ', draggedAsset); console.log('panel: ', panel); addWidgetToPanel(draggedAsset, panel); }; const isPanelLocked = (panel: Side) => selectedZone.lockedPanels.includes(panel); const getCurrentWidgetCount = (panel: Side) => selectedZone.widgets.filter((w) => w.panel === panel).length; const calculatePanelCapacity = (panel: Side) => { const CHART_WIDTH = 150; const CHART_HEIGHT = 150; const FALLBACK_HORIZONTAL_CAPACITY = 5; const FALLBACK_VERTICAL_CAPACITY = 3; const dimensions = panelDimensions[panel]; if (!dimensions) { return panel === "top" || panel === "bottom" ? FALLBACK_HORIZONTAL_CAPACITY : FALLBACK_VERTICAL_CAPACITY; } return panel === "top" || panel === "bottom" ? Math.floor(dimensions.width / CHART_WIDTH) : Math.floor(dimensions.height / CHART_HEIGHT); }; const addWidgetToPanel = (asset: any, panel: Side) => { const newWidget = { ...asset, id: generateUniqueId(), panel, }; setSelectedZone((prev) => ({ ...prev, widgets: [...prev.widgets, newWidget], })); }; useEffect(() => { const observers: ResizeObserver[] = []; const currentPanelRefs = panelRefs.current; selectedZone.activeSides.forEach((side) => { const element = currentPanelRefs[side]; if (element) { const observer = new ResizeObserver((entries) => { for (const entry of entries) { const { width, height } = entry.contentRect; setPanelDimensions((prev) => ({ ...prev, [side]: { width, height }, })); } }); observer.observe(element); observers.push(observer); } }); return () => { observers.forEach((observer) => observer.disconnect()); }; }, [selectedZone.activeSides]); const handleReorder = (fromIndex: number, toIndex: number, panel: Side) => { if (!selectedZone) return; // Ensure selectedZone is not null console.log('selectedZone: ', selectedZone); setSelectedZone((prev) => { if (!prev) return prev; // Ensure prev is not null // Filter widgets for the specified panel const widgetsInPanel = prev.widgets.filter((w) => w.panel === panel); // Reorder widgets within the same panel const reorderedWidgets = arrayMove(widgetsInPanel, fromIndex, toIndex); // Merge the reordered widgets back into the full list while preserving the order const updatedWidgets = prev.widgets .filter((widget) => widget.panel !== panel) // Keep widgets from other panels .concat(reorderedWidgets); // Add the reordered widgets for the specified panel return { ...prev, widgets: updatedWidgets, }; }); }; return ( <> {selectedZone.activeSides.map((side) => (
handleDrop(e, side)} onDragOver={(e) => e.preventDefault()} ref={(el) => { if (el) { panelRefs.current[side] = el; } else { delete panelRefs.current[side]; } }} >
{selectedZone.widgets .filter((w) => w.panel === side) .map((widget, index) => ( handleReorder(fromIndex, toIndex, side) } /> ))}
))} ); }; export default Panel;