'use client' import { useCallback, useEffect, useState } from 'react' import clsx from 'clsx' import { Loader2, Shield, Eye, RefreshCw, Zap, Check, Copy, ShoppingCart, Flame, Sparkles, Lock, Globe, X, ChevronDown, } from 'lucide-react' import Link from 'next/link' import { api } from '@/lib/api' import { useAnalyzePanelStore } from '@/lib/analyze-store' import { useStore } from '@/lib/store' // ============================================================================ // CONSTANTS // ============================================================================ const GEOS = [ { code: 'US', flag: 'πŸ‡ΊπŸ‡Έ', name: 'USA' }, { code: 'DE', flag: 'πŸ‡©πŸ‡ͺ', name: 'Germany' }, { code: 'GB', flag: 'πŸ‡¬πŸ‡§', name: 'UK' }, { code: 'CH', flag: 'πŸ‡¨πŸ‡­', name: 'Switzerland' }, { code: 'FR', flag: 'πŸ‡«πŸ‡·', name: 'France' }, ] const TLDS = ['com', 'io', 'ai', 'co', 'net', 'app'] // ============================================================================ // COMPONENT // ============================================================================ export function TrendSurferTab({ showToast }: { showToast: (msg: string, type?: any) => void }) { const openAnalyze = useAnalyzePanelStore((s) => s.open) const addDomain = useStore((s) => s.addDomain) const subscription = useStore((s) => s.subscription) const tier = (subscription?.tier || '').toLowerCase() const hasAI = tier === 'trader' || tier === 'tycoon' // State const [geo, setGeo] = useState('US') const [loading, setLoading] = useState(true) const [trends, setTrends] = useState>([]) const [selected, setSelected] = useState(null) const [tlds, setTlds] = useState(['com', 'io', 'ai']) // Keywords to check (original + AI expanded) const [keywords, setKeywords] = useState([]) const [aiLoading, setAiLoading] = useState(false) // Results const [results, setResults] = useState>([]) const [checking, setChecking] = useState(false) const [copied, setCopied] = useState(null) const [tracking, setTracking] = useState(null) // Load trends const loadTrends = useCallback(async () => { setLoading(true) try { const res = await api.getHuntTrends(geo) setTrends(res.items || []) } catch (e) { showToast('Failed to load trends', 'error') } finally { setLoading(false) } }, [geo, showToast]) useEffect(() => { loadTrends() }, [loadTrends]) // When a trend is selected, set the base keyword and auto-expand with AI if available const selectTrend = useCallback(async (trend: string) => { const baseKeyword = trend.toLowerCase().replace(/\s+/g, '') setSelected(trend) setKeywords([baseKeyword]) setResults([]) // Auto-expand with AI if available if (hasAI) { setAiLoading(true) try { const res = await api.expandTrendKeywords(trend, geo) if (res.keywords?.length) { // Combine base + AI keywords, remove duplicates const all = [baseKeyword, ...res.keywords.filter(k => k !== baseKeyword)] setKeywords(all.slice(0, 8)) // Max 8 keywords } } catch (e) { // Silent fail for AI } finally { setAiLoading(false) } } }, [geo, hasAI]) // Check availability for all keywords const checkAvailability = useCallback(async () => { if (keywords.length === 0 || tlds.length === 0) return setChecking(true) setResults([]) try { const res = await api.huntKeywords({ keywords, tlds }) setResults(res.items.map(i => ({ domain: i.domain, available: i.status === 'available' }))) const avail = res.items.filter(i => i.status === 'available').length showToast(`Found ${avail} available domains!`, 'success') } catch (e) { showToast('Check failed', 'error') } finally { setChecking(false) } }, [keywords, tlds, showToast]) // Remove a keyword const removeKeyword = (kw: string) => { setKeywords(prev => prev.filter(k => k !== kw)) } // Add custom keyword const [customKw, setCustomKw] = useState('') const addKeyword = () => { const kw = customKw.trim().toLowerCase().replace(/\s+/g, '') if (kw && !keywords.includes(kw)) { setKeywords(prev => [...prev, kw]) setCustomKw('') } } // Actions const copy = (domain: string) => { navigator.clipboard.writeText(domain) setCopied(domain) setTimeout(() => setCopied(null), 1500) } const track = async (domain: string) => { if (tracking) return setTracking(domain) try { await addDomain(domain) showToast(`Added: ${domain}`, 'success') } catch (e) { showToast('Failed to track', 'error') } finally { setTracking(null) } } const availableResults = results.filter(r => r.available) const takenResults = results.filter(r => !r.available) return (
{/* Header */}

Trend Surfer

Ride the viral wave with AI-powered domain hunt

{/* Trends Grid */}
Real-time Viral Topics ({geo})
{loading ? (
{[...Array(12)].map((_, i) => (
))}
) : (
{trends.slice(0, 12).map((t, idx) => { const isSelected = selected === t.title return ( ) })}
)}
{/* Keyword Builder */} {selected && (
Target Concept
{selected}
{/* Keywords */}
Constructed Keywords {aiLoading && ( AI Expansion in progress... )}
{keywords.map((kw, idx) => ( {kw} ))} {/* Add custom keyword */}
setCustomKw(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && addKeyword()} placeholder="+ CUSTOM KW" className="w-28 px-3 py-1.5 bg-white/[0.03] border border-white/10 text-[10px] font-mono text-white placeholder:text-white/20 outline-none focus:border-accent/30 uppercase tracking-wider transition-all" />
{/* TLDs */}
Selected Extensions
{TLDS.map(tld => ( ))}
{/* Check Button */}
)} {/* Results */} {results.length > 0 && (
{/* Available */} {availableResults.length > 0 && (

{availableResults.length} High-Potential Assets Identified

{availableResults.map(r => (
Buy
))}
)} {/* Taken (collapsed) */} {takenResults.length > 0 && (
{takenResults.length} Registered Variations
{takenResults.map(r => (
{r.domain}
))}
)}
)} {/* Empty State */} {!selected && !loading && trends.length > 0 && (

Select a trending topic above

Our engines will analyze the viral potential and suggest premium assets

)}
) }