'use client'
import { useEffect, useState, useRef, useCallback } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { cn, formatPrice, formatMins } from '@/lib/utils'
import type { Listing } from '@/lib/types'
import { fetchListings } from '@/lib/api/listings'
const REFRESH_MS = 10_000
function UrgencyBadge({ mins }: { mins: number | null }) {
if (mins === null) return —
const isUrgent = mins <= 60
const isWarning = mins > 60 && mins <= 180
if (isUrgent) {
return (
{formatMins(mins)}
)
}
if (isWarning) {
return (
{formatMins(mins)}
)
}
return (
{formatMins(mins)}
)
}
function AiBadge({ match }: { match: 1 | 0 | null }) {
if (match === 1)
return ✓ AI
if (match === 0)
return ✗ AI
return null
}
function ScorePill({ score }: { score: number }) {
const color =
score >= 50
? 'text-g-green'
: score >= 20
? 'text-g-amber'
: score >= 0
? 'text-g-muted'
: 'text-g-red'
return (
{score > 0 ? `+${score}` : score}
)
}
function Thumbnail({ src }: { src: string | undefined }) {
const [err, setErr] = useState(false)
if (!src || err) {
return (
)
}
return (
// eslint-disable-next-line @next/next/no-img-element
setErr(true)}
className="w-9 h-9 rounded-lg object-cover shrink-0 border border-g-border/30 bg-g-raised"
loading="lazy"
/>
)
}
export default function RecentListings() {
const [listings, setListings] = useState([])
const [loading, setLoading] = useState(true)
const [lastRefresh, setLastRefresh] = useState(null)
const alive = useRef(true)
const refresh = useCallback(async () => {
try {
const data = await fetchListings(10)
if (alive.current) {
setListings(data)
setLastRefresh(new Date())
setLoading(false)
}
} catch {
if (alive.current) setLoading(false)
}
}, [])
useEffect(() => {
alive.current = true
refresh()
const id = setInterval(refresh, REFRESH_MS)
return () => {
alive.current = false
clearInterval(id)
}
}, [refresh])
return (
{/* ── Header ── */}
Recent Captures
{listings.length} lots
{lastRefresh && (
{lastRefresh.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })}
)}
{/* ── Body ── */}
{loading ? (
{Array.from({ length: 6 }).map((_, i) => (
))}
) : listings.length === 0 ? (
No lots captured yet
Start the engine to begin scanning
) : (
{listings.map((lot, i) => (
{/* Thumbnail */}
{/* Title + meta */}
{lot.title}
{lot.site_name}
#{lot.keyword}
{/* Price */}
{formatPrice(lot.price, lot.currency, lot.price_usd)}
{lot.price_usd && lot.currency !== 'USD' && (
${lot.price_usd.toFixed(0)} USD
)}
{/* Time left */}
{/* Score */}
{/* Open arrow — visible on hover */}
))}
)}
{/* ── Footer ── */}
{listings.length > 0 && (
)}
)
}