'use client' import { useEffect, useState, useMemo, useCallback } from 'react' import { api } from '@/lib/api' import { TerminalLayout } from '@/components/TerminalLayout' import { PageContainer, StatCard, Badge, SearchInput, FilterBar, SelectDropdown, ActionButton, } from '@/components/PremiumTable' import { Search, Shield, Loader2, ExternalLink, Store, Tag, DollarSign, Filter, } from 'lucide-react' import Link from 'next/link' import clsx from 'clsx' interface Listing { domain: string slug: string title: string | null description: string | null asking_price: number | null currency: string price_type: string pounce_score: number | null estimated_value: number | null is_verified: boolean allow_offers: boolean public_url: string seller_verified: boolean } type SortOption = 'newest' | 'price_asc' | 'price_desc' | 'score' export default function CommandMarketplacePage() { const [listings, setListings] = useState([]) const [loading, setLoading] = useState(true) const [searchQuery, setSearchQuery] = useState('') const [minPrice, setMinPrice] = useState('') const [maxPrice, setMaxPrice] = useState('') const [verifiedOnly, setVerifiedOnly] = useState(false) const [sortBy, setSortBy] = useState('newest') const [showFilters, setShowFilters] = useState(false) const loadListings = useCallback(async () => { setLoading(true) try { const params = new URLSearchParams() params.set('limit', '100') if (sortBy === 'price_asc') params.set('sort', 'price_asc') if (sortBy === 'price_desc') params.set('sort', 'price_desc') if (verifiedOnly) params.set('verified_only', 'true') const data = await api.request(`/listings?${params.toString()}`) setListings(data) } catch (err) { console.error('Failed to load listings:', err) } finally { setLoading(false) } }, [sortBy, verifiedOnly]) useEffect(() => { loadListings() }, [loadListings]) const formatPrice = (price: number | null, currency: string) => { if (!price) return 'Make Offer' return new Intl.NumberFormat('en-US', { style: 'currency', currency, minimumFractionDigits: 0, }).format(price) } // Memoized filtered and sorted listings const sortedListings = useMemo(() => { let result = listings.filter(listing => { if (searchQuery && !listing.domain.toLowerCase().includes(searchQuery.toLowerCase())) return false if (minPrice && listing.asking_price && listing.asking_price < parseFloat(minPrice)) return false if (maxPrice && listing.asking_price && listing.asking_price > parseFloat(maxPrice)) return false return true }) return result.sort((a, b) => { switch (sortBy) { case 'price_asc': return (a.asking_price || 0) - (b.asking_price || 0) case 'price_desc': return (b.asking_price || 0) - (a.asking_price || 0) case 'score': return (b.pounce_score || 0) - (a.pounce_score || 0) default: return 0 } }) }, [listings, searchQuery, minPrice, maxPrice, sortBy]) // Memoized stats const stats = useMemo(() => { const verifiedCount = listings.filter(l => l.is_verified).length const pricesWithValue = listings.filter(l => l.asking_price) const avgPrice = pricesWithValue.length > 0 ? pricesWithValue.reduce((sum, l) => sum + (l.asking_price || 0), 0) / pricesWithValue.length : 0 return { verifiedCount, avgPrice } }, [listings]) return ( My Listings } > {/* Stats */}
0 ? `$${Math.round(stats.avgPrice).toLocaleString()}` : '—'} icon={DollarSign} />
{/* Search & Filters */}
{/* Search */}
setSearchQuery(e.target.value)} className="w-full pl-12 pr-4 py-3 bg-background border border-border rounded-xl text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-2 focus:ring-accent/30 focus:border-accent" />
{/* Sort */} {/* Filter Toggle */}
{/* Expanded Filters */} {showFilters && (
Price: setMinPrice(e.target.value)} className="w-24 px-3 py-2 bg-background border border-border rounded-lg text-sm text-foreground placeholder:text-foreground-subtle focus:outline-none focus:border-accent" /> setMaxPrice(e.target.value)} className="w-24 px-3 py-2 bg-background border border-border rounded-lg text-sm text-foreground placeholder:text-foreground-subtle focus:outline-none focus:border-accent" />
)}
{/* Listings Grid */} {loading ? (
) : sortedListings.length === 0 ? (

No Domains Found

{searchQuery || minPrice || maxPrice ? 'Try adjusting your filters' : 'No domains are currently listed for sale'}

List Your Domain
) : (
{sortedListings.map((listing) => (

{listing.domain}

{listing.title && (

{listing.title}

)}
{listing.is_verified && (
)}
{listing.description && (

{listing.description}

)}
{listing.pounce_score && (
{listing.pounce_score}
)} {listing.allow_offers && ( Offers )}

{formatPrice(listing.asking_price, listing.currency)}

{listing.price_type === 'negotiable' && (

Negotiable

)}
))}
)}
) }