import type { Metadata } from 'next'; import Link from 'next/link'; import { PageHeader } from '@/components/ui/page-header'; import { Card, CardHeader, Delta, EmptyState, Table, th, td, tdNum } from '@/components/ui/primitives'; import { LineChart } from '@/components/charts/line-chart'; import { getAssetsBySlugs, getAssetSnapshots } from '@/lib/queries/assets'; import { getIndex, getIndexSeries } from '@/lib/queries/indices'; import { fmtMoney, fmtNum, fmtRelative, confidenceLabel, cn } from '@/lib/format'; import { catName } from '@/lib/taxonomy'; import type { SP } from '@/lib/search-params'; import { CompareForm } from './compare-form'; export const metadata: Metadata = { title: 'Compare', description: 'Compare up to four collectible assets or RareIndex indices side by side: indexed performance and key metrics.' }; const SLOTS = ['a', 'b', 'c', 'd'] as const; export default async function ComparePage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const keys = SLOTS.map((k) => (Array.isArray(sp[k]) ? sp[k]![0] : sp[k])).filter((v): v is string => Boolean(v)); const assetSlugs = keys.filter((k) => !k.toUpperCase().startsWith('RARE')); const tickers = keys.filter((k) => k.toUpperCase().startsWith('RARE')); const [assets, indices] = await Promise.all([getAssetsBySlugs(assetSlugs), Promise.all(tickers.map((t) => getIndex(t)))]); const series = await Promise.all([ ...assets.map(async (a) => ({ id: a.slug, label: a.title.length > 40 ? `${a.title.slice(0, 39)}…` : a.title, points: (await getAssetSnapshots(a.id, '', 730)).filter((p) => p.rivUsd != null).map((p) => ({ x: p.date, y: p.rivUsd! })) })), ...indices.filter((i): i is NonNullable => Boolean(i)).map(async (i) => ({ id: i.ticker, label: i.ticker, dashed: true, points: (await getIndexSeries(i.id, 730)).map((p) => ({ x: p.date, y: p.value })) })), ]); const found = assets.length + indices.filter(Boolean).length; return (
{found ? (

Indexed performance · 2 years

{assets.map((a) => ( ))} {indices.filter(Boolean).map((i) => ( ))} {[ ['Category', assets.map((a) => catName(a.categorySlug)), indices.map(() => 'Index')], ['RIV / value', assets.map((a) => (a.rivUsd === null ? '—' : fmtMoney(a.rivUsd))), indices.map((i) => (i?.latest ? i.latest.value.toFixed(2) : 'building'))], ['Confidence', assets.map((a) => `${confidenceLabel(a.rivConfidence)} (n=${a.rivSampleSize})`), indices.map((i) => (i?.latest?.coverage != null ? `coverage ${Math.round(i.latest.coverage * 100)}%` : '—'))], ['1D', assets.map((a) => ), indices.map((i) => )], ['7D', assets.map((a) => ), indices.map((i) => )], ['30D', assets.map((a) => ), indices.map((i) => )], ['1Y', assets.map((a) => ), indices.map((i) => )], ['Latest sale', assets.map((a) => (a.latestSaleUsd === null ? '—' : `${fmtMoney(a.latestSaleUsd)} · ${fmtRelative(a.latestSaleAt)}`)), indices.map((i) => (i?.latest?.medianSaleUsd != null ? `median ${fmtMoney(i.latest.medianSaleUsd)}` : '—'))], ['Sales (30D / all)', assets.map((a) => `${fmtNum(a.sales30d)} / ${fmtNum(a.salesCount)}`), indices.map((i) => (i?.latest ? fmtNum(i.latest.transactions) : '—'))], ['Active listings', assets.map((a) => fmtNum(a.activeListings)), indices.map(() => '—')], ['Liquidity', assets.map((a) => (a.liquidityScore == null ? '—' : Math.round(a.liquidityScore))), indices.map((i) => (i?.latest?.liquidityScore != null ? Math.round(i.latest.liquidityScore) : '—'))], ['Rarity', assets.map((a) => (a.rarityScore == null ? '—' : Math.round(a.rarityScore))), indices.map(() => '—')], ['Trending', assets.map((a) => (a.trendingScore == null ? '—' : a.trendingScore.toFixed(1))), indices.map((i) => (i?.latest?.momentum != null ? i.latest.momentum.toFixed(2) : '—'))], ].map(([label, av, iv]) => ( {(av as React.ReactNode[]).map((v, i) => ( ))} {(iv as React.ReactNode[]).map((v, i) => ( ))} ))}
Metric {a.title.length > 32 ? `${a.title.slice(0, 31)}…` : a.title} {i!.ticker}
{label as string} {v} {v}
) : ( )}
); }