diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 49361bd..d9782b5 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -42,7 +42,7 @@ interface HotAuction { platform: string } -// High-end Live Market Ticker - Monochrome & Technical +// High-end Live Market Ticker - Monochrome & Technical (Hidden on mobile for cleaner UX) function MarketTicker({ auctions }: { auctions: HotAuction[] }) { const tickerRef = useRef(null) @@ -52,9 +52,9 @@ function MarketTicker({ auctions }: { auctions: HotAuction[] }) { const items = [...auctions, ...auctions, ...auctions] return ( -
-
-
+
+
+
(
-
+
- + {auction.domain}
-
- ${auction.current_bid.toLocaleString()} - {auction.time_remaining} +
+ ${auction.current_bid.toLocaleString()} + {auction.time_remaining}
))} @@ -133,16 +133,16 @@ export default function HomePage() {
- {/* HERO SECTION: Brutally Catchy & Noble */} -
+ {/* HERO SECTION: Brutally Catchy & Noble - Mobile First */} +
-
+
{/* Left: Typography & Brand */}
- {/* Brand Seal */} -
-
+ {/* Brand Seal - Optimized for mobile */} +
+
-
- Est. 2025 // Global Operations +
+ Est. 2025
- {/* Headline */} -

+ {/* Headline - Mobile optimized typography */} +

The market never sleeps. - + You should.

{/* Subline & Stats */}
-

+

Transforming domains from static addresses into yield-bearing financial assets. - Scan. Acquire. Route. Profit. + Scan. Acquire. Route. Profit.

- {/* Stats Grid */} -
-
-
886+
-
TLDs Scanned
+ {/* Stats Grid - 2x2 on mobile, 4 cols on desktop */} +
+
+
886+
+
TLDs Scanned
-
-
24/7
-
Live Recon
+
+
24/7
+
Live Recon
-
-
10s
-
Latency
+
+
10s
+
Latency
-
-
$1B+
-
Assets Tracked
+
+
$1B+
+
Assets Tracked
- {/* Right: The Artifact (Domain Checker) */} -
+ {/* Right: The Artifact (Domain Checker) - Mobile optimized */} +
-
+
{/* Tech Corners */} -
-
-
-
+
+
+
+
-
+
-
- +
+ Terminal Access -
+
-
+
-
+
SECURE CONNECTION - V2.0.4 [STABLE] + V2.0.4 [STABLE] + V2.0.4
@@ -246,16 +247,16 @@ export default function HomePage() { )} - {/* THE PARADIGM SHIFT - Problem / Solution */} -
+ {/* THE PARADIGM SHIFT - Problem / Solution - Mobile optimized */} +
-
-
- The Broken Model -

- 99% of portfolios are
bleeding cash. +
+
+ The Broken Model +

+ 99% of portfolios are
bleeding cash.

-
+

Investors pay renewal fees for years, hoping for a "Unicorn" sale that never happens. It's gambling, not investing.

