import { useState, ReactNode } from 'react'; import { X, Maximize2, Minimize2, Pin, PinOff } from 'lucide-react'; import ComponentSettings from './ComponentSettings'; import type { TabConfig, LayoutMode, TabCustomization } from '@/types'; interface TabPanel { config: TabConfig; content: ReactNode; } interface TabbedContainerProps { panels: TabPanel[]; mode: LayoutMode; onTabClose?: (tabId: string) => void; onTabPin?: (tabId: string) => void; onCustomizationUpdate?: (tabId: string, customization: TabCustomization) => void; className?: string; } export default function TabbedContainer({ panels, mode, onTabClose, onTabPin, onCustomizationUpdate, className = '', }: TabbedContainerProps) { const [activeTabId, setActiveTabId] = useState( panels.find((p) => p.config.visible)?.config.id || panels[0]?.config.id ); const [expandedTab, setExpandedTab] = useState(null); const visiblePanels = panels .filter((p) => p.config.visible) .sort((a, b) => a.config.order - b.config.order); const activePanel = visiblePanels.find((p) => p.config.id === activeTabId); const handleExpand = (tabId: string) => { setExpandedTab(expandedTab === tabId ? null : tabId); }; // Tabs mode - single panel with tab switcher if (mode === 'tabs') { return (
{/* Tab switcher */}
{visiblePanels.map((panel) => ( )} ))}
{/* Active panel content */}
{activePanel && (
{activePanel.content}
)}
); } // Split mode - two main sections if (mode === 'split') { const leftPanels = visiblePanels.filter((p) => p.config.position !== 'right'); const rightPanels = visiblePanels.filter((p) => p.config.position === 'right'); return (
{/* Left section */}
{leftPanels.map((panel) => ( ))}
{/* Right section */}
{rightPanels.map((panel) => ( ))}
); } // Grid mode - responsive grid layout const getSizeClass = (size: TabConfig['size']) => { switch (size) { case 'small': return 'col-span-1'; case 'medium': return 'col-span-1 lg:col-span-2'; case 'large': return 'col-span-1 lg:col-span-3'; case 'full': return 'col-span-full'; default: return 'col-span-1'; } }; return (
{visiblePanels.map((panel) => (
))}
); } // Individual panel card component interface PanelCardProps { panel: TabPanel; onExpand: (tabId: string) => void; onPin?: (tabId: string) => void; onClose?: (tabId: string) => void; onCustomizationUpdate?: (tabId: string, customization: TabCustomization) => void; isExpanded: boolean; } function PanelCard({ panel, onExpand, onPin, onClose, onCustomizationUpdate, isExpanded }: PanelCardProps) { const getAvailableSettings = (tabId: string) => { // Define available settings per tab switch (tabId) { case 'news': return { autoRefresh: true, refreshRate: true, filters: { sentiment: ['ALL', 'POSITIVE', 'NEGATIVE', 'NEUTRAL'], impact: ['ALL', 'HIGH', 'MEDIUM', 'LOW'], }, theme: true, }; case 'alerts': return { autoRefresh: true, refreshRate: true, filters: { severity: ['ALL', 'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'], type: ['ALL', 'PRICE_SPIKE', 'NEWS_BREAKING', 'SUPPORT_BREACH'], }, }; case 'chart': return { displayMode: ['candlestick', 'line', 'area'], theme: true, }; case 'analytics': return { displayMode: ['detailed', 'compact', 'charts-only'], theme: true, }; case 'daily-checklist': return { autoRefresh: false, displayMode: ['all-phases', 'current-phase-only'], theme: true, }; case 'trading-journal': return { displayMode: ['detailed', 'compact', 'list'], filters: { emotion: ['all', 'confident', 'neutral', 'anxious'], result: ['all', 'winners', 'losers'], }, }; case 'market-summary': return { autoRefresh: true, refreshRate: true, displayMode: ['overview', 'levels', 'events', 'ai'], }; default: return { theme: true }; } }; return (
{/* Panel header */}

{panel.config.pinned && } {panel.config.label}

{onCustomizationUpdate && ( onCustomizationUpdate(panel.config.id, customization) } availableSettings={getAvailableSettings(panel.config.id)} /> )} {onPin && ( )} {onClose && !panel.config.pinned && ( )}
{/* Panel content */}
{panel.content}
); }