"use client"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; import { Suspense, useEffect, useMemo, useState } from "react"; import { AppShell } from "@/components/AppShell"; import { CreateWorkspaceModal } from "@/components/CreateWorkspaceModal"; import { Button } from "@/components/ui/Primitives"; import { exportNotes, listNoteSummaries, listWorkspaceSummaries, deleteWorkspace } from "@/lib/notes-client"; import { buildWorkspaceContextPackMarkdown } from "@/lib/context-pack"; import { toast } from "@/lib/toast"; import type { NoteSummary, WorkspaceSummary } from "@/lib/types"; export default function WorkspacesPage() { return (

Loading...

}>
); } function WorkspacesPageInner() { const searchParams = useSearchParams(); const [notes, setNotes] = useState([]); const [workspaces, setWorkspaces] = useState([]); const [query, setQuery] = useState(() => searchParams?.get("q") ?? ""); const [error, setError] = useState(null); const [showCreate, setShowCreate] = useState(false); const [loadKey, setLoadKey] = useState(0); useEffect(() => { setQuery(searchParams?.get("q") ?? ""); }, [searchParams]); useEffect(() => { void (async () => { try { const [nextNotes, nextWorkspaces] = await Promise.all([ listNoteSummaries(), listWorkspaceSummaries(), ]); setNotes(nextNotes); setWorkspaces(nextWorkspaces); } catch (err) { setError(err instanceof Error ? err.message : "Unable to load workspaces"); } })(); }, [loadKey]); function reload() { setLoadKey((k) => k + 1); } async function downloadWorkspaceContextPack(workspaceId: string, workspaceName: string) { try { const raw = await exportNotes("json", workspaceId); const data = JSON.parse(typeof raw === "string" ? raw : JSON.stringify(raw)) as { notes?: Array<{ id: string; title: string; body: string; tags?: string[] }>; }; const notes = (data.notes ?? []).slice(0, 50).map((n) => ({ id: n.id, title: n.title, body: n.body, tags: n.tags ?? [], })); const md = buildWorkspaceContextPackMarkdown({ workspaceId, workspaceName, notes }); const blob = new Blob([md], { type: "text/markdown" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `notelett-context-${workspaceId.slice(0, 8)}.md`; a.click(); URL.revokeObjectURL(url); toast.success("Context pack downloaded"); } catch (err) { toast.error(err instanceof Error ? err.message : "Export failed"); } } async function handleDelete(id: string, name: string) { if (!confirm(`Delete workspace "${name}"? This cannot be undone.`)) return; try { await deleteWorkspace(id); toast.success(`Workspace "${name}" deleted`); reload(); } catch (err) { toast.error(err instanceof Error ? err.message : "Delete failed"); } } const notesByWorkspace = useMemo( () => new Map( workspaces.map((workspace) => [ workspace.id, notes.filter((note) => note.workspaceId === workspace.id), ]), ), [notes, workspaces], ); const savedViews = [ { id: "workspace-all", name: "All workspaces", description: "Current backend-backed workspace inventory.", resultCount: workspaces.length, }, { id: "workspace-shared", name: "Shared workspaces", description: "Workspaces with more than one member.", resultCount: workspaces.filter((workspace) => workspace.visibility === "shared").length, }, ]; const filteredWorkspaces = useMemo(() => { const normalized = query.trim().toLowerCase(); if (!normalized) { return workspaces; } return workspaces.filter((workspace) => { const workspaceNotes = notesByWorkspace.get(workspace.id) ?? []; return ( workspace.name.toLowerCase().includes(normalized) || workspace.description.toLowerCase().includes(normalized) || workspace.owner.toLowerCase().includes(normalized) || workspace.visibility.toLowerCase().includes(normalized) || workspace.tags.some((tag) => tag.toLowerCase().includes(normalized)) || workspaceNotes.some( (note) => note.title.toLowerCase().includes(normalized) || note.excerpt.toLowerCase().includes(normalized) || note.tags.some((tag) => tag.toLowerCase().includes(normalized)), ) ); }); }, [notesByWorkspace, query, workspaces]); return ( } >
setQuery(event.target.value)} />
owner:any visibility:any sort:updated
{error ? (
{error}
) : null}
{filteredWorkspaces.map((workspace) => { const workspaceNotes = notesByWorkspace.get(workspace.id) ?? []; return (
{workspace.name}
{workspace.description}
{workspace.visibility} Owner: {workspace.owner}
{workspace.tags.map((tag) => ( #{tag} ))}
{workspaceNotes.map((note) => ( {note.title} {note.excerpt} ))}
); })}
{showCreate && ( { setShowCreate(false); toast.success("Workspace created"); reload(); }} onClose={() => setShowCreate(false)} /> )}
); }