import type { Metadata } from 'next'; import { Suspense } from 'react'; import { t } from '@/i18n'; import { isNotBuilt, safe } from '@/lib/api'; import { apiExplore } from '@/lib/api-explore'; import { grouped } from '@/lib/format'; import { routes } from '@/lib/site'; import { TOPICS, isTopicId, topicById } from '@/lib/topics'; import type { IndicatorSummary } from '@/lib/types'; import { NotBuiltState } from '@/components/data/empty-state'; import { PageHeader } from '@/components/explore/page-header'; import { IndicatorDirectory } from '@/components/indicators/directory'; export const revalidate = 900; type Search = Promise<{ topic?: string | string[] }>; export async function generateMetadata({ searchParams }: { searchParams: Search }): Promise { const sp = await searchParams; const topic = typeof sp.topic === 'string' && isTopicId(sp.topic) ? topicById(sp.topic) : null; const title = topic ? `${topic.name} — ${t('indicators.title')}` : t('indicators.title'); return { title, description: topic ? topic.blurb : t('indicators.sub', { n: 260 }), alternates: { canonical: routes.indicators(topic?.id) }, }; } export default async function IndicatorsPage({ searchParams }: { searchParams: Search }) { const sp = await searchParams; const initialTopic = typeof sp.topic === 'string' && isTopicId(sp.topic) ? sp.topic : null; let items: IndicatorSummary[] = []; let notBuilt = false; try { items = (await apiExplore.indicators()).items; } catch (e) { if (isNotBuilt(e)) notBuilt = true; else throw e; } // Topic membership + order from the API (an indicator can belong to several topics). const perTopic = notBuilt ? [] : await Promise.all(TOPICS.map((tp) => safe(apiExplore.indicators({ topic: tp.id })))); const topicMembers: Record = {}; TOPICS.forEach((tp, i) => { const res = perTopic[i]; if (res) topicMembers[tp.id] = res.items.map((it) => it.slug); }); return ( <> {notBuilt ? ( ) : ( )} ); }