'use client'; import { ClientApiError } from './client-api'; import type { MapResponse, MultiSeriesResponse, RankingResponse, SearchResponse, SimilarResponse } from './types'; import type { ChangesFeedResponse, TrendResponse } from './types-explore'; /** * Browser-side fetches used by the interactive widgets of the indicator / region / explore / changes pages. * Same-origin `/api/v1/*` (rewritten to the FastAPI service). Small and typed; server components do the * first render, these only react to user input. */ async function get(path: string, signal?: AbortSignal): Promise { const res = await fetch(`/api/v1${path}`, { headers: { accept: 'application/json' }, signal }); if (!res.ok) throw new ClientApiError(res.status, `API ${res.status}`); return (await res.json()) as T; } function qs(query: Record): string { const p = new URLSearchParams(); for (const [k, v] of Object.entries(query)) if (v !== undefined && v !== null && v !== '') p.set(k, String(v)); const s = p.toString(); return s ? `?${s}` : ''; } export const clientExplore = { indicatorMap: (slug: string, year: number | null, signal?: AbortSignal) => get(`/indicators/${encodeURIComponent(slug)}/map${qs({ year })}`, signal), indicatorTrend: (slug: string, group: string, signal?: AbortSignal) => get(`/indicators/${encodeURIComponent(slug)}/trend${qs({ group })}`, signal), seriesBundle: (countries: string[], indicator: string, signal?: AbortSignal) => get(`/series${qs({ country: countries.join(','), indicator })}`, signal), ranking: (indicator: string, group: string, limit = 60, signal?: AbortSignal) => get(`/rankings/${encodeURIComponent(indicator)}${qs({ group, limit, sparkline: false })}`, signal), changes: (q: { limit?: number; kind?: string | null; indicator?: string | null; topic?: string | null; min_severity?: number | null }, signal?: AbortSignal) => get(`/changes${qs({ limit: 100, ...q })}`, signal), search: (q: string, type?: string, limit = 8, signal?: AbortSignal) => get(`/search${qs({ q, type, limit })}`, signal), similar: (id: string, mode: string, limit = 10, signal?: AbortSignal) => get(`/countries/${encodeURIComponent(id)}/similar${qs({ mode, limit })}`, signal), };