spb/countryatlas
Public
TypeScript 57%
Python 38.6%
JavaScript 3.6%
CSS 0.6%
1import Link from 'next/link';2import { t, tOpt } from '@/i18n';3import { cn } from '@/lib/cn';4import { compact, formatDate, grouped } from '@/lib/format';5import { routes } from '@/lib/site';6import type { UpdatesResponse } from '@/lib/types-analytics';78/** Latest data updates: one row per source (status, last import, vintage, latest year, values changed). */9export function LatestUpdates({ data, limit = 9 }: { data: UpdatesResponse; limit?: number }) {10 const rows = [...data.sources].sort((a, b) => (b.last_success_at ?? '').localeCompare(a.last_success_at ?? '')).slice(0, limit);11 return (12 <div className="min-w-0">13 <ul className="divide-y divide-rule border-y border-rule text-sm">14 {rows.map((s) => (15 <li key={s.source.id} className="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-x-4 py-2 md:grid-cols-[minmax(0,12rem)_6rem_7rem_5rem_minmax(0,1fr)]">16 <Link href={routes.source(s.source.id)} className="link-quiet flex min-h-[32px] min-w-0 items-center gap-2 font-medium text-ink">17 <span className={cn('inline-block h-2 w-2 shrink-0 rounded-full', s.status === 'ok' ? 'bg-up' : s.status === 'partial' ? 'bg-warn' : s.status === 'failed' ? 'bg-down' : 'bg-rule-strong')} aria-hidden />18 <span className="truncate">{s.source.name ?? s.source.id}</span>19 <span className="sr-only">{tOpt(`home.updates.status.${s.status}`, s.status)}</span>20 </Link>21 <span className="tnum text-right text-xs text-ink-2 md:text-left">{formatDate(s.last_success_at ?? s.last_retrieved_at)}</span>22 <span className="tnum hidden text-xs text-ink-3 md:block">{s.source_updated_at ? t('home.updates.vintage', { date: formatDate(s.source_updated_at) }) : ''}</span>23 <span className="tnum hidden text-xs text-ink-3 md:block">{s.latest_year ? `→ ${s.latest_year}` : ''}</span>24 <span className="tnum hidden truncate text-xs text-ink-3 md:block">25 {t('home.updates.counts', { obs: compact(s.n_observations), ind: grouped(s.n_indicators) })}26 {s.values_changed ? ` · ${t('home.updates.changed', { n: grouped(s.values_changed), c: grouped(s.countries_affected) })}` : ''}27 </span>28 </li>29 ))}30 </ul>31 <div className="mt-2 flex flex-wrap items-center justify-between gap-2 text-xs text-ink-3">32 <span className="tnum">{t('home.updates.snapshot', { run: data.snapshot.run_id ?? '', date: formatDate(data.snapshot.built_at) })}</span>33 <Link href={routes.updates()} className="inline-flex min-h-[36px] items-center text-sm text-accent hover:underline">34 {t('home.updates.all')} →35 </Link>36 </div>37 </div>38 );39}40