@@ -266,29 +267,29 @@ export default function HomePage() {
-
- The Pounce Protocol -

Asset Class V2.0

-
    -
  • - +
    + The Pounce Protocol +

    Asset Class V2.0

    +
      +
    • +
      Deep Recon - Zone file analysis reveals what's truly valuable. Don't guess. Know. + Zone file analysis reveals what's truly valuable. Don't guess. Know.
    • -
    • - +
    • +
      Frictionless Liquidity - Instant settlement. Verified owners. 0% Commission. + Instant settlement. Verified owners. 0% Commission.
    • -
    • - +
    • +
      Automated Yield - Domains pay for their own renewals via Intent Routingβ„’. + Domains pay for their own renewals via Intent Routingβ„’.
    @@ -298,57 +299,58 @@ export default function HomePage() {

- {/* CORE ARCHITECTURE - 3 Pillars */} -
+ {/* CORE ARCHITECTURE - 3 Pillars - Mobile optimized */} +
{/* Section Header */} -
-
- Core Architecture -

+
+
+ Core Architecture +

The Lifecycle
Engine.

-

+

// INTELLIGENCE_LAYER_ACTIVE
// MARKET_PROTOCOL_READY
// YIELD_GENERATION_STANDBY

-
+ {/* Mobile: Stacked cards with gaps. Desktop: Grid with borders */} +
{/* 1. INTELLIGENCE */} -
-
- +
+
+
-
+
Module 01
-

Intelligence

-

+

Intelligence

+

"Identify Targets." We scan 886+ TLDs in real-time to uncover hidden opportunities before the market reacts.

-
-
- +
+
+
-
Global Scan
-
Zone file analysis & expiration monitoring.
+
Global Scan
+
Zone file analysis & expiration monitoring.
-
- +
+
-
Valuation AI
-
Instant fair-market value estimation.
+
Valuation AI
+
Instant fair-market value estimation.
@@ -356,35 +358,35 @@ export default function HomePage() {
{/* 2. MARKET */} -
-
- +
+
+
-
+
Module 02
-

Market

-

+

Market

+

"Secure the Asset." Direct access to liquidity. A verified exchange where assets move instantly, securely, and with 0% commission fees.

-
-
- +
+
+
-
Verified Owners
-
Mandatory DNS verification. No fakes.
+
Verified Owners
+
Mandatory DNS verification. No fakes.
-
- +
+
-
Direct Execution
-
P2P transfers without middlemen.
+
Direct Execution
+
P2P transfers without middlemen.
@@ -392,35 +394,35 @@ export default function HomePage() {
{/* 3. YIELD */} -
-
- +
+
+
-
+
Module 03
-

Yield

-

+

Yield

+

"Deploy the Asset." Our "Intent Routing" engine transforms idle domains into active revenue generators via automated traffic monetization.

-
-
- +
+
+
-
Intent Routing
-
Traffic directed to high-value partners.
+
Intent Routing
+
Traffic directed to high-value partners.
-
- +
+
-
Passive Income
-
Monthly payouts from your portfolio.
+
Passive Income
+
Monthly payouts from your portfolio.
@@ -431,45 +433,47 @@ export default function HomePage() {

- {/* DEEP DIVE: YIELD */} -
+ {/* DEEP DIVE: YIELD - Mobile optimized */} +
-
- The Endgame -

Intent Routingβ„’

-

- We don't build websites. We build signposts.
- Our engine detects user intent (e.g. "kredit.ch" = Loan Search) and routes traffic directly to high-paying partners. +

+ The Endgame +

Intent Routingβ„’

+

+ We don't build websites. We build signposts. +
+ + Our engine detects user intent and routes traffic directly to high-paying partners.

-
+
{/* Step 1 */} -
-
- +
+
+
-

1. Connect

-

Point your nameservers to `ns.pounce.io`. The system takes over instantly.

+

1. Connect

+

Point your nameservers to `ns.pounce.io`. The system takes over instantly.

{/* Step 2 */} -
-
- +
+
+
-

2. Analyze

-

We scan the semantic intent. `zahnarzt-zh.ch` is identified as "Medical Booking Lead".

+

2. Analyze

+

We scan the semantic intent. `zahnarzt-zh.ch` is identified as "Medical Booking Lead".

{/* Step 3 */} -
-
- +
+
+
-

3. Route

-

Traffic is routed to vertical partners (e.g. Doctolib, Comparis). You earn per qualified lead.

+

3. Route

+

Traffic is routed to vertical partners. You earn per qualified lead.

diff --git a/frontend/src/app/terminal/settings/page.tsx b/frontend/src/app/terminal/settings/page.tsx index 72215a9..e3a4d49 100644 --- a/frontend/src/app/terminal/settings/page.tsx +++ b/frontend/src/app/terminal/settings/page.tsx @@ -2,7 +2,7 @@ import { useEffect, useState, useCallback } from 'react' import { useRouter } from 'next/navigation' -import { CommandCenterLayout } from '@/components/CommandCenterLayout' +import { Sidebar } from '@/components/Sidebar' import { useStore } from '@/lib/store' import { api, PriceAlert } from '@/lib/api' import { @@ -52,19 +52,12 @@ const PLANS = [ price: 0, period: 'forever', description: 'Perfect for getting started', - color: 'white', features: [ { icon: Target, text: '5 Watchlist Domains' }, { icon: Clock, text: 'Daily Checks' }, { icon: Bell, text: '2 Sniper Alerts' }, { icon: BarChart3, text: 'Basic Market Data' }, ], - limits: { - domains: 5, - alerts: 2, - listings: 0, - portfolio: 0, - } }, { id: 'trader', @@ -72,23 +65,16 @@ const PLANS = [ icon: TrendingUp, price: 9, period: '/month', - description: 'For serious domain investors', - color: 'accent', + description: 'For serious investors', badge: 'Popular', features: [ { icon: Target, text: '50 Watchlist Domains' }, { icon: Clock, text: 'Hourly Checks' }, { icon: Bell, text: '10 Sniper Alerts' }, { icon: Sparkles, text: 'Domain Valuation' }, - { icon: Database, text: '25 Portfolio Domains' }, - { icon: MessageSquare, text: '5 Marketplace Listings' }, + { icon: Database, text: '25 Portfolio' }, + { icon: MessageSquare, text: '5 Listings' }, ], - limits: { - domains: 50, - alerts: 10, - listings: 5, - portfolio: 25, - } }, { id: 'tycoon', @@ -96,23 +82,16 @@ const PLANS = [ icon: Crown, price: 29, period: '/month', - description: 'Maximum power & control', - color: 'amber', + description: 'Maximum power', badge: 'Full Power', features: [ - { icon: Target, text: '500 Watchlist Domains' }, - { icon: Clock, text: '10-Minute Checks' }, + { icon: Target, text: '500 Domains' }, + { icon: Clock, text: '10-Min Checks' }, { icon: Bell, text: '50 Sniper Alerts' }, - { icon: Sparkles, text: 'Full SEO Metrics' }, + { icon: Sparkles, text: 'Full SEO' }, { icon: Database, text: 'Unlimited Portfolio' }, - { icon: MessageSquare, text: '50 Featured Listings' }, + { icon: MessageSquare, text: '50 Featured' }, ], - limits: { - domains: 500, - alerts: 50, - listings: 50, - portfolio: -1, - } }, ] @@ -125,169 +104,110 @@ export default function SettingsPage() { const [success, setSuccess] = useState(null) const [error, setError] = useState(null) const [menuOpen, setMenuOpen] = useState(false) + const [changingPlan, setChangingPlan] = useState(null) - const [profileForm, setProfileForm] = useState({ - name: '', - email: '', - }) - + const [profileForm, setProfileForm] = useState({ name: '', email: '' }) const [notificationPrefs, setNotificationPrefs] = useState({ domain_availability: true, price_alerts: true, weekly_digest: false, }) const [savingNotifications, setSavingNotifications] = useState(false) - const [priceAlerts, setPriceAlerts] = useState([]) const [loadingAlerts, setLoadingAlerts] = useState(false) const [deletingAlertId, setDeletingAlertId] = useState(null) - const [changingPlan, setChangingPlan] = useState(null) + + useEffect(() => { checkAuth() }, [checkAuth]) useEffect(() => { - checkAuth() - }, [checkAuth]) - - useEffect(() => { - if (!isLoading && !isAuthenticated) { - router.push('/login') - } + if (!isLoading && !isAuthenticated) router.push('/login') }, [isLoading, isAuthenticated, router]) useEffect(() => { - if (user) { - setProfileForm({ - name: user.name || '', - email: user.email || '', - }) - } + if (user) setProfileForm({ name: user.name || '', email: user.email || '' }) }, [user]) useEffect(() => { - if (isAuthenticated && activeTab === 'notifications') { - loadPriceAlerts() - } + if (isAuthenticated && activeTab === 'notifications') loadPriceAlerts() }, [isAuthenticated, activeTab]) - const loadPriceAlerts = async () => { - setLoadingAlerts(true) - try { - const alerts = await api.getPriceAlerts() - setPriceAlerts(alerts) - } catch (err) { - console.error('Failed to load alerts:', err) - } finally { - setLoadingAlerts(false) - } - } - - const handleSaveProfile = async (e: React.FormEvent) => { - e.preventDefault() - setSaving(true) - setError(null) - setSuccess(null) - - try { - await api.updateMe({ name: profileForm.name || undefined }) - const { checkAuth } = useStore.getState() - await checkAuth() - setSuccess('Profile updated') - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to update profile') - } finally { - setSaving(false) - } - } - - const handleSaveNotifications = async () => { - setSavingNotifications(true) - setError(null) - setSuccess(null) - - try { - localStorage.setItem('notification_prefs', JSON.stringify(notificationPrefs)) - setSuccess('Preferences saved') - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to save preferences') - } finally { - setSavingNotifications(false) - } - } - useEffect(() => { const saved = localStorage.getItem('notification_prefs') - if (saved) { - try { - setNotificationPrefs(JSON.parse(saved)) - } catch {} - } + if (saved) try { setNotificationPrefs(JSON.parse(saved)) } catch {} }, []) - const handleDeletePriceAlert = async (tld: string, alertId: number) => { - setDeletingAlertId(alertId) - try { - await api.deletePriceAlert(tld) - setPriceAlerts(prev => prev.filter(a => a.id !== alertId)) - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to delete alert') - } finally { - setDeletingAlertId(null) - } - } - - const handleOpenBillingPortal = async () => { - try { - const { portal_url } = await api.createPortalSession() - window.location.href = portal_url - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to open billing portal') - } - } - - const handlePlanChange = async (planId: string) => { - setChangingPlan(planId) - setError(null) - - try { - if (planId === 'scout') { - // Downgrade to free - cancel subscription - await api.cancelSubscription() - setSuccess('Downgraded to Scout. Your premium features will remain active until the end of your billing period.') - await checkAuth() - } else { - // Upgrade to paid plan - const successUrl = `${window.location.origin}/terminal/settings?upgraded=${planId}` - const cancelUrl = `${window.location.origin}/terminal/settings?cancelled=true` - const { checkout_url } = await api.createCheckoutSession(planId, successUrl, cancelUrl) - window.location.href = checkout_url - } - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to change plan') - } finally { - setChangingPlan(null) - } - } - // Handle URL params for upgrade success/cancel useEffect(() => { const params = new URLSearchParams(window.location.search) const upgraded = params.get('upgraded') const cancelled = params.get('cancelled') - if (upgraded) { - setSuccess(`πŸŽ‰ Welcome to ${upgraded.charAt(0).toUpperCase() + upgraded.slice(1)}! Your account has been upgraded.`) + setSuccess(`πŸŽ‰ Welcome to ${upgraded.charAt(0).toUpperCase() + upgraded.slice(1)}!`) setActiveTab('billing') - // Clean URL window.history.replaceState({}, '', '/terminal/settings') - // Refresh subscription data checkAuth() } - if (cancelled) { - setError('Checkout was cancelled. No changes were made.') + setError('Checkout cancelled.') setActiveTab('billing') window.history.replaceState({}, '', '/terminal/settings') } - }, []) + }, [checkAuth]) + + const loadPriceAlerts = async () => { + setLoadingAlerts(true) + try { setPriceAlerts(await api.getPriceAlerts()) } catch {} + finally { setLoadingAlerts(false) } + } + + const handleSaveProfile = async (e: React.FormEvent) => { + e.preventDefault() + setSaving(true); setError(null); setSuccess(null) + try { + await api.updateMe({ name: profileForm.name || undefined }) + await checkAuth() + setSuccess('Profile updated') + } catch (err) { setError(err instanceof Error ? err.message : 'Failed') } + finally { setSaving(false) } + } + + const handleSaveNotifications = async () => { + setSavingNotifications(true); setError(null); setSuccess(null) + try { localStorage.setItem('notification_prefs', JSON.stringify(notificationPrefs)); setSuccess('Saved') } + catch (err) { setError('Failed') } + finally { setSavingNotifications(false) } + } + + const handleDeletePriceAlert = async (tld: string, alertId: number) => { + setDeletingAlertId(alertId) + try { await api.deletePriceAlert(tld); setPriceAlerts(prev => prev.filter(a => a.id !== alertId)) } + catch (err) { setError('Failed') } + finally { setDeletingAlertId(null) } + } + + const handleOpenBillingPortal = async () => { + try { const { portal_url } = await api.createPortalSession(); window.location.href = portal_url } + catch (err) { setError('Failed to open portal') } + } + + const handlePlanChange = async (planId: string) => { + setChangingPlan(planId); setError(null) + try { + if (planId === 'scout') { + await api.cancelSubscription() + setSuccess('Downgraded to Scout') + await checkAuth() + } else { + const { checkout_url } = await api.createCheckoutSession( + planId, + `${window.location.origin}/terminal/settings?upgraded=${planId}`, + `${window.location.origin}/terminal/settings?cancelled=true` + ) + window.location.href = checkout_url + } + } catch (err) { setError(err instanceof Error ? err.message : 'Failed') } + finally { setChangingPlan(null) } + } if (isLoading) { return ( @@ -297,21 +217,19 @@ export default function SettingsPage() { ) } - if (!isAuthenticated || !user) { - return null - } + if (!isAuthenticated || !user) return null const tierName = subscription?.tier_name || subscription?.tier || 'Scout' - const isProOrHigher = ['Trader', 'Tycoon', 'Professional', 'Enterprise'].includes(tierName) + const isProOrHigher = ['Trader', 'Tycoon'].includes(tierName) + const TierIcon = tierName === 'Tycoon' ? Crown : tierName === 'Trader' ? TrendingUp : Zap const tabs = [ { id: 'profile' as const, label: 'Profile', icon: User }, - { id: 'notifications' as const, label: 'Notifications', icon: Bell }, - { id: 'billing' as const, label: 'Billing', icon: CreditCard }, + { id: 'notifications' as const, label: 'Alerts', icon: Bell }, + { id: 'billing' as const, label: 'Plans', icon: CreditCard }, { id: 'security' as const, label: 'Security', icon: Shield }, ] - // Mobile Navigation const mobileNavItems = [ { href: '/terminal/radar', label: 'Radar', icon: Target, active: false }, { href: '/terminal/market', label: 'Market', icon: Gavel, active: false }, @@ -319,556 +237,354 @@ export default function SettingsPage() { { href: '/terminal/settings', label: 'Settings', icon: Settings, active: true }, ] - const TierIcon = tierName === 'Tycoon' ? Crown : tierName === 'Trader' ? TrendingUp : Zap - const drawerNavSections = [ - { - title: 'Discover', - items: [ - { href: '/terminal/radar', label: 'Radar', icon: Target }, - { href: '/terminal/market', label: 'Market', icon: Gavel }, - { href: '/terminal/intel', label: 'Intel', icon: TrendingUp }, - ] - }, - { - title: 'Manage', - items: [ - { href: '/terminal/watchlist', label: 'Watchlist', icon: Eye }, - { href: '/terminal/sniper', label: 'Sniper', icon: Bell }, - ] - }, - { - title: 'Monetize', - items: [ - { href: '/terminal/yield', label: 'Yield', icon: Coins }, - { href: '/terminal/listing', label: 'For Sale', icon: Tag }, - ] - }, + { title: 'Discover', items: [ + { href: '/terminal/radar', label: 'Radar', icon: Target }, + { href: '/terminal/market', label: 'Market', icon: Gavel }, + { href: '/terminal/intel', label: 'Intel', icon: TrendingUp }, + ]}, + { title: 'Manage', items: [ + { href: '/terminal/watchlist', label: 'Watchlist', icon: Eye }, + { href: '/terminal/sniper', label: 'Sniper', icon: Bell }, + ]}, + { title: 'Monetize', items: [ + { href: '/terminal/yield', label: 'Yield', icon: Coins }, + { href: '/terminal/listing', label: 'For Sale', icon: Tag }, + ]}, ] return ( - - {/* ═══════════════════════════════════════════════════════════════════════ */} - {/* HEADER */} - {/* ═══════════════════════════════════════════════════════════════════════ */} -
-
-
-
- - Account -
- -

- Settings -

-
- -
-
- {tierName === 'Tycoon' ? : - tierName === 'Trader' ? : - } - {tierName} -
-
-
-
- - {/* Messages */} - {error && ( -
- -

{error}

- -
- )} +
+ {/* Sidebar - Desktop only */} + - {success && ( -
- -

{success}

- -
- )} - - {/* ═══════════════════════════════════════════════════════════════════════ */} - {/* TABS + CONTENT */} - {/* ═══════════════════════════════════════════════════════════════════════ */} -
-
- {/* Tab Navigation */} -
- {/* Mobile: Horizontal */} - - - {/* Desktop: Vertical */} - - - {/* Plan Info - Desktop */} -
-
- {isProOrHigher ? : } - {tierName} +
+ + {/* ═══════════════════════════════════════════════════════════════════════ */} + {/* MOBILE HEADER */} + {/* ═══════════════════════════════════════════════════════════════════════ */} +
+
+ {/* Top Row */} +
+
+
+ Settings +
+
+ + {tierName} +
+
+ + {/* Stats Grid */} +
+
+
{subscription?.domains_used || 0}
+
Domains
+
+
+
+ {subscription?.check_frequency === 'realtime' ? '10m' : subscription?.check_frequency === 'hourly' ? '1h' : '24h'} +
+
Interval
+
+
+
{subscription?.status || 'active'}
+
Status
-

- {subscription?.domains_used || 0} / {subscription?.domain_limit || 5} domains -

- {!isProOrHigher && ( - - Upgrade - - - )}
+
- {/* Content */} -
- {/* Profile Tab */} - {activeTab === 'profile' && ( -
-

Profile Information

- -
-
- - setProfileForm({ ...profileForm, name: e.target.value })} - placeholder="Your name" - className="w-full px-4 py-3 bg-white/5 border border-white/10 text-white placeholder:text-white/25 outline-none focus:border-accent/50" - /> -
+ {/* ═══════════════════════════════════════════════════════════════════════ */} + {/* DESKTOP HEADER */} + {/* ═══════════════════════════════════════════════════════════════════════ */} +
+
+
+ Account +
+

Settings

+

Manage your account, plan, and preferences

+
-
- - -

Email cannot be changed

-
- - -
+ {/* Messages */} + {(error || success) && ( +
+ {error && ( +
+ +

{error}

+
)} + {success && ( +
+ +

{success}

+ +
+ )} +
+ )} - {/* Notifications Tab */} - {activeTab === 'notifications' && ( -
-
-

Email Preferences

- -
- {[ - { key: 'domain_availability', label: 'Domain Availability', desc: 'Get notified when watched domains become available' }, - { key: 'price_alerts', label: 'Price Alerts', desc: 'Get notified when TLD prices change' }, - { key: 'weekly_digest', label: 'Weekly Digest', desc: 'Receive a weekly summary of your portfolio' }, - ].map((item) => ( - - ))} -
+ {/* ═══════════════════════════════════════════════════════════════════════ */} + {/* TABS */} + {/* ═══════════════════════════════════════════════════════════════════════ */} +
+
+ {tabs.map((tab) => ( + + ))} +
+
+ {/* ═══════════════════════════════════════════════════════════════════════ */} + {/* CONTENT */} + {/* ═══════════════════════════════════════════════════════════════════════ */} +
+ + {/* Profile Tab */} + {activeTab === 'profile' && ( +
+
+ Profile Information +
+
+
+ + setProfileForm({ ...profileForm, name: e.target.value })} + className="w-full px-4 py-3 bg-white/[0.02] border border-white/[0.08] text-white placeholder:text-white/20 outline-none focus:border-accent/50" + /> +
+
+ + +
+ +
+
+ )} + + {/* Notifications Tab */} + {activeTab === 'notifications' && ( +
+
+
+ Email Preferences +
+
+ {[ + { key: 'domain_availability', label: 'Domain Available', desc: 'When domains become available' }, + { key: 'price_alerts', label: 'Price Changes', desc: 'TLD price updates' }, + { key: 'weekly_digest', label: 'Weekly Digest', desc: 'Weekly summary' }, + ].map((item) => ( + + ))}
- - {/* Active Price Alerts */} -
-

Active Price Alerts

- - {loadingAlerts ? ( -
- -
- ) : priceAlerts.length === 0 ? ( -
- -

No price alerts set

- - Browse TLD prices β†’ - -
- ) : ( -
- {priceAlerts.map((alert) => ( -
-
-
-
- - .{alert.tld} - -

- Alert on {alert.threshold_percent}% change - {alert.target_price && ` or below $${alert.target_price}`} -

-
-
- -
- ))} -
- )} -
- )} +
+ )} - {/* Billing Tab */} - {activeTab === 'billing' && ( -
- {/* Plan Switcher */} -
-
-

Choose Your Plan

- {isProOrHigher && ( - - )} -
+ {/* Billing Tab */} + {activeTab === 'billing' && ( +
+ {/* Plan Cards */} +
+ {PLANS.map((plan) => { + const isCurrent = tierName.toLowerCase() === plan.id + const isUpgrade = (tierName === 'Scout' && plan.id !== 'scout') || (tierName === 'Trader' && plan.id === 'tycoon') + const isDowngrade = (tierName === 'Tycoon' && plan.id !== 'tycoon') || (tierName === 'Trader' && plan.id === 'scout') - {/* Plan Cards */} -
- {PLANS.map((plan) => { - const isCurrent = tierName.toLowerCase() === plan.id - const isUpgrade = - (tierName === 'Scout' && (plan.id === 'trader' || plan.id === 'tycoon')) || - (tierName === 'Trader' && plan.id === 'tycoon') - const isDowngrade = - (tierName === 'Tycoon' && (plan.id === 'trader' || plan.id === 'scout')) || - (tierName === 'Trader' && plan.id === 'scout') + return ( +
+ {plan.badge && ( +
{plan.badge}
+ )} + {isCurrent && ( +
Current
+ )} - return ( -
- {/* Badge */} - {plan.badge && ( -
- {plan.badge} -
- )} - - {/* Current Badge */} - {isCurrent && ( -
- Current -
- )} - - {/* Header */} -
-
- -
-
-

{plan.name}

-

{plan.description}

-
-
- - {/* Price */} -
- {plan.price === 0 ? ( - Free - ) : ( - <> - ${plan.price} - {plan.period} - - )} -
- - {/* Features */} -
    - {plan.features.map((feature, idx) => ( -
  • - - {feature.text} -
  • - ))} -
- - {/* Action Button */} - {isCurrent ? ( -
- - Active Plan -
- ) : isUpgrade ? ( - - ) : isDowngrade ? ( - - ) : null} +
+ + {plan.name} +
+ +
+ {plan.price === 0 ? ( + Free + ) : ( + <> + ${plan.price} + {plan.period} + + )} +
+ +
    + {plan.features.slice(0, 4).map((f, i) => ( +
  • + + {f.text} +
  • + ))} +
+ + {isCurrent ? ( +
+ Active
- ) - })} -
-
- - {/* Usage Stats */} -
-

Current Usage

- -
-
-
- Watchlist - -
-

- {subscription?.domains_used || 0} - /{subscription?.domain_limit || 5} -

-
-
-
+ ) : isUpgrade ? ( + + ) : isDowngrade ? ( + + ) : null}
- -
-
- Check Speed - -
-

- {subscription?.check_frequency === 'realtime' ? '10m' : - subscription?.check_frequency === 'hourly' ? '1h' : '24h'} -

-

Interval

-
- -
-
- Portfolio - -
-

- {subscription?.portfolio_limit === -1 ? '∞' : subscription?.portfolio_limit || 0} -

-

Slots

-
- -
-
- Status - -
-

- {subscription?.status || 'active'} -

-

Subscription

-
-
-
- - {/* Help Text */} -
-

- Need help? Contact support -

-
+ ) + })}
- )} + + {/* Billing Portal Link */} + {isProOrHigher && ( + + )} +
+ )} - {/* Security Tab */} - {activeTab === 'security' && ( -
-
-

Password

-

- Change your password or reset it if you've forgotten it. -

+ {/* Security Tab */} + {activeTab === 'security' && ( +
+
+
+ Password +
+
+

Change or reset your password

Change Password
- -
-

Account Security

- -
-
-
-

Email Verified

-

Your email has been verified

-
-
- -
+
+ +
+
+ Account Status +
+
+
+
+

Email Verified

+

Your email is verified

- -
-
-

Two-Factor Authentication

-

Coming soon

-
- Soon + +
+
+
+

2FA

+

Coming soon

+ Soon
- -
-

Danger Zone

-

- Permanently delete your account and all associated data. -

- -
- )} -
-
-
- - {/* Mobile Bottom Padding */} -
+ +
+

Danger Zone

+

Permanently delete your account

+ +
+
+ )} +
+ {/* ═══════════════════════════════════════════════════════════════════════ */} - {/* MOBILE BOTTOM NAVIGATION */} + {/* MOBILE BOTTOM NAV */} {/* ═══════════════════════════════════════════════════════════════════════ */}