'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,
Clock,
ExternalLink,
Plus,
Activity,
Search,
ArrowRight,
CheckCircle2,
XCircle,
Loader2,
Crosshair,
Radar,
Zap,
Globe,
Target,
Cpu,
Radio
} 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 TrendingTld {
tld: string
current_price: number
price_change: number
reason: string
}
interface SearchResult {
domain: string
status: string
is_available: boolean | null
registrar: string | null
expiration_date: string | null
loading: boolean
inAuction: boolean
auctionData?: HotAuction
}
// ============================================================================
// ANIMATED RADAR COMPONENT
// ============================================================================
function RadarAnimation() {
return (
{/* Outer Ring */}
{/* Crosshairs */}
{/* Sweeping Line */}
{/* Center Dot */}
{/* Blips */}
)
}
// ============================================================================
// 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 [searchQuery, setSearchQuery] = useState('')
const [searchResult, setSearchResult] = useState(null)
const [addingToWatchlist, setAddingToWatchlist] = useState(false)
const [searchFocused, setSearchFocused] = 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, 6))
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)
}
}, [])
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(`Target acquired: ${searchQuery.trim()}`, 'success')
setSearchQuery('')
setSearchResult(null)
} catch (err: any) {
showToast(err.message || 'Mission 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: 'System', value: 'ONLINE', highlight: true },
{ label: 'Targets', value: totalDomains.toString() },
{ label: 'Opportunities', value: availableDomains.length.toString(), highlight: availableDomains.length > 0 },
{ label: 'Market', value: `${marketStats.totalAuctions} Active` },
{ label: 'Latency', value: '12ms' },
]
return (
{toast && }
{/* ═══════════════════════════════════════════════════════════════════════ */}
{/* HERO SECTION - CINEMATIC */}
{/* ═══════════════════════════════════════════════════════════════════════ */}
{/* Left: Typography */}
Intelligence Hub // Active
Global
Recon.
Zero Blind Spots.
Scanning {marketStats.totalAuctions.toLocaleString()}+ auction listings across all major platforms.
Your targets. Your intel.
{/* Stats Row */}
{availableDomains.length}
Ready
{marketStats.endingSoon}
Ending Soon
{/* Right: Search Terminal */}
{/* Tech Corners */}
{/* Header */}
{/* Input */}
{'>'}
setSearchQuery(e.target.value)}
onFocus={() => setSearchFocused(true)}
onBlur={() => setSearchFocused(false)}
placeholder="ENTER_TARGET..."
className="w-full bg-black/50 px-10 py-5 text-2xl text-white placeholder:text-white/20 font-mono uppercase tracking-tight outline-none"
/>
{searchQuery && (
)}
{/* Results */}
{searchResult && (
{searchResult.loading ? (
Scanning registries...
) : (
{searchResult.is_available ? (
) : (
)}
{searchResult.domain}
{searchResult.is_available ? 'AVAILABLE' : 'REGISTERED'}
{searchResult.is_available && (
ACQUIRE
)}
)}
)}
{/* Footer */}
SECURE_CONNECTION
V2.1.0
{/* Ticker */}
{/* ═══════════════════════════════════════════════════════════════════════ */}
{/* LIVE FEED SECTION */}
{/* ═══════════════════════════════════════════════════════════════════════ */}
{/* Section Header */}
Live Feed
Market
Operations.
{/* Grid */}
{/* Hot Auctions */}
Active Auctions
Real-time market data
{loadingData ? (
) : hotAuctions.length > 0 ? (
) : (
No active auctions
)}
{/* Quick Actions */}
{[
{ label: 'Watchlist', desc: 'Your targets', href: '/terminal/watchlist', icon: Eye },
{ label: 'Market', desc: 'All auctions', href: '/terminal/market', icon: Gavel },
{ label: 'Intel', desc: 'TLD pricing', href: '/terminal/intel', icon: Globe },
].map((item) => (
))}
{/* System Status */}
)
}