import { useState, useEffect, useRef } from 'react' import { useNavigate } from 'react-router-dom' import { Plus, Play, FileText, Bookmark, Users, X } from 'lucide-react' import { treesApi } from '@/api/trees' import type { TreeListItem } from '@/types' import { getTreeNavigatePath } from '@/lib/routing' import { cn } from '@/lib/utils' interface QuickLaunchProps { open: boolean onClose: () => void } interface QuickAction { id: string icon: typeof Plus label: string description: string path: string color: string } const ACTIONS: QuickAction[] = [ { id: 'new-tree', icon: Plus, label: 'New Troubleshooting Flow', description: 'Create a branching decision tree', path: '/trees/new', color: '#3b82f6' }, { id: 'new-project', icon: Plus, label: 'New Project', description: 'Create a step-by-step project', path: '/flows/new', color: '#8b5cf6' }, { id: 'sessions', icon: Play, label: 'View Sessions', description: 'See active and recent sessions', path: '/sessions', color: '#f59e0b' }, { id: 'step-library', icon: Bookmark, label: 'Step Library', description: 'Browse reusable steps', path: '/step-library', color: '#10b981' }, { id: 'exports', icon: FileText, label: 'Exports & Shares', description: 'View shared session exports', path: '/shares', color: '#06b6d4' }, { id: 'team', icon: Users, label: 'Team Settings', description: 'Manage team members and roles', path: '/account', color: '#ec4899' }, ] export function QuickLaunch({ open, onClose }: QuickLaunchProps) { const navigate = useNavigate() const [recentTrees, setRecentTrees] = useState([]) const [selectedIndex, setSelectedIndex] = useState(0) const containerRef = useRef(null) const allItems = [...ACTIONS.map(a => ({ type: 'action' as const, ...a })), ...recentTrees.slice(0, 4).map(t => ({ type: 'tree' as const, ...t }))] const totalItems = allItems.length useEffect(() => { if (open) { // eslint-disable-next-line react-hooks/set-state-in-effect setSelectedIndex(0) treesApi.list({ sort_by: 'updated_at' }) .then(trees => setRecentTrees(trees.slice(0, 4))) .catch(() => {}) } }, [open]) useEffect(() => { if (!open) return const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() if (e.key === 'ArrowDown') { e.preventDefault(); setSelectedIndex(i => Math.min(i + 1, totalItems - 1)) } if (e.key === 'ArrowUp') { e.preventDefault(); setSelectedIndex(i => Math.max(i - 1, 0)) } if (e.key === 'Enter') { e.preventDefault() const item = allItems[selectedIndex] if (!item) return onClose() if (item.type === 'action') navigate(item.path) else navigate(getTreeNavigatePath(item.id, item.tree_type)) } } document.addEventListener('keydown', handler) return () => document.removeEventListener('keydown', handler) }, [open, selectedIndex, totalItems, allItems, navigate, onClose]) if (!open) return null return (

Quick Launch

{/* Actions */}

Actions

{ACTIONS.map((action, i) => { const Icon = action.icon return ( ) })} {/* Recent flows */} {recentTrees.length > 0 && ( <>

Recent Flows

{recentTrees.slice(0, 4).map((tree, ti) => { const idx = ACTIONS.length + ti return ( ) })} )}
โ†‘โ†“ Navigate โ†ต Open
) }