"use client"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; import { Suspense, useCallback, useEffect, useMemo, useState } from "react"; import { AppShell } from "@/components/AppShell"; import { searchNotesRanked, type SearchRankedHit } from "@/lib/notes-client"; import { listSavedViews, createSavedView, deleteSavedView, type SavedView } from "@/lib/saved-views-client"; import { useDebounce } from "@/lib/use-debounce"; export default function SearchPage() { return (

Loading...

}>
); } function SearchPageInner() { const searchParams = useSearchParams(); const [hits, setHits] = useState([]); const [query, setQuery] = useState(() => searchParams?.get("q") ?? ""); const debouncedQuery = useDebounce(query, 250); const [mode, setMode] = useState<"lexical" | "hybrid">("hybrid"); const [savedViewsList, setSavedViewsList] = useState([]); const [error, setError] = useState(null); useEffect(() => { setQuery(searchParams?.get("q") ?? ""); }, [searchParams]); useEffect(() => { void (async () => { try { const res = await searchNotesRanked(debouncedQuery, mode); setHits(res.items); setError(null); } catch (err) { setError(err instanceof Error ? err.message : "Unable to load notes"); } })(); }, [debouncedQuery, mode]); useEffect(() => { void (async () => { try { setSavedViewsList(await listSavedViews("search")); } catch { // Saved views are best-effort } })(); }, []); const handleSaveCurrentSearch = useCallback(async () => { if (!query.trim()) return; try { const view = await createSavedView({ id: crypto.randomUUID(), name: query.trim().slice(0, 60), scope: "search", query: query.trim(), }); setSavedViewsList((current) => [...current, view]); } catch { // Best-effort } }, [query]); const handleDeleteSavedView = useCallback(async (id: string) => { try { await deleteSavedView(id); setSavedViewsList((current) => current.filter((v) => v.id !== id)); } catch { // Best-effort } }, []); const savedViews = useMemo( () => savedViewsList.map((view) => ({ id: view.id, name: view.name, query: view.query, resultCount: 0, })), [savedViewsList], ); return ( POST /notes/search} >
setQuery(event.target.value)} />
mode:{mode} {hits.length} hits
{error ?
{error}
: null}
{hits.map((hit) => (
{hit.title} {hit.matchKind} ยท score {hit.score}
{hit.snippet}
workspace: {hit.workspaceId}
))}
); }