39246-vm/frontend/components/listings/ListingDetailPanel.tsx
abbashkyt-creator 7d8ce0e322 V0.1
2026-03-14 04:02:22 +03:00

93 lines
4.1 KiB
TypeScript

'use client'
import { motion, AnimatePresence } from 'framer-motion'
import ImageGallery from './ImageGallery'
import type { Listing } from '@/lib/types'
interface Props { listing: Listing | null; onClose: () => void }
export default function ListingDetailPanel({ listing, onClose }: Props) {
return (
<AnimatePresence>
{listing && (
<>
<motion.div
initial={{ opacity: 1 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
onClick={onClose}
className="fixed inset-0 bg-black/60 backdrop-blur-md z-40"
/>
<motion.div
initial={{ x: '100%', opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: '100%', opacity: 0 }}
transition={{ type: 'spring', damping: 30, stiffness: 260 }}
className="fixed right-0 top-0 h-full w-[32rem] glass-strong z-50 overflow-y-auto shadow-2xl shadow-black/60"
>
{/* Gradient accent at top */}
<div className="h-px bg-gradient-to-r from-g-green/50 via-g-cyan/40 to-transparent" />
<div className="sticky top-0 flex items-center justify-between px-6 py-4 border-b border-g-border/30 glass-strong z-10">
<span className="text-[10px] font-bold text-g-faint uppercase tracking-[0.15em]">Lot Detail</span>
<button onClick={onClose} className="g-btn h-7 px-3 text-xs"> Close</button>
</div>
<div className="p-6 space-y-6">
<div>
<h2 className="text-g-text font-bold text-base leading-snug">{listing.title}</h2>
<div className="flex items-center gap-2 mt-3 flex-wrap">
<span className="g-badge g-badge-neutral">{listing.site_name}</span>
<span className="g-badge g-badge-blue">{listing.keyword}</span>
{listing.ai_match === 1 && <span className="g-badge g-badge-green">AI Match</span>}
{listing.ai_match === 0 && <span className="g-badge g-badge-red">AI Rejected</span>}
</div>
</div>
<div className="grid grid-cols-2 gap-3">
<div className="g-card-glow p-4">
<p className="text-[10px] uppercase tracking-[0.12em] text-g-faint mb-2">Price</p>
<p className="font-mono text-xl font-extrabold text-g-amber">{listing.price_raw || '—'}</p>
</div>
<div className="g-card-glow p-4">
<p className="text-[10px] uppercase tracking-[0.12em] text-g-faint mb-2">Score</p>
<p className="font-mono text-xl font-extrabold text-g-text">{listing.score}</p>
</div>
</div>
<div className="g-card divide-y divide-g-border/30">
<MetaRow label="Location" value={listing.location || '—'} />
<MetaRow label="Captured" value={new Date(listing.timestamp).toLocaleString()} />
{listing.ai_reason && (
<MetaRow label="AI reason" value={listing.ai_reason}
valueClass={listing.ai_match === 1 ? 'text-g-green' : 'text-g-red'} />
)}
</div>
{listing.images?.length > 0 && (
<div>
<p className="text-[10px] uppercase tracking-[0.12em] text-g-faint mb-3">Images</p>
<ImageGallery images={listing.images} />
</div>
)}
<a href={listing.link} target="_blank" rel="noopener noreferrer"
className="g-btn-primary w-full justify-center text-sm py-3 !rounded-xl font-semibold">
Open lot
</a>
</div>
</motion.div>
</>
)}
</AnimatePresence>
)
}
function MetaRow({ label, value, valueClass = 'text-g-muted' }: {
label: string; value: string; valueClass?: string
}) {
return (
<div className="flex gap-4 px-4 py-3">
<span className="text-xs text-g-faint/60 w-20 flex-shrink-0">{label}</span>
<span className={`text-xs leading-relaxed ${valueClass}`}>{value}</span>
</div>
)
}