39 lines
1.1 KiB
TypeScript
39 lines
1.1 KiB
TypeScript
/**
|
|||
|
|
* Client for /api/suggest.
|
||
|
|
*
|
||
|
|
* No `cache: "no-store"`. The compare modal's search uses it, and copying that
|
||
|
|
* here would discard both the browser cache and the ETag 304s the backend's
|
||
|
|
* CacheAndETagMiddleware already provides — on the one endpoint where prefix
|
||
|
|
* queries repeat most.
|
||
|
|
*/
|
||
|
|
|
||
|
|
export interface Suggestion {
|
||
|
|
urn: number;
|
||
|
|
school_name: string;
|
||
|
|
local_authority: string;
|
||
|
|
postcode: string;
|
||
|
|
phase: string;
|
||
|
|
school_type: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Below this the response is thousands of schools and worth no round trip. */
|
||
|
|
export const SUGGEST_MIN_QUERY = 2;
|
||
|
|
|
||
|
|
const API = process.env.NEXT_PUBLIC_API_URL || '/api';
|
||
|
|
|
||
|
|
/** Suggestions for `q`. Never throws: no suggestions is a fine outcome. */
|
||
|
|
export async function fetchSuggestions(
|
||
|
|
q: string, signal?: AbortSignal,
|
||
|
|
): Promise<Suggestion[]> {
|
||
|
|
if (q.trim().length < SUGGEST_MIN_QUERY) return [];
|
||
|
|
try {
|
||
|
|
const res = await fetch(`${API}/suggest?q=${encodeURIComponent(q.trim())}`,
|
||
|
|
{ signal });
|
||
|
|
if (!res.ok) return [];
|
||
|
|
const body = await res.json();
|
||
|
|
return body.suggestions ?? [];
|
||
|
|
} catch {
|
||
|
|
// Includes AbortError, which is the normal path on every keystroke.
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
}
|