'use client'; import type { RankingResponse } from './types'; import type { CompareMode, CompareResponse, IndicatorsResponse, RankHistoryResponse } from './types-compare'; /** Browser-side fetches for the compare / rankings pages (same-origin `/api/v1`, rewritten to the API). */ export class ClientCompareError extends Error { constructor( readonly status: number, message: string, ) { super(message); this.name = 'ClientCompareError'; } } 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 ClientCompareError(res.status, `API ${res.status}`); return (await res.json()) as T; } function qs(obj: Record): string { const p = new URLSearchParams(); for (const [k, v] of Object.entries(obj)) if (v !== undefined && v !== null && v !== '') p.set(k, String(v)); const s = p.toString(); return s ? `?${s}` : ''; } export const clientCompare = { compare: (countries: string[], indicators: string[], q: { from?: number | null; to?: number | null; mode?: CompareMode } = {}, signal?: AbortSignal) => get(`/compare${qs({ countries: countries.join(','), indicators: indicators.join(','), from: q.from, to: q.to, mode: q.mode ?? 'absolute' })}`, signal), indicators: (signal?: AbortSignal) => get('/indicators', signal), rankingTop: (slug: string, limit = 3, signal?: AbortSignal) => get(`/rankings/${encodeURIComponent(slug)}${qs({ limit, sparkline: false })}`, signal), rankHistory: (slug: string, countries: string[], signal?: AbortSignal) => get(`/rankings/${encodeURIComponent(slug)}/history${qs({ countries: countries.join(',') })}`, signal), };