-
e.stopPropagation()}
- >
- {/* Header */}
-
-
-
-
-
-
-
{report.domain}
-
{config.label}
-
-
-
-
-
-
-
- {/* Score */}
-
-
-
Health Score
-
-
-
= 70 ? "bg-accent" :
- report.score >= 40 ? "bg-amber-400" : "bg-red-400"
- )}
- style={{ width: `${report.score}%` }}
- />
-
-
= 70 ? "text-accent" :
- report.score >= 40 ? "text-amber-400" : "text-red-400"
- )}>
- {report.score}/100
-
-
-
-
-
- {/* Check Results */}
-
- {/* DNS */}
- {report.dns && (
-
-
-
- DNS Infrastructure
-
-
-
-
- {report.dns.has_ns ? '✓' : '✗'}
-
- Nameservers
-
-
-
- {report.dns.has_a ? '✓' : '✗'}
-
- A Record
-
-
-
- {report.dns.has_mx ? '✓' : '—'}
-
- MX Record
-
-
- {report.dns.is_parked && (
-
⚠ Parked at {report.dns.parking_provider || 'unknown provider'}
- )}
-
- )}
-
- {/* HTTP */}
- {report.http && (
-
-
-
- Website Status
-
-
-
- {report.http.is_reachable ? 'Reachable' : 'Unreachable'}
-
- {report.http.status_code && (
-
- HTTP {report.http.status_code}
-
- )}
-
- {report.http.is_parked && (
-
⚠ Parking page detected
- )}
-
- )}
-
- {/* SSL */}
- {report.ssl && (
-
-
-
- SSL Certificate
-
-
- {report.ssl.has_certificate ? (
-
-
- {report.ssl.is_valid ? '✓ Valid certificate' : '✗ Certificate invalid/expired'}
-
- {report.ssl.days_until_expiry !== undefined && (
-
30 ? "text-foreground-muted" :
- report.ssl.days_until_expiry > 7 ? "text-amber-400" : "text-red-400"
- )}>
- Expires in {report.ssl.days_until_expiry} days
-
- )}
-
- ) : (
-
No SSL certificate
- )}
-
-
- )}
-
- {/* Signals & Recommendations */}
- {((report.signals?.length || 0) > 0 || (report.recommendations?.length || 0) > 0) && (
-
- {(report.signals?.length || 0) > 0 && (
-
-
Signals
-
- {report.signals?.map((signal, i) => (
-
- •
- {signal}
-
- ))}
-
-
- )}
- {(report.recommendations?.length || 0) > 0 && (
-
-
Recommendations
-
- {report.recommendations?.map((rec, i) => (
-
- →
- {rec}
-
- ))}
-
-
- )}
-
- )}
-
-
- {/* Footer */}
-
-
- Checked at {new Date(report.checked_at).toLocaleString()}
-
-
-
-
- )
-}
-
-// Modal Component
-function Modal({ title, children, onClose }: { title: string; children: React.ReactNode; onClose: () => void }) {
- return (
-
-
e.stopPropagation()}
- >
-
-
{title}
-
-
-
-
-
- {children}
-
-
-
- )
-}
diff --git a/frontend/src/app/terminal/radar/page.tsx b/frontend/src/app/terminal/radar/page.tsx
index 62f8262..3e87ce5 100644
--- a/frontend/src/app/terminal/radar/page.tsx
+++ b/frontend/src/app/terminal/radar/page.tsx
@@ -200,10 +200,10 @@ export default function DashboardPage() {
accent={availableDomains.length > 0}
/>
-
+
@@ -291,7 +291,7 @@ export default function DashboardPage() {
icon={Gavel}
compact
action={
-
+
View all →
}
diff --git a/frontend/src/app/terminal/seo/page.tsx b/frontend/src/app/terminal/seo/page.tsx
deleted file mode 100644
index 4f96841..0000000
--- a/frontend/src/app/terminal/seo/page.tsx
+++ /dev/null
@@ -1,508 +0,0 @@
-'use client'
-
-import { useEffect, useState } from 'react'
-import { useStore } from '@/lib/store'
-import { api } from '@/lib/api'
-import { TerminalLayout } from '@/components/TerminalLayout'
-import { PageContainer, StatCard, Badge } from '@/components/PremiumTable'
-import {
- Search,
- Link2,
- Globe,
- Shield,
- TrendingUp,
- Loader2,
- AlertCircle,
- X,
- ExternalLink,
- Crown,
- CheckCircle,
- Sparkles,
- BookOpen,
- Building,
- GraduationCap,
- Newspaper,
- Lock,
- Star,
-} from 'lucide-react'
-import Link from 'next/link'
-import clsx from 'clsx'
-
-interface SEOData {
- domain: string
- seo_score: number
- value_category: string
- metrics: {
- domain_authority: number | null
- page_authority: number | null
- spam_score: number | null
- total_backlinks: number | null
- referring_domains: number | null
- }
- notable_links: {
- has_wikipedia: boolean
- has_gov: boolean
- has_edu: boolean
- has_news: boolean
- notable_domains: string[]
- }
- top_backlinks: Array<{
- domain: string
- authority: number
- page: string
- }>
- estimated_value: number | null
- data_source: string
- last_updated: string | null
- is_estimated: boolean
-}
-
-export default function SEOPage() {
- const { subscription } = useStore()
-
- const [domain, setDomain] = useState('')
- const [loading, setLoading] = useState(false)
- const [seoData, setSeoData] = useState
(null)
- const [error, setError] = useState(null)
- const [recentSearches, setRecentSearches] = useState([])
-
- const tier = subscription?.tier?.toLowerCase() || 'scout'
- const isTycoon = tier === 'tycoon'
-
- useEffect(() => {
- // Load recent searches from localStorage
- const saved = localStorage.getItem('seo-recent-searches')
- if (saved) {
- setRecentSearches(JSON.parse(saved))
- }
- }, [])
-
- const saveRecentSearch = (domain: string) => {
- const updated = [domain, ...recentSearches.filter(d => d !== domain)].slice(0, 5)
- setRecentSearches(updated)
- localStorage.setItem('seo-recent-searches', JSON.stringify(updated))
- }
-
- const cleanDomain = (d: string): string => {
- // Remove whitespace, protocol, www, and trailing slashes
- return d.trim()
- .toLowerCase()
- .replace(/\s+/g, '')
- .replace(/^https?:\/\//, '')
- .replace(/^www\./, '')
- .replace(/\/.*$/, '')
- }
-
- const handleSearch = async (e: React.FormEvent) => {
- e.preventDefault()
- const cleanedDomain = cleanDomain(domain)
- if (!cleanedDomain) return
-
- setLoading(true)
- setError(null)
- setSeoData(null)
-
- try {
- const data = await api.request(`/seo/${encodeURIComponent(cleanedDomain)}`)
- setSeoData(data)
- saveRecentSearch(cleanedDomain)
- } catch (err: any) {
- setError(err.message || 'Failed to analyze domain')
- } finally {
- setLoading(false)
- }
- }
-
- const handleQuickSearch = async (searchDomain: string) => {
- const cleanedDomain = cleanDomain(searchDomain)
- setDomain(cleanedDomain)
- setLoading(true)
- setError(null)
- setSeoData(null)
-
- try {
- const data = await api.request(`/seo/${encodeURIComponent(cleanedDomain)}`)
- setSeoData(data)
- } catch (err: any) {
- setError(err.message || 'Failed to analyze domain')
- } finally {
- setLoading(false)
- }
- }
-
- const getScoreColor = (score: number) => {
- if (score >= 60) return 'text-accent'
- if (score >= 40) return 'text-amber-400'
- if (score >= 20) return 'text-orange-400'
- return 'text-foreground-muted'
- }
-
- const getScoreBg = (score: number) => {
- if (score >= 60) return 'bg-accent/10 border-accent/30'
- if (score >= 40) return 'bg-amber-500/10 border-amber-500/30'
- if (score >= 20) return 'bg-orange-500/10 border-orange-500/30'
- return 'bg-foreground/5 border-border'
- }
-
- const formatNumber = (num: number | null) => {
- if (num === null) return '-'
- if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`
- if (num >= 1000) return `${(num / 1000).toFixed(1)}K`
- return num.toString()
- }
-
- // Show upgrade prompt for non-Tycoon users
- if (!isTycoon) {
- return (
-
-
-
-
-
-
-
Tycoon Feature
-
- SEO Juice Detector is a premium feature for serious domain investors.
- Analyze backlinks, domain authority, and find hidden gems that SEO agencies pay
- $100-$500 for — even if the name is "ugly".
-
-
-
-
-
-
Backlink Analysis
-
Top referring domains
-
-
-
-
Domain Authority
-
Moz DA/PA scores
-
-
-
-
Notable Links
-
Wikipedia, .gov, .edu
-
-
-
-
-
- Upgrade to Tycoon
-
-
-
-
- )
- }
-
- return (
-
-
- {/* Error Message */}
- {error && (
-
-
-
{error}
-
setError(null)}>
-
- )}
-
- {/* Search Form */}
-
-
-
- {/* Recent Searches */}
- {recentSearches.length > 0 && !seoData && (
-
- Recent:
- {recentSearches.map((d) => (
- handleQuickSearch(d)}
- className="px-3 py-1 text-xs bg-foreground/5 text-foreground-muted rounded-full hover:bg-foreground/10 transition-colors"
- >
- {d}
-
- ))}
-
- )}
-
-
- {/* Loading State */}
- {loading && (
-
-
-
Analyzing backlinks & authority...
-
- )}
-
- {/* Results */}
- {seoData && !loading && (
-
- {/* Header with Score */}
-
-
-
-
- {seoData.domain}
-
-
-
- {seoData.data_source === 'moz' ? 'Moz Data' : 'Estimated'}
-
- {seoData.value_category}
-
-
-
-
- {seoData.seo_score}
-
- SEO Score
-
-
-
- {/* Estimated Value */}
- {seoData.estimated_value && (
-
-
Estimated SEO Value
-
- ${seoData.estimated_value.toLocaleString()}
-
-
- Based on domain authority & backlink profile
-
-
- )}
-
-
- {/* Metrics Grid */}
-
-
-
-
-
- 30 ? '⚠️ High' : '✓ Low'}
- />
-
-
- {/* Notable Links */}
-
-
Notable Backlinks
-
-
-
-
-
Wikipedia
-
- {seoData.notable_links.has_wikipedia ? '✓ Found' : 'Not found'}
-
-
-
-
-
-
-
-
.gov Links
-
- {seoData.notable_links.has_gov ? '✓ Found' : 'Not found'}
-
-
-
-
-
-
-
-
.edu Links
-
- {seoData.notable_links.has_edu ? '✓ Found' : 'Not found'}
-
-
-
-
-
-
-
-
News Sites
-
- {seoData.notable_links.has_news ? '✓ Found' : 'Not found'}
-
-
-
-
-
- {/* Notable Domains List */}
- {seoData.notable_links.notable_domains.length > 0 && (
-
-
High-authority referring domains:
-
- {seoData.notable_links.notable_domains.map((d) => (
-
- {d}
-
- ))}
-
-
- )}
-
-
- {/* Top Backlinks */}
- {seoData.top_backlinks.length > 0 && (
-
-
Top Backlinks
-
- {seoData.top_backlinks.map((link, idx) => (
-
-
-
= 60 ? "bg-accent/10 text-accent" :
- link.authority >= 40 ? "bg-amber-500/10 text-amber-400" :
- "bg-foreground/5 text-foreground-muted"
- )}>
- {link.authority}
-
-
-
{link.domain}
- {link.page && (
-
{link.page}
- )}
-
-
-
-
-
-
- ))}
-
-
- )}
-
- {/* Data Source Note */}
- {seoData.is_estimated && (
-
-
-
- This data is estimated based on domain characteristics.
- For live Moz data, configure MOZ_ACCESS_ID and MOZ_SECRET_KEY in the backend.
-
-
- )}
-
- )}
-
- {/* Empty State */}
- {!seoData && !loading && !error && (
-
-
-
SEO Juice Detector
-
- Enter a domain above to analyze its backlink profile, domain authority,
- and find hidden SEO value that others miss.
-
-
- )}
-
-
- )
-}
-
diff --git a/frontend/src/app/terminal/welcome/page.tsx b/frontend/src/app/terminal/welcome/page.tsx
index d4f3752..07414af 100644
--- a/frontend/src/app/terminal/welcome/page.tsx
+++ b/frontend/src/app/terminal/welcome/page.tsx
@@ -35,8 +35,8 @@ const planDetails = {
],
nextSteps: [
{ href: '/terminal/watchlist', label: 'Add domains to watchlist', icon: Eye },
- { href: '/terminal/alerts', label: 'Set up Sniper Alerts', icon: Bell },
- { href: '/terminal/portfolio', label: 'Track your portfolio', icon: BarChart3 },
+ { href: '/terminal/market', label: 'Browse the market', icon: Store },
+ { href: '/terminal/intel', label: 'Check TLD pricing', icon: BarChart3 },
],
},
tycoon: {
@@ -53,8 +53,8 @@ const planDetails = {
],
nextSteps: [
{ href: '/terminal/watchlist', label: 'Add domains to watchlist', icon: Eye },
- { href: '/terminal/seo', label: 'Analyze SEO metrics', icon: Sparkles },
- { href: '/terminal/alerts', label: 'Create Sniper Alerts', icon: Bell },
+ { href: '/terminal/market', label: 'Browse the market', icon: Store },
+ { href: '/terminal/listing', label: 'List your domains', icon: Sparkles },
],
},
}
diff --git a/frontend/src/hooks/useKeyboardShortcuts.tsx b/frontend/src/hooks/useKeyboardShortcuts.tsx
index 7902f40..5fe5a65 100644
--- a/frontend/src/hooks/useKeyboardShortcuts.tsx
+++ b/frontend/src/hooks/useKeyboardShortcuts.tsx
@@ -241,8 +241,8 @@ export function useUserShortcuts() {
// Navigation
{ key: 'g', label: 'Go to Dashboard', description: 'Navigate to dashboard', action: () => router.push('/terminal/radar'), category: 'navigation' },
{ key: 'w', label: 'Go to Watchlist', description: 'Navigate to watchlist', action: () => router.push('/terminal/watchlist'), category: 'navigation' },
- { key: 'p', label: 'Go to Portfolio', description: 'Navigate to portfolio', action: () => router.push('/terminal/portfolio'), category: 'navigation' },
- { key: 'a', label: 'Go to Auctions', description: 'Navigate to auctions', action: () => router.push('/terminal/auctions'), category: 'navigation' },
+ { key: 'p', label: 'Go to Watchlist', description: 'Navigate to watchlist', action: () => router.push('/terminal/watchlist'), category: 'navigation' },
+ { key: 'a', label: 'Go to Market', description: 'Navigate to market', action: () => router.push('/terminal/market'), category: 'navigation' },
{ key: 't', label: 'Go to TLD Pricing', description: 'Navigate to TLD pricing', action: () => router.push('/terminal/intel'), category: 'navigation' },
{ key: 's', label: 'Go to Settings', description: 'Navigate to settings', action: () => router.push('/terminal/settings'), category: 'navigation' },
// Actions