import type { Metadata } from 'next'; import { t } from '@/i18n'; import { api, isNotBuilt, safe } from '@/lib/api'; import { apiAnalytics } from '@/lib/api-analytics'; import { apiExplore } from '@/lib/api-explore'; import { routes } from '@/lib/site'; import { NotBuiltState } from '@/components/data/empty-state'; import { WorldExplorer } from '@/components/explorer/world-explorer'; import { baseFeatures } from '@/components/indicators/map-geometry'; import { DEFAULT_EXPLORER_INDICATOR, EXPLORER_VIEWS, explorerIndicators, parseYearParam, type ExplorerView } from '@/components/explorer/options'; export const revalidate = 900; type SP = Record; const SLUG = /^[a-z0-9][a-z0-9-]*$/; function first(sp: SP, k: string): string | null { const v = sp[k]; return (Array.isArray(v) ? v[0] : v) ?? null; } function parseState(sp: SP) { const ind = (first(sp, 'indicator') ?? '').toLowerCase(); const view = first(sp, 'view') as ExplorerView | null; const country = (first(sp, 'country') ?? '').toLowerCase(); const group = (first(sp, 'group') ?? 'world').toLowerCase(); return { indicator: SLUG.test(ind) ? ind : DEFAULT_EXPLORER_INDICATOR, year: parseYearParam(first(sp, 'year')), view: view && EXPLORER_VIEWS.includes(view) ? view : ('map' as ExplorerView), country: /^[a-z]{3}$/.test(country) ? country : null, group: SLUG.test(group) ? group : 'world', }; } export async function generateMetadata({ searchParams }: { searchParams: Promise }): Promise { const sp = await searchParams; const parameterized = Object.keys(sp).length > 0; return { title: t('explorer.metaTitle'), description: t('explorer.description'), alternates: { canonical: routes.explore() }, robots: parameterized ? { index: false, follow: true } : undefined, openGraph: { title: `${t('explorer.metaTitle')} — ${t('site.name')}`, description: t('explorer.description'), url: routes.explore(), type: 'website' }, }; } export default async function ExplorePage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const state = parseState(sp); let countriesRes; try { countriesRes = await api.countries(); } catch (e) { if (isNotBuilt(e)) return ; throw e; } const [indicatorsRes, groupsRes, frames] = await Promise.all([ safe(apiExplore.indicators({ with_data: true })), safe(apiExplore.regions()), safe(apiAnalytics.indicatorFrames(state.indicator, { group: state.group !== 'world' ? state.group : null })), ]); const countries = countriesRes.items.filter((c) => (c.kind ?? 'country') === 'country'); const { features, sphere } = baseFeatures(countriesRes.items); const indicators = explorerIndicators(indicatorsRes?.items ?? []); return ( ({ id: c.id, slug: c.slug, name: c.name, flag: c.flag, region: c.region, income: c.income }))} indicators={indicators} groups={groupsRes?.items ?? []} initial={frames} initialState={state} /> ); }