import Link from 'next/link'; import type { LotRow } from '@/lib/queries/market-lists'; import { cn, confidenceLabel, fmtMoney, fmtNum, fmtRelative } from '@/lib/format'; import { Table, th, td, tdNum, EmptyState, Badge, VsRiv } from '@/components/ui/primitives'; import { FeeBasisPill, GradeBadge, Thumb } from './bits'; /** * Auction intelligence table (§33–§35): the house's own estimate and bid in native currency, the * buyer-pays all-in cost in USD (hammer + buyer's premium from the house schedule) and the gated * comparison with the RareIndex Valuation. Lots the worker has not assessed yet say so. */ export function LotsIntelTable({ items, className, showHouse = true, emptyTitle = 'No auction lots', emptyDescription = 'Lots appear once auction-house connectors publish catalogues.' }: { items: LotRow[]; className?: string; showHouse?: boolean; emptyTitle?: string; emptyDescription?: string }) { if (!items.length) return ; return ( {showHouse ? : null} {items.map((l) => ( ))}
LotHouse · auctionEstimate Current bid All-in est. RIV Bid vs RIV Ends
); } function LotIntelRow({ l, showHouse }: { l: LotRow; showHouse: boolean }) { const cur = l.currency ?? 'USD'; const hasBid = l.currentBid !== null && (l.bidCount ?? 1) > 0; const approx = l.feeBasis === 'added_approximate' || l.feeBasis === 'added_default'; const allIn = l.hammerPriceUsd ?? l.allInBidUsd ?? l.allInEstimateLowUsd; const allInIsEstimate = l.hammerPriceUsd === null && l.allInBidUsd === null && l.allInEstimateLowUsd !== null; const vs = l.bidVsRiv ?? l.estimateVsRiv; const vsIsEstimate = l.bidVsRiv === null && l.estimateVsRiv !== null; return ( {l.lotNumber ? `Lot ${l.lotNumber} · ` : ''} {l.title} {l.assetSlug ? ( {l.assetTitle} ) : ( Not yet matched to a canonical asset )} {showHouse ? ( {l.auctionHouseSlug ? ( {l.auctionHouse} ) : ( l.auctionHouse )} {l.auctionName ? {l.auctionName} : null} ) : null} {l.estimateLow !== null || l.estimateHigh !== null ? ( {fmtMoney(l.estimateLow, cur)} – {fmtMoney(l.estimateHigh, cur)} {cur !== 'USD' && (l.estimateLowUsd !== null || l.estimateHighUsd !== null) ? {fmtMoney(l.estimateLowUsd)} – {fmtMoney(l.estimateHighUsd)} : null} ) : ( — )} {l.hammerPrice !== null ? ( {fmtMoney(l.hammerPrice, cur)} hammer ) : hasBid ? ( {fmtMoney(l.currentBid, cur)} {l.bidCount !== null ? `${fmtNum(l.bidCount)} bid${l.bidCount === 1 ? '' : 's'}` : 'bid'} ) : l.currentBid !== null ? ( {fmtMoney(l.currentBid, cur)} opening · 0 bids ) : ( — )} {allIn !== null ? ( {approx ? '≈ ' : ''} {fmtMoney(allIn)} {allInIsEstimate ? on low est. : null} ) : l.assessedAt ? ( — ) : ( Not assessed yet )} {l.rivUsd !== null ? ( {fmtMoney(l.rivUsd)} {confidenceLabel(l.rivConfidence)} · n={l.rivSampleSize} ) : ( — )} {vs !== null ? ( {vsIsEstimate ? est. vs RIV : null} ) : l.assessedAt && l.assessmentVerdict === 'ungated' ? ( — ) : l.assessedAt && l.assessmentVerdict === 'anomaly' ? ( Data/identity anomaly ) : l.assessedAt ? ( — ) : ( Not assessed yet )} {l.endsAt ? {fmtRelative(l.endsAt)} : '—'} {l.status} ); } /** Card list of lots for phones (image, title, house, all-in, bid vs RIV, ends). */ export function LotsIntelCards({ items, className }: { items: LotRow[]; className?: string }) { if (!items.length) return null; return ( ); }