import { useEffect, useState } from 'react'; import { ChevronDown, ChevronRight, Folder, RotateCcw } from 'lucide-react'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; import { AddProjectModal } from '@/components/AddProjectModal'; import { CreateProjectModal } from '@/components/CreateProjectModal'; import { api } from '@/api/client'; import type { Project } from '@/api/types'; import { sessionEvents } from '@/hooks/sessionEvents'; import { useSidebar } from '@/hooks/useSidebar'; export function Home() { const { data } = useSidebar(); const [addOpen, setAddOpen] = useState(false); const [createOpen, setCreateOpen] = useState(false); const [archived, setArchived] = useState(null); const [showArchived, setShowArchived] = useState(false); const empty = data ? data.projects.length === 0 : false; useEffect(() => { api.projects.list({ status: 'archived' }) .then(setArchived) .catch(() => {}); }, []); useEffect(() => { return sessionEvents.subscribe((event) => { if (event.type === 'project_archived') { setArchived((prev) => { if (!prev) return prev; if (prev.some((p) => p.id === event.project_id)) return prev; const fromSidebar = data?.projects.find((p) => p.id === event.project_id); if (!fromSidebar) return prev; return [ { id: fromSidebar.id, name: fromSidebar.name, path: fromSidebar.path, added_at: new Date().toISOString(), last_session_id: null, status: 'archived' as const, gitea_remote: fromSidebar.gitea_remote, }, ...prev, ]; }); } if (event.type === 'project_unarchived') { setArchived((prev) => prev ? prev.filter((p) => p.id !== event.project.id) : prev); } if (event.type === 'project_deleted') { setArchived((prev) => prev ? prev.filter((p) => p.id !== event.project_id) : prev); } if (event.type === 'project_updated') { setArchived((prev) => prev ? prev.map((p) => p.id === event.project_id ? { ...p, name: event.name } : p) : prev ); } }); }, [data]); async function handleUnarchive(id: string) { try { await api.projects.unarchive(id); // Server publishes project_unarchived; useUserEvents delivers it. } catch (err) { toast.error(err instanceof Error ? err.message : 'failed to restore project'); } } return (
{empty ? ( <>

No projects yet

Add a project from /opt or create a new one.

) : ( <>

BooCode

Pick a project from the sidebar, or add another.

)}
{archived && archived.length > 0 && (
{showArchived && (
    {archived.map((p) => (
  • {p.name}
  • ))}
)}
)}
{}} />
); }