'use client' import { useEffect, useState, useMemo, useCallback, useRef } from 'react' import { useStore } from '@/lib/store' import { api } from '@/lib/api' import { CommandCenterLayout } from '@/components/CommandCenterLayout' import { Toast, useToast } from '@/components/Toast' import { Eye, Gavel, ExternalLink, Plus, Activity, ArrowRight, CheckCircle2, XCircle, Loader2, Crosshair, Zap, Globe, Target, Search, Home, BarChart3, Settings, Bell, ChevronRight, TrendingUp, RefreshCw, Menu, X, Tag, Coins, Shield, LogOut, User } from 'lucide-react' import clsx from 'clsx' import Link from 'next/link' // ============================================================================ // TYPES // ============================================================================ interface HotAuction { domain: string current_bid: number time_remaining: string platform: string affiliate_url?: string } interface SearchResult { domain: string status: string is_available: boolean | null registrar: string | null expiration_date: string | null loading: boolean inAuction: boolean auctionData?: HotAuction } // ============================================================================ // FULLSCREEN NAVIGATION MENU // ============================================================================ function FullscreenNav({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) { const { user, logout, subscription } = useStore() const mainLinks = [ { label: 'Radar', href: '/terminal/radar', icon: Crosshair, desc: 'Domain search & overview' }, { label: 'Market', href: '/terminal/market', icon: Gavel, desc: 'Live auctions' }, { label: 'Watchlist', href: '/terminal/watchlist', icon: Eye, desc: 'Track domains' }, { label: 'Intel', href: '/terminal/intel', icon: BarChart3, desc: 'TLD pricing data' }, ] const secondaryLinks = [ { label: 'Sniper', href: '/terminal/sniper', icon: Target }, { label: 'Yield', href: '/terminal/yield', icon: Coins }, { label: 'For Sale', href: '/terminal/listing', icon: Tag }, { label: 'Settings', href: '/terminal/settings', icon: Settings }, ] if (!isOpen) return null return (
{/* Header */}
Menu
{/* Main Links */}
{mainLinks.map((item) => (
{item.label}
{item.desc}
))}
{/* Secondary Links */}
More
{secondaryLinks.map((item) => ( {item.label} ))}
{/* User Section */}
{user?.name || user?.email?.split('@')[0]}
{subscription?.tier || 'Scout'}
) } // ============================================================================ // MOBILE BOTTOM NAV - With Menu Button // ============================================================================ function MobileBottomNav({ active, onMenuOpen }: { active: string; onMenuOpen: () => void }) { const navItems = [ { id: 'radar', label: 'Radar', icon: Crosshair, href: '/terminal/radar' }, { id: 'market', label: 'Market', icon: Gavel, href: '/terminal/market' }, { id: 'watchlist', label: 'Watch', icon: Eye, href: '/terminal/watchlist' }, ] return ( ) } // ============================================================================ // MOBILE HEADER // ============================================================================ function MobileHeader({ onSearchOpen, isRefreshing, onRefresh }: { onSearchOpen: () => void isRefreshing: boolean onRefresh: () => void }) { return (

Radar

