'use client' import { useEffect, useState, useMemo } from 'react' import { Header } from '@/components/Header' import { Footer } from '@/components/Footer' import { useStore } from '@/lib/store' import { api } from '@/lib/api' import { TrendingUp, TrendingDown, Minus, ArrowRight, BarChart3, ChevronUp, ChevronDown, ChevronsUpDown, Lock, ChevronRight, } from 'lucide-react' import Link from 'next/link' import clsx from 'clsx' interface TldData { tld: string type: string description: string avg_registration_price: number min_registration_price: number max_registration_price: number registrar_count: number trend: string } interface TrendingTld { tld: string reason: string price_change: number current_price: number } interface TldHistoryData { history: Array<{ date: string price: number }> } type SortField = 'tld' | 'avg_registration_price' | 'min_registration_price' | 'registrar_count' type SortDirection = 'asc' | 'desc' // Mini sparkline chart component with real data function MiniChart({ tld, isAuthenticated }: { tld: string, isAuthenticated: boolean }) { const [historyData, setHistoryData] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { if (isAuthenticated) { loadHistory() } }, [tld, isAuthenticated]) const loadHistory = async () => { try { const data = await api.getTldHistory(tld, 365) // Get 1 year of data // Sample down to 12 data points (monthly) const history = data.history || [] const sampledData = history .filter((_, i) => i % Math.floor(history.length / 12) === 0) .slice(0, 12) .map(h => h.price) setHistoryData(sampledData.length > 0 ? sampledData : []) } catch (error) { console.error('Failed to load history:', error) setHistoryData([]) } finally { setLoading(false) } } if (!isAuthenticated || loading || historyData.length === 0) { return (
Sign in
) } const min = Math.min(...historyData) const max = Math.max(...historyData) const range = max - min || 1 const points = historyData.map((value, i) => { const x = (i / (historyData.length - 1)) * 100 const y = 100 - ((value - min) / range) * 100 return `${x},${y}` }).join(' ') const isIncreasing = historyData[historyData.length - 1] > historyData[0] return ( ) } function SortIcon({ field, currentField, direction }: { field: SortField, currentField: SortField, direction: SortDirection }) { if (field !== currentField) { return } return direction === 'asc' ? : } function ShimmerBlock({ className }: { className?: string }) { return (
) } export default function TldPricingPage() { const { isAuthenticated, checkAuth, isLoading: authLoading } = useStore() const [tlds, setTlds] = useState([]) const [trending, setTrending] = useState([]) const [loading, setLoading] = useState(true) const [sortField, setSortField] = useState('tld') const [sortDirection, setSortDirection] = useState('asc') useEffect(() => { checkAuth() loadData() }, [checkAuth]) const loadData = async () => { try { const [overviewData, trendingData] = await Promise.all([ api.getTldOverview(100), api.getTrendingTlds(), ]) setTlds(overviewData?.tlds || []) setTrending(trendingData?.trending || []) } catch (error) { console.error('Failed to load TLD data:', error) setTlds([]) setTrending([]) } finally { setLoading(false) } } const handleSort = (field: SortField) => { if (sortField === field) { setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc') } else { setSortField(field) setSortDirection('asc') } } const sortedTlds = useMemo(() => { const sorted = [...tlds].sort((a, b) => { let aVal: number | string = a[sortField] let bVal: number | string = b[sortField] if (typeof aVal === 'string') aVal = aVal.toLowerCase() if (typeof bVal === 'string') bVal = bVal.toLowerCase() if (aVal < bVal) return sortDirection === 'asc' ? -1 : 1 if (aVal > bVal) return sortDirection === 'asc' ? 1 : -1 return 0 }) return sorted }, [tlds, sortField, sortDirection]) const getTrendIcon = (trend: string) => { switch (trend) { case 'up': return case 'down': return default: return } } if (loading || authLoading) { return (
) } return (
{/* Ambient glow */}
{/* Header */}
TLD Price Intelligence

Domain Extension Pricing

Track price trends across all major TLDs. Compare prices and monitor trends over time.

{/* Login Banner for non-authenticated users */} {!isAuthenticated && (

Unlock Full TLD Data

Sign in to see detailed pricing and trends.

Get Started Free
)} {/* Trending Section */} {trending.length > 0 && (

Trending Now

{trending.map((item) => (
.{item.tld} {isAuthenticated ? ( 0 ? "text-[#f97316] bg-[#f9731615]" : "text-accent bg-accent-muted" )}> {item.price_change > 0 ? '+' : ''}{item.price_change.toFixed(1)}% ) : ( )}

{isAuthenticated ? item.reason : 'Sign in to view trend details'}

{isAuthenticated ? ( ${item.current_price.toFixed(2)}/yr ) : ( )}
))}
)} {/* TLD Table */}
{sortedTlds.map((tld, idx) => ( ))}
Description 12-Month Trend Trend
.{tld.tld} {tld.description} {isAuthenticated ? ( ${tld.avg_registration_price.toFixed(2)} ) : ( ••• )} {isAuthenticated ? ( ${tld.min_registration_price.toFixed(2)} ) : ( ••• )} {isAuthenticated ? ( {tld.registrar_count} ) : ( )} {isAuthenticated ? getTrendIcon(tld.trend) : } Details
{/* Stats */}

Showing {sortedTlds.length} TLDs

) }