spb/countryatlas
Public
1/**2 * TypeScript mirror of the compare / rankings / regions / indicators response models in3 * `src/countryatlas/api/schemas.py` (CompareResponse, CompareSnapshotResponse, RankingsListResponse,4 * RankHistoryResponse, IndicatorsResponse, RegionsResponse). Kept in its own file so the compare / rankings5 * pages and the indicators / regions pages can be built concurrently without touching `types.ts`.6 */7import type { CountryCard, IndicatorCard, IndicatorSummary, Meta, MetricValue, Series, TopicId } from './types';89// ---------------------------------------------------------------------------------------------- compare1011/** `mode` query of `/compare` (docs/API.md § Compare). */12export type CompareMode = 'absolute' | 'per-capita' | 'index100' | 'pct';13export const COMPARE_MODES: readonly CompareMode[] = ['absolute', 'per-capita', 'index100', 'pct'];1415/** Transformation echo added by the router on every series (`extra="allow"`). */16export interface CompareTransform {17 mode: CompareMode | string;18 base_year?: number | null;19 applied: boolean;20 unit?: string | null;21}2223export interface CompareSeries extends Series {24 transform?: CompareTransform;25}2627export interface CompareResponse {28 meta: Meta;29 mode: CompareMode | string;30 base_year: number | null;31 countries: CountryCard[];32 indicators: IndicatorCard[];33 series: CompareSeries[];34}3536/** One row of `/compare/snapshot`: the indicator, its latest value per country (ISO3 → MetricValue), the best ISO3. */37export interface CompareSnapshotRow {38 indicator: IndicatorCard;39 values: Record<string, MetricValue>;40 /** ISO3 of the best value when `higher_is_better` is known, else null. */41 best: string | null;42}4344export interface CompareSnapshotResponse {45 meta: Meta;46 topic: { id: TopicId | string; name: string; short: string | null; blurb: string | null } | null;47 countries: CountryCard[];48 rows: CompareSnapshotRow[];49}5051// ---------------------------------------------------------------------------------------------- rankings5253/** `/rankings` item — an IndicatorSummary enriched with the latest ranking year and its size. */54export interface RankableIndicator extends IndicatorSummary {55 ranking_year: number | null;56 ranking_n: number | null;57}5859export interface RankingsListResponse {60 meta: Meta;61 n: number;62 items: RankableIndicator[];63}6465export interface RankHistoryPoint {66 year: number;67 rank: number | null;68 n: number | null;69 value: number | null;70 pct_rank: number | null;71}7273export interface RankHistoryResponse {74 meta: Meta;75 indicator: IndicatorCard;76 countries: CountryCard[];77 years: number[];78 /** ISO3 → points (one per year with a rank). */79 series: Record<string, RankHistoryPoint[]>;80}8182// ---------------------------------------------------------------------------------------------- indicators list / regions list8384export interface IndicatorsResponse {85 meta: Meta;86 n: number;87 filters: { topic: string | null; q: string | null; featured: boolean | null; source: string | null };88 items: IndicatorSummary[];89}9091/** `/regions` item (schemas.RegionsResponse.items is `dict[str, Any]`; these are the keys the router emits). */92export interface RegionItem {93 id: string;94 slug: string;95 name: string;96 kind: 'world' | 'region' | 'continent' | 'income' | 'org' | string;97 wb_code: string | null;98 n_members: number | null;99 description: string | null;100 population_latest: number | null;101 gdp_latest: number | null;102}103104export interface RegionsResponse {105 meta: Meta;106 n: number;107 items: RegionItem[];108}109110// ---------------------------------------------------------------------------------------------- UI-side helpers111112/** Minimal country reference passed to client components (kept small: the full CountrySummary list is ~60 kB). */113export interface CountryLite {114 id: string;115 slug: string;116 name: string;117 flag: string | null;118 region: string | null;119 income: string | null;120}121122export function toCountryLite(c: CountryCard): CountryLite {123 return { id: c.id, slug: c.slug ?? c.id.toLowerCase(), name: c.name ?? c.id, flag: c.flag, region: c.region, income: c.income };124}125