Live
) } // ============================================================================ // MOBILE SEARCH MODAL // ============================================================================ function MobileSearchModal({ isOpen, onClose, searchQuery, setSearchQuery, searchResult, addingToWatchlist, onAddToWatchlist }: { isOpen: boolean onClose: () => void searchQuery: string setSearchQuery: (q: string) => void searchResult: SearchResult | null addingToWatchlist: boolean onAddToWatchlist: () => void }) { const inputRef = useRef(null) useEffect(() => { if (isOpen && inputRef.current) { setTimeout(() => inputRef.current?.focus(), 100) } }, [isOpen]) if (!isOpen) return null return (
{/* Header */}
setSearchQuery(e.target.value)} placeholder="Search domain..." className="w-full h-11 bg-white/10 border border-white/[0.2] pl-11 pr-4 text-white placeholder:text-white/40 outline-none focus:border-accent/50 rounded-xl text-base" autoComplete="off" autoCorrect="off" autoCapitalize="none" />
{/* Results */}
{searchResult?.loading && (
Checking availability...
)} {searchResult && !searchResult.loading && (
{/* Status Banner */}
{searchResult.is_available ? (
) : (
)}
{searchResult.domain}
{searchResult.is_available ? 'Available for registration' : 'Already registered'}
{/* Details */} {!searchResult.is_available && searchResult.registrar && (
Registrar {searchResult.registrar}
)} {/* Actions */}
{searchResult.is_available && ( Register Now )}
)} {!searchResult && searchQuery.length === 0 && (

Enter a domain to check availability

)}
) } // ============================================================================ // STAT CARD - Higher Contrast // ============================================================================ function StatCard({ label, value, highlight, icon: Icon }: { label: string value: string | number highlight?: boolean icon: any }) { return (
{label}
{value}
) } // ============================================================================ // AUCTION CARD - Higher Contrast // ============================================================================ function AuctionCard({ auction }: { auction: HotAuction }) { return (
{auction.platform.substring(0, 2).toUpperCase()}
{auction.domain}
{auction.time_remaining}
${auction.current_bid.toLocaleString()}
Current bid
) } // ============================================================================ // DESKTOP LIVE TICKER // ============================================================================ function LiveTicker({ items }: { items: { label: string; value: string; highlight?: boolean }[] }) { return (
{[...items, ...items, ...items].map((item, i) => (
{item.label} {item.value}
))}
) } // ============================================================================ // MAIN PAGE // ============================================================================ export default function RadarPage() { const { isAuthenticated, user, domains, addDomain } = useStore() const { toast, showToast, hideToast } = useToast() const [hotAuctions, setHotAuctions] = useState([]) const [marketStats, setMarketStats] = useState({ totalAuctions: 0, endingSoon: 0 }) const [loadingData, setLoadingData] = useState(true) const [isRefreshing, setIsRefreshing] = useState(false) const [searchQuery, setSearchQuery] = useState('') const [searchResult, setSearchResult] = useState(null) const [addingToWatchlist, setAddingToWatchlist] = useState(false) const [searchFocused, setSearchFocused] = useState(false) const [mobileSearchOpen, setMobileSearchOpen] = useState(false) const [menuOpen, setMenuOpen] = useState(false) const searchInputRef = useRef(null) // Load Data const loadDashboardData = useCallback(async () => { try { const summary = await api.getDashboardSummary() setHotAuctions((summary.market.ending_soon_preview || []).slice(0, 5)) setMarketStats({ totalAuctions: summary.market.total_auctions || 0, endingSoon: summary.market.ending_soon || 0, }) } catch (error) { console.error('Failed to load data:', error) } finally { setLoadingData(false) setIsRefreshing(false) } }, []) const handleRefresh = useCallback(async () => { setIsRefreshing(true) await loadDashboardData() }, [loadDashboardData]) useEffect(() => { if (isAuthenticated) loadDashboardData() }, [isAuthenticated, loadDashboardData]) // Search const handleSearch = useCallback(async (domainInput: string) => { if (!domainInput.trim()) { setSearchResult(null); return } const cleanDomain = domainInput.trim().toLowerCase() setSearchResult({ domain: cleanDomain, status: 'checking', is_available: null, registrar: null, expiration_date: null, loading: true, inAuction: false }) try { const [whoisResult, auctionsResult] = await Promise.all([ api.checkDomain(cleanDomain).catch(() => null), api.getAuctions(cleanDomain).catch(() => ({ auctions: [] })), ]) const auctionMatch = (auctionsResult as any).auctions?.find((a: any) => a.domain.toLowerCase() === cleanDomain) setSearchResult({ domain: whoisResult?.domain || cleanDomain, status: whoisResult?.status || 'unknown', is_available: whoisResult?.is_available ?? null, registrar: whoisResult?.registrar || null, expiration_date: whoisResult?.expiration_date || null, loading: false, inAuction: !!auctionMatch, auctionData: auctionMatch, }) } catch { setSearchResult({ domain: cleanDomain, status: 'error', is_available: null, registrar: null, expiration_date: null, loading: false, inAuction: false }) } }, []) const handleAddToWatchlist = useCallback(async () => { if (!searchQuery.trim()) return setAddingToWatchlist(true) try { await addDomain(searchQuery.trim()) showToast(`Added: ${searchQuery.trim()}`, 'success') setSearchQuery('') setSearchResult(null) setMobileSearchOpen(false) } catch (err: any) { showToast(err.message || 'Failed', 'error') } finally { setAddingToWatchlist(false) } }, [searchQuery, addDomain, showToast]) useEffect(() => { const timer = setTimeout(() => { if (searchQuery.length > 3) handleSearch(searchQuery) else setSearchResult(null) }, 500) return () => clearTimeout(timer) }, [searchQuery, handleSearch]) // Computed const availableDomains = domains?.filter(d => d.is_available) || [] const totalDomains = domains?.length || 0 const tickerItems = [ { label: 'Status', value: 'ONLINE', highlight: true }, { label: 'Tracking', value: totalDomains.toString() }, { label: 'Available', value: availableDomains.length.toString(), highlight: availableDomains.length > 0 }, { label: 'Auctions', value: marketStats.totalAuctions.toString() }, ] return ( <> {/* Fullscreen Navigation Menu */} setMenuOpen(false)} /> {/* Mobile Header */} setMobileSearchOpen(true)} isRefreshing={isRefreshing} onRefresh={handleRefresh} /> {/* Mobile Search Modal */} setMobileSearchOpen(false)} searchQuery={searchQuery} setSearchQuery={setSearchQuery} searchResult={searchResult} addingToWatchlist={addingToWatchlist} onAddToWatchlist={handleAddToWatchlist} /> {/* Mobile Content */}
{toast && } {/* Stats Grid */}
0} icon={CheckCircle2} />
{/* Available Alert */} {availableDomains.length > 0 && (
{availableDomains.length} Domain{availableDomains.length > 1 ? 's' : ''} Available!
Grab them now
)} {/* Section: Live Auctions */}
Live Auctions
See all
{loadingData ? (
) : hotAuctions.length > 0 ? (
{hotAuctions.map((auction, i) => ( ))}
) : (

No active auctions

)}
{/* Section: Quick Links */}
Quick Actions
{[ { label: 'TLD Intel', desc: 'Price trends', href: '/terminal/intel', icon: TrendingUp }, { label: 'Sniper', desc: 'Set alerts', href: '/terminal/sniper', icon: Target }, { label: 'Yield', desc: 'Monetize', href: '/terminal/yield', icon: Coins }, { label: 'For Sale', desc: 'List domains', href: '/terminal/listing', icon: Tag }, ].map((item) => (
{item.label}
{item.desc}
))}
{/* Mobile Bottom Nav with Menu Button */} setMenuOpen(true)} /> {/* ═══════════════════════════════════════════════════════════════════════ */} {/* DESKTOP LAYOUT */} {/* ═══════════════════════════════════════════════════════════════════════ */}
{toast && } {/* HERO */}
{/* Left: Typography */}
Intelligence Hub

Domain Radar Find your next acquisition.

Real-time monitoring across {marketStats.totalAuctions.toLocaleString()}+ auctions. Your targets. Your intel.

{/* Stats Row */}
{totalDomains}
Tracking
{availableDomains.length}
Available
{marketStats.endingSoon}
Ending Soon
{/* Right: Search Terminal */}
{/* Header Bar */}
Domain Search
{/* Input */}
setSearchQuery(e.target.value)} onFocus={() => setSearchFocused(true)} onBlur={() => setSearchFocused(false)} placeholder="example.com" className="w-full bg-transparent px-4 py-4 text-lg text-white placeholder:text-white/20 outline-none" /> {searchQuery && ( )}
{/* Results */} {searchResult && (
{searchResult.loading ? (
Checking availability...
) : (
{/* Status Header */}
{searchResult.is_available ? ( ) : ( )} {searchResult.domain}
{searchResult.is_available ? 'Available' : 'Taken'}
{/* Registrar Info for taken domains */} {!searchResult.is_available && searchResult.registrar && (

Registered with {searchResult.registrar}

)} {/* Actions */}
{searchResult.is_available && ( Register Now )}
)}
)} {/* Hint */} {!searchResult && (

Enter a domain name to check availability

)}
{/* Ticker */} {/* CONTENT GRID */}
{/* Hot Auctions - 2 cols */}
Live Auctions
View all →
{loadingData ? (
) : hotAuctions.length > 0 ? ( ) : (
No active auctions
)}
{/* Quick Links */}
Quick Access
{[ { label: 'Watchlist', href: '/terminal/watchlist', icon: Eye }, { label: 'Market', href: '/terminal/market', icon: Gavel }, { label: 'Intel', href: '/terminal/intel', icon: Globe }, ].map((item) => ( {item.label} ))}
{/* Status */}
System online
) }