import type { SaleRow, ListingRow } from '@/lib/queries/assets';
import type { LotRow } from '@/lib/queries/market-lists';
import { fmtDate, fmtMoney, fmtRelative, fmtPct, cn } from '@/lib/format';
import { humanize } from '@/lib/taxonomy';
import { Table, th, td, tdNum, EmptyState, Badge, VsRiv } from '@/components/ui/primitives';
import { AllInCell, AssetTitleCell, FeeBasisPill, GradeBadge, PriceCell, SourceLink, Thumb, VerificationBadge } from './bits';
/** Card list for sales on small screens (image, title, grade, price, source). */
export function SalesCards({ items, className }: { items: SaleRow[]; className?: string }) {
return (
);
}
export function SalesTable({ items, showAsset = true, className, emptyDescription = 'Sales appear once connectors ingest verified transactions.', responsive = true }: { items: SaleRow[]; showAsset?: boolean; className?: string; emptyDescription?: string; responsive?: boolean }) {
if (!items.length) return ;
if (responsive) {
return (
<>
>
);
}
return (
| Date |
{showAsset ? Asset | : Listing title | }
Grade |
Price |
Type |
Source |
Quality |
{items.map((s) => (
|
{fmtDate(s.saleDate)}
|
{showAsset && s.assetSlug ? (
) : (
{s.rawTitle}
)}
|
{s.condition ? {humanize(s.condition)} : null}
|
{s.allInUsd !== null && Math.abs(s.allInUsd - s.priceUsd) >= 0.5 ? (
{fmtMoney(s.priceUsd)} hammer{s.currency !== 'USD' ? ` · ${fmtMoney(s.price, s.currency)}` : ''}
) : (
{s.feeBasis && s.feeBasis !== 'none' ? : null}
)}
|
{humanize(s.saleType)}
{s.auctionHouse ? {s.auctionHouse} : null}
|
|
{Math.round(s.confidence * 100)}%
{s.flags.length ? ⚑ : null}
|
))}
);
}
export function ListingsCards({ items, className }: { items: ListingRow[]; className?: string }) {
return (
);
}
export function ListingsTable({ items, showAsset = true, className, emptyDescription = 'Live listings appear once marketplace connectors run.', responsive = true }: { items: ListingRow[]; showAsset?: boolean; className?: string; emptyDescription?: string; responsive?: boolean }) {
if (!items.length) return ;
if (responsive) {
return (
<>
>
);
}
return (
{showAsset ? | Asset | : Listing | }
Grade |
Ask |
vs RIV
|
Type |
Seller · location |
Source |
Seen |
{items.map((l) => (
|
{showAsset && l.assetSlug ? (
) : (
{l.rawTitle}
)}
|
{l.condition ? {humanize(l.condition)} : null}
|
{l.shippingCost ? +{fmtMoney(l.shippingCost, l.currency ?? 'USD')} ship : null}
|
{l.discountToRiv === null ? (
—
) : (
{l.assetRivUsd !== undefined && l.assetRivUsd !== null ? RIV {fmtMoney(l.assetRivUsd)} : null}
)}
|
{humanize(l.listingType)}
{l.bidCount !== null ? {l.bidCount} bids : null}
{l.endsAt ? ends {fmtRelative(l.endsAt)} : null}
|
{l.seller ?? '—'}
{l.location ? {l.location} : null}
|
|
{fmtRelative(l.lastSeenAt)} |
))}
);
}
export function LotsTable({ items, className, emptyDescription = 'Auction lots appear once auction-house connectors run.' }: { items: LotRow[]; className?: string; emptyDescription?: string }) {
if (!items.length) return ;
return (
| Lot |
Auction |
Estimate |
Bid / hammer |
RIV |
Ends |
Status |
{items.map((l) => (
|
{l.lotNumber ? `Lot ${l.lotNumber} · ` : ''}
{l.title}
{l.assetSlug ? (
{l.assetTitle}
) : (
Not yet matched to a canonical asset
)}
|
{l.auctionHouse}
{l.auctionName ? {l.auctionName} : null}
|
{l.estimateLow !== null || l.estimateHigh !== null ? `${fmtMoney(l.estimateLow, l.currency ?? 'USD')} – ${fmtMoney(l.estimateHigh, l.currency ?? 'USD')}` : '—'} |
{l.hammerPrice !== null ? {fmtMoney(l.hammerPrice, l.currency ?? 'USD')} : l.currentBid !== null ? fmtMoney(l.currentBid, l.currency ?? 'USD') : '—'} |
{fmtMoney(l.rivUsd)} |
{l.endsAt ? `${fmtDate(l.endsAt, { time: true })} (${fmtRelative(l.endsAt)})` : '—'} |
{l.status}
|
))}
);
}
export function pctLabel(v: number | null): string {
return fmtPct(v);
}