31 lines
1.5 KiB
TypeScript
31 lines
1.5 KiB
TypeScript
import { useEffect, useState } from "preact/hooks";
|
|
import { searchWorkspaceItems, type WorkspaceItem, type WorkspaceSearchResponse } from "@/lib/api";
|
|
import { scheduleWorkspaceSearch } from "@/lib/workspace-search";
|
|
|
|
type SearchState = WorkspaceSearchResponse & { query: string; revision: number; error: string | null };
|
|
const EMPTY_ITEMS: WorkspaceItem[] = [];
|
|
|
|
export function useWorkspaceSearch(query: string, enabled: boolean, revision: number) {
|
|
const trimmed = query.trim();
|
|
const [state, setState] = useState<SearchState | null>(null);
|
|
const validationError = trimmed.length > 200 ? "Use 200 characters or fewer." : null;
|
|
|
|
useEffect(() => {
|
|
setState(null);
|
|
if (!enabled || !trimmed || validationError) return;
|
|
return scheduleWorkspaceSearch(trimmed, searchWorkspaceItems,
|
|
(result) => setState({ ...result, query: trimmed, revision, error: null }),
|
|
(error) => setState({ items: [], hasMore: false, query: trimmed, revision, error: error instanceof Error ? error.message : String(error) })
|
|
);
|
|
}, [trimmed, enabled, revision, validationError]);
|
|
|
|
// Hide obsolete results immediately, even before effect cleanup runs.
|
|
const current = enabled && state?.query === trimmed && state.revision === revision ? state : null;
|
|
return {
|
|
items: current?.items ?? EMPTY_ITEMS,
|
|
hasMore: current?.hasMore ?? false,
|
|
error: validationError ?? current?.error ?? null,
|
|
isLoading: enabled && Boolean(trimmed) && !validationError && !current,
|
|
};
|
|
}
|