'use client' import { useEffect, useState, useMemo, useCallback } from 'react' import { useSearchParams } from 'next/navigation' import { useStore } from '@/lib/store' import { api } from '@/lib/api' import { TerminalLayout } from '@/components/TerminalLayout' import { Ticker, useTickerItems } from '@/components/Ticker' import { PremiumTable, StatCard, PageContainer, Badge, SectionHeader, ActionButton } from '@/components/PremiumTable' import { Toast, useToast } from '@/components/Toast' import { Eye, Gavel, Tag, Clock, ExternalLink, Sparkles, Plus, Zap, Crown, Activity, Bell, Search, TrendingUp, ArrowRight, Globe, CheckCircle2, XCircle, Loader2, } from 'lucide-react' import clsx from 'clsx' import Link from 'next/link' interface HotAuction { domain: string current_bid: number time_remaining: string platform: string affiliate_url?: string } interface TrendingTld { tld: string current_price: number price_change: number reason: string } interface SearchResult { available: boolean | null inAuction: boolean inMarketplace: boolean auctionData?: HotAuction loading: boolean } export default function RadarPage() { const searchParams = useSearchParams() const { isAuthenticated, isLoading, user, domains, subscription, addDomain, } = useStore() const { toast, showToast, hideToast } = useToast() const [hotAuctions, setHotAuctions] = useState([]) const [trendingTlds, setTrendingTlds] = useState([]) const [loadingData, setLoadingData] = useState(true) // Universal Search State const [searchQuery, setSearchQuery] = useState('') const [searchResult, setSearchResult] = useState(null) const [addingToWatchlist, setAddingToWatchlist] = useState(false) // Check for upgrade success useEffect(() => { if (searchParams.get('upgraded') === 'true') { showToast('Welcome to your upgraded plan! 🎉', 'success') window.history.replaceState({}, '', '/terminal/radar') } }, [searchParams, showToast]) const loadDashboardData = useCallback(async () => { try { const [auctions, trending] = await Promise.all([ api.getEndingSoonAuctions(5).catch(() => []), api.getTrendingTlds().catch(() => ({ trending: [] })) ]) setHotAuctions(auctions.slice(0, 5)) setTrendingTlds(trending.trending?.slice(0, 6) || []) } catch (error) { console.error('Failed to load dashboard data:', error) } finally { setLoadingData(false) } }, []) useEffect(() => { if (isAuthenticated) { loadDashboardData() } }, [isAuthenticated, loadDashboardData]) // Universal Search - simultaneous check const handleSearch = useCallback(async (domain: string) => { if (!domain.trim()) { setSearchResult(null) return } const cleanDomain = domain.trim().toLowerCase() setSearchResult({ available: null, inAuction: false, inMarketplace: false, loading: true }) try { // Parallel checks const [whoisResult, auctionsResult] = await Promise.all([ api.checkDomain(cleanDomain, true).catch(() => null), api.getAuctions(cleanDomain).catch(() => ({ auctions: [] })), ]) const auctionMatch = (auctionsResult as any).auctions?.find( (a: any) => a.domain.toLowerCase() === cleanDomain ) const isAvailable = whoisResult && 'is_available' in whoisResult ? whoisResult.is_available : null setSearchResult({ available: isAvailable, inAuction: !!auctionMatch, inMarketplace: false, // TODO: Check marketplace auctionData: auctionMatch, loading: false, }) } catch (error) { setSearchResult({ available: null, inAuction: false, inMarketplace: false, loading: false }) } }, []) const handleAddToWatchlist = useCallback(async () => { if (!searchQuery.trim()) return setAddingToWatchlist(true) try { await addDomain(searchQuery.trim()) showToast(`Added ${searchQuery.trim()} to watchlist`, 'success') setSearchQuery('') setSearchResult(null) } catch (err: any) { showToast(err.message || 'Failed to add domain', 'error') } finally { setAddingToWatchlist(false) } }, [searchQuery, addDomain, showToast]) // Debounced search useEffect(() => { const timer = setTimeout(() => { if (searchQuery.length > 3) { handleSearch(searchQuery) } else { setSearchResult(null) } }, 500) return () => clearTimeout(timer) }, [searchQuery, handleSearch]) // Memoized computed values const { availableDomains, totalDomains, tierName, TierIcon, greeting, subtitle, listingsCount } = useMemo(() => { const availableDomains = domains?.filter(d => d.is_available) || [] const totalDomains = domains?.length || 0 const tierName = subscription?.tier_name || subscription?.tier || 'Scout' const TierIcon = tierName === 'Tycoon' ? Crown : tierName === 'Trader' ? TrendingUp : Zap const hour = new Date().getHours() const greeting = hour < 12 ? 'Good morning' : hour < 18 ? 'Good afternoon' : 'Good evening' let subtitle = '' if (availableDomains.length > 0) { subtitle = `${availableDomains.length} domain${availableDomains.length !== 1 ? 's' : ''} ready to pounce!` } else if (totalDomains > 0) { subtitle = `Monitoring ${totalDomains} domain${totalDomains !== 1 ? 's' : ''} for you` } else { subtitle = 'Start tracking domains to find opportunities' } // TODO: Get actual listings count from API const listingsCount = 0 return { availableDomains, totalDomains, tierName, TierIcon, greeting, subtitle, listingsCount } }, [domains, subscription]) // Generate ticker items const tickerItems = useTickerItems(trendingTlds, availableDomains, hotAuctions) if (isLoading || !isAuthenticated) { return (
) } return ( {toast && } {/* A. THE TICKER - Market movements */} {tickerItems.length > 0 && (
)} {/* B. QUICK STATS - 3 Cards as per concept */}
0 ? `${availableDomains.length} alerts` : undefined} icon={Eye} accent={availableDomains.length > 0} /> 0 ? `${hotAuctions.length}+` : '0'} subtitle="opportunities" icon={Gavel} />
{/* C. UNIVERSAL SEARCH - Hero Element */}

Universal Search

Check availability, auctions & marketplace simultaneously

setSearchQuery(e.target.value)} placeholder="Enter domain to check (e.g., dream.com)" className="w-full h-14 pl-12 pr-4 bg-background/80 backdrop-blur-sm border border-border/50 rounded-xl text-base text-foreground placeholder:text-foreground-subtle focus:outline-none focus:border-accent focus:ring-2 focus:ring-accent/20" />
{/* Search Results */} {searchResult && (
{searchResult.loading ? (
Checking...
) : (
{/* Availability */}
{searchResult.available === true ? ( ) : searchResult.available === false ? ( ) : ( )} {searchResult.available === true ? 'Available for registration!' : searchResult.available === false ? 'Currently registered' : 'Could not check availability'}
{searchResult.available === true && ( Register Now )}
{/* In Auction */} {searchResult.inAuction && searchResult.auctionData && (
In auction: ${searchResult.auctionData.current_bid} ({searchResult.auctionData.time_remaining})
Bid Now
)} {/* Action Buttons */}
)}
)}
{/* D. RECENT ALERTS + MARKET PULSE */}
{/* Recent Alerts / Activity Feed */}
View all } />
{availableDomains.length > 0 ? (
{availableDomains.slice(0, 5).map((domain) => (

{domain.name}

Available for registration!

Register
))}
) : totalDomains > 0 ? (

All domains are still registered

Monitoring {totalDomains} domains for you

) : (

No domains tracked yet

Use Universal Search above to start

)}
{/* Market Pulse */}
View all } />
{loadingData ? (
{[...Array(4)].map((_, i) => (
))}
) : hotAuctions.length > 0 ? ( ) : (

No auctions ending soon

)}
) }