'use client'; import Link from 'next/link'; import { useMemo } from 'react'; import { t } from '@/i18n'; import { formatValue, grouped } from '@/lib/format'; import { routes } from '@/lib/site'; import type { FormatSpec } from '@/lib/types'; import type { PointCountry } from '@/lib/types-analytics'; import { Histogram } from '@/components/charts/histogram'; import { LineChart, type LineSeries } from '@/components/charts/line-chart'; import { RankedBars, type RankedBarRow } from '@/components/charts/ranked-bars'; import { histogramOf, median, wantsLog } from './geo'; export interface YearRow { country: PointCountry; value: number; rank: number; } /** Rank view: the top N of the current year, plus the selected country pinned when outside the top. */ export function RankView({ rows, year, spec, selectedId, indicatorSlug, top = 25 }: { rows: YearRow[]; year: number; spec: FormatSpec; selectedId: string | null; indicatorSlug: string; top?: number }) { const shown = rows.slice(0, top); const sel = selectedId ? rows.find((r) => r.country.id === selectedId) : null; if (sel && !shown.some((r) => r.country.id === sel.country.id)) shown.push(sel); const bars: RankedBarRow[] = shown.map((r) => ({ id: r.country.id, label: r.country.name ?? r.country.id, flag: r.country.flag, href: r.country.slug ? routes.country(r.country.slug) : null, value: r.value, rank: r.rank })); if (!rows.length) return

{t('explorer.noDataYear', { indicator: spec.name ?? '', year })}

; return (
{t('explorer.rank.sub', { n: grouped(rows.length), year })} {t('explorer.rank.full')} →
); } /** Trend view: world median (and the country count), plus the selected country's own series. */ export function TrendView({ years, values, spec, selected, subject }: { years: number[]; values: Record>; spec: FormatSpec; selected: { country: PointCountry; series: Array } | null; subject: string }) { const series: LineSeries[] = useMemo(() => { const med = years.map((y, i) => ({ period: `${y}-01-01`, year: y, value: median(Object.values(values).map((arr) => arr[i])) })); const out: LineSeries[] = [{ id: 'median', name: t('explorer.trend.median'), points: med.filter((p) => p.value != null), colorIndex: 0 }]; if (selected) out.push({ id: selected.country.id, name: selected.country.name ?? selected.country.id, points: years.map((y, i) => ({ period: `${y}-01-01`, year: y, value: selected.series[i] ?? null })).filter((p) => p.value != null), colorIndex: 1 }); return out; }, [years, values, selected]); const counts = years.map((_, i) => Object.values(values).filter((arr) => arr[i] != null).length); return (

{t('explorer.trend.note')}

); } /** Distribution view: histogram of the current year with world median and selected country markers. */ export function DistributionView({ rows, year, spec, selected }: { rows: YearRow[]; year: number; spec: FormatSpec; selected: { country: PointCountry; value: number | null } | null }) { const vals = rows.map((r) => r.value); const log = wantsLog(spec, vals); const h = useMemo(() => histogramOf(vals, 20, log), [vals, log]); const med = median(vals); const markers = [ ...(med != null ? [{ id: 'median', label: t('explorer.trend.median'), value: med, tone: 'ink' as const }] : []), ...(selected && selected.value != null ? [{ id: selected.country.id, label: selected.country.name ?? selected.country.id, value: selected.value, tone: 'accent' as const }] : []), ]; if (!rows.length) return

{t('explorer.noDataYear', { indicator: spec.name ?? '', year })}

; return (
); }