'use client'; import { useState, useMemo } from 'react'; import type { BeadIssue } from '../../lib/types'; import { useResponsive } from '../../hooks/use-responsive'; import { cn } from '../../lib/utils'; export interface LeftPanelProps { issues: BeadIssue[]; selectedEpicId?: string | null; onEpicSelect?: (epicId: string | null) => void; } interface EpicNode { epic: BeadIssue; children: BeadIssue[]; } function buildEpicTree(issues: BeadIssue[]): EpicNode[] { const epics = issues.filter(issue => issue.issue_type === 'epic'); const epicMap = new Map(); for (const epic of epics) { epicMap.set(epic.id, { epic, children: [] }); } for (const issue of issues) { if (issue.issue_type === 'epic') continue; const parentDep = issue.dependencies.find(dep => dep.type === 'parent'); if (parentDep && epicMap.has(parentDep.target)) { epicMap.get(parentDep.target)!.children.push(issue); } } return Array.from(epicMap.values()).sort((a, b) => a.epic.id.localeCompare(b.epic.id) ); } export function LeftPanel({ issues, selectedEpicId, onEpicSelect, }: LeftPanelProps) { const [expandedEpics, setExpandedEpics] = useState>(new Set()); const { isDesktop, isTablet } = useResponsive(); const epicTree = useMemo(() => buildEpicTree(issues), [issues]); const toggleEpic = (epicId: string) => { setExpandedEpics(prev => { const next = new Set(prev); if (next.has(epicId)) { next.delete(epicId); } else { next.add(epicId); } return next; }); }; const handleEpicClick = (epicId: string) => { onEpicSelect?.(epicId === selectedEpicId ? null : epicId); // Toggle selection toggleEpic(epicId); }; if (isTablet) { return (
{epicTree.map(({ epic }) => ( ))}
); } return (
{/* Header */}
Channels {epicTree.length}
{/* Tree */}
{epicTree.map(({ epic, children }) => { const isExpanded = expandedEpics.has(epic.id); const isSelected = selectedEpicId === epic.id; const childCount = children.length; return (
{/* Sub-items (Agents/Tasks usually, but here listed as children) */} {isExpanded && childCount > 0 && (
{children.slice(0, 5).map(child => (
{child.title}
))} {childCount > 5 && (
+{childCount - 5} more
)}
)}
); })} {epicTree.length === 0 && (
📡

NO_CHANNELS

)}
{/* Footer Scope */}
); } export default LeftPanel;