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.0 KB · 50 lines tsx
Raw Blame History
1import type { Metadata } from 'next';2import { Suspense } from 'react';3import { t } from '@/i18n';4import { isNotBuilt } from '@/lib/api';5import { apiAnalytics } from '@/lib/api-analytics';6import { routes } from '@/lib/site';7import type { PeersResponse } from '@/lib/types-analytics';8import { NotBuiltState } from '@/components/data/empty-state';9import { PageHeader } from '@/components/explore/page-header';10import { PeersView } from '@/components/peers/peers-view';1112export const revalidate = 900;13type SP = Record<string, string | string[] | undefined>;1415function slug(v: string | string[] | undefined): string | undefined {16  const s = (Array.isArray(v) ? v[0] : v) ?? '';17  return /^[a-z0-9][a-z0-9-]*$/.test(s) ? s : undefined;18}1920export async function generateMetadata({ searchParams }: { searchParams: Promise<SP> }): Promise<Metadata> {21  const sp = await searchParams;22  const custom = !!(slug(sp.x) || slug(sp.y) || sp.year || sp.method);23  return { title: t('peers.metaTitle'), description: t('peers.description'), alternates: { canonical: routes.peers() }, robots: custom ? { index: false, follow: true } : undefined };24}2526export default async function PeersPage({ searchParams }: { searchParams: Promise<SP> }) {27  const sp = await searchParams;28  const year = Number(Array.isArray(sp.year) ? sp.year[0] : sp.year);29  const method = (Array.isArray(sp.method) ? sp.method[0] : sp.method) === 'ols' ? 'ols' : 'theil-sen';30  let data: PeersResponse | null = null;31  try {32    data = await apiAnalytics.peers({ x: slug(sp.x), y: slug(sp.y), year: Number.isInteger(year) && year > 1800 ? year : null, method });33  } catch (e) {34    if (isNotBuilt(e)) return <NotBuiltState />;35    data = null;36  }37  return (38    <>39      <PageHeader title={t('peers.title')} lede={t('peers.lede')} />40      {!data ? (41        <p className="py-8 text-sm text-ink-3">{t('peers.unavailable')}</p>42      ) : (43        <Suspense fallback={null}>44          <PeersView data={data} />45        </Suspense>46      )}47    </>48  );49}50