SPB Git forge

spb/countryatlas

Public
20commits 1branches 0releases
268.3 MBsize
maindefault branch
12 days agolast push
TypeScript 57% Python 38.6% JavaScript 3.6% CSS 0.6%
2.3 KB · 62 lines tsx
Raw Blame History
1import type { Metadata } from 'next';2import { Suspense } from 'react';3import { t } from '@/i18n';4import { isNotBuilt, safe } from '@/lib/api';5import { apiExplore } from '@/lib/api-explore';6import { grouped } from '@/lib/format';7import { routes } from '@/lib/site';8import { TOPICS, isTopicId, topicById } from '@/lib/topics';9import type { IndicatorSummary } from '@/lib/types';10import { NotBuiltState } from '@/components/data/empty-state';11import { PageHeader } from '@/components/explore/page-header';12import { IndicatorDirectory } from '@/components/indicators/directory';1314export const revalidate = 900;1516type Search = Promise<{ topic?: string | string[] }>;1718export async function generateMetadata({ searchParams }: { searchParams: Search }): Promise<Metadata> {19  const sp = await searchParams;20  const topic = typeof sp.topic === 'string' && isTopicId(sp.topic) ? topicById(sp.topic) : null;21  const title = topic ? `${topic.name} — ${t('indicators.title')}` : t('indicators.title');22  return {23    title,24    description: topic ? topic.blurb : t('indicators.sub', { n: 260 }),25    alternates: { canonical: routes.indicators(topic?.id) },26  };27}2829export default async function IndicatorsPage({ searchParams }: { searchParams: Search }) {30  const sp = await searchParams;31  const initialTopic = typeof sp.topic === 'string' && isTopicId(sp.topic) ? sp.topic : null;3233  let items: IndicatorSummary[] = [];34  let notBuilt = false;35  try {36    items = (await apiExplore.indicators()).items;37  } catch (e) {38    if (isNotBuilt(e)) notBuilt = true;39    else throw e;40  }41  // Topic membership + order from the API (an indicator can belong to several topics).42  const perTopic = notBuilt ? [] : await Promise.all(TOPICS.map((tp) => safe(apiExplore.indicators({ topic: tp.id }))));43  const topicMembers: Record<string, string[]> = {};44  TOPICS.forEach((tp, i) => {45    const res = perTopic[i];46    if (res) topicMembers[tp.id] = res.items.map((it) => it.slug);47  });4849  return (50    <>51      <PageHeader title={t('indicators.title')} lede={t('indicators.sub', { n: grouped(items.length || 260) })} />52      {notBuilt ? (53        <NotBuiltState />54      ) : (55        <Suspense fallback={null}>56          <IndicatorDirectory items={items} topicMembers={topicMembers} initialTopic={initialTopic} />57        </Suspense>58      )}59    </>60  );61}62