diff --git a/frontend/src/app/about/page.tsx b/frontend/src/app/about/page.tsx index 3389c6b..c2222f7 100644 --- a/frontend/src/app/about/page.tsx +++ b/frontend/src/app/about/page.tsx @@ -2,187 +2,158 @@ import { Header } from '@/components/Header' import { Footer } from '@/components/Footer' -import { Target, Shield, Zap, Users, Globe, TrendingUp, ArrowRight } from 'lucide-react' +import { Target, Shield, Zap, Users, Globe, ArrowRight } from 'lucide-react' import Link from 'next/link' -const values = [ - { - icon: Target, - title: 'Precision', - description: 'Accurate data. No guesswork. Every check counts.', - }, - { - icon: Shield, - title: 'Privacy', - description: 'Your strategy stays yours. We never share or sell data.', - }, - { - icon: Zap, - title: 'Speed', - description: 'Real-time intel. You see it first.', - }, - { - icon: Users, - title: 'Transparency', - description: 'Clear pricing. No surprises. Ever.', - }, -] - const stats = [ - { value: '500K+', label: 'Domains Tracked' }, - { value: '99.9%', label: 'Uptime' }, - { value: '50ms', label: 'Response Time' }, - { value: '24/7', label: 'Always On' }, -] - -const team = [ - { - name: 'Domain Intel', - role: 'Core', - description: 'WHOIS + RDAP queries. Accurate. Reliable. Always.', - }, - { - name: 'Price Tracking', - role: 'Market', - description: 'Real-time TLD pricing. Know what domains cost.', - }, - { - name: 'Instant Alerts', - role: 'Notify', - description: 'Domain drops? You know first. Email or webhook.', - }, + { value: '500K+', label: 'ASSETS TRACKED' }, + { value: '99.9%', label: 'SYSTEM UPTIME' }, + { value: '50ms', label: 'SCAN LATENCY' }, + { value: '24/7', label: 'LIVE MONITOR' }, ] export default function AboutPage() { return ( -
- {/* Ambient glow */} -
-
+
+ {/* Background Atmosphere */} +
+
+
+
-
-
+
+
{/* Hero */} -
-
- - About pounce -
-

+
+ +
+ Mission Briefing + +

Built for hunters.
- By hunters. + By hunters.

-

+

POUNCE exists for one reason: to give you the edge. - Track domains. See opportunities. Move first. + Track assets. See opportunities. Move first.

- {/* Stats */} -
+ {/* Stats Grid - Bento Style */} +
{stats.map((stat) => (
-

+

{stat.value} -

-

{stat.label}

+
+
{stat.label}
))}
{/* Mission */} -
-
-

- The Mission -

-

- Level the playing field. Domain intel shouldn't be locked behind enterprise - paywalls. With POUNCE, anyone can track domains, spot trends, and strike - when the iron's hot. Simple tools. Powerful results. -

-
-
+
+
+ The Objective +

Level the playing field.

+
+

+ Domain intelligence shouldn't be locked behind enterprise paywalls or hidden in archaic CLI tools. +

+

+ We built POUNCE to democratize access to high-value digital assets. Whether you're a sniper looking for a single drop or a whale managing a portfolio, our tools give you the same firepower. +

+
+
+
+
+
+
+ +
+

Global Coverage

+
    +
  • + Registrars + 50+ Connected +
  • +
  • + TLDs + 886 Supported +
  • +
  • + Refresh Rate + Real-time +
  • +
  • + Data Source + WHOIS / RDAP / DNS +
  • +
+
+
+
{/* Values */} -
-

- Our Code -

-
- {values.map((value, i) => ( +
+

Operational Code

+
+ {[ + { icon: Target, title: 'Precision', desc: 'Accurate data. No guesswork. Every check counts.' }, + { icon: Shield, title: 'Privacy', desc: 'Your strategy stays yours. We never share or sell data.' }, + { icon: Zap, title: 'Speed', desc: 'Real-time intel. You see it first.' }, + { icon: Users, title: 'Transparency', desc: 'Clear pricing. No surprises. Ever.' }, + ].map((value, i) => (
-
- -
-

{value.title}

-

{value.description}

+ +

{value.title}

+

{value.desc}

))}
-
- - {/* Features */} -
-

- What We Do -

-
- {team.map((item, i) => ( -
-
-
-

{item.name}

- - {item.role} - -
-

{item.description}

-
-
- ))} -
-
+
{/* CTA */} -
-

- Ready to hunt? -

-

- Join the hunters who move first. -

-
- - Start Hunting - - - - Get in Touch - +
+
+
+

Ready to deploy?

+

+ Join the elite circle of investors who stop guessing and start knowing. +

+
+ + Start Hunting + + + Contact HQ + +
-
+

@@ -190,4 +161,3 @@ export default function AboutPage() {
) } - diff --git a/frontend/src/app/market/metadata.ts b/frontend/src/app/acquire/metadata.ts similarity index 100% rename from frontend/src/app/market/metadata.ts rename to frontend/src/app/acquire/metadata.ts diff --git a/frontend/src/app/acquire/page.tsx b/frontend/src/app/acquire/page.tsx new file mode 100644 index 0000000..1774d9d --- /dev/null +++ b/frontend/src/app/acquire/page.tsx @@ -0,0 +1,652 @@ +'use client' + +import { useEffect, useState, useMemo } from 'react' +import { useStore } from '@/lib/store' +import { api } from '@/lib/api' +import { Header } from '@/components/Header' +import { Footer } from '@/components/Footer' +import { PlatformBadge } from '@/components/PremiumTable' +import { + Clock, + ExternalLink, + Search, + Flame, + Timer, + Gavel, + DollarSign, + X, + Lock, + TrendingUp, + ChevronUp, + ChevronDown, + ChevronsUpDown, + Sparkles, + Diamond, + ShieldCheck, + Zap, + Filter, + Check, + Shield, + ArrowUpRight, + ArrowRight +} from 'lucide-react' +import Link from 'next/link' +import clsx from 'clsx' + +interface MarketItem { + id: string + domain: string + tld: string + price: number + currency: string + price_type: 'bid' | 'fixed' | 'negotiable' + status: 'auction' | 'instant' + source: string + is_pounce: boolean + verified: boolean + time_remaining?: string + end_time?: string + num_bids?: number + slug?: string + seller_verified: boolean + url: string + is_external: boolean + pounce_score: number +} + +interface Auction { + domain: string + platform: string + platform_url: string + current_bid: number + currency: string + num_bids: number + end_time: string + time_remaining: string + buy_now_price: number | null + reserve_met: boolean | null + traffic: number | null + age_years: number | null + tld: string + affiliate_url: string +} + +type TabType = 'all' | 'ending' | 'hot' +type SortField = 'domain' | 'ending' | 'bid' | 'bids' +type SortDirection = 'asc' | 'desc' + +const PLATFORMS = [ + { id: 'All', name: 'All Sources' }, + { id: 'GoDaddy', name: 'GoDaddy' }, + { id: 'Sedo', name: 'Sedo' }, + { id: 'NameJet', name: 'NameJet' }, + { id: 'DropCatch', name: 'DropCatch' }, +] + +// Premium TLDs that look professional +const PREMIUM_TLDS = ['com', 'io', 'ai', 'co', 'de', 'ch', 'net', 'org', 'app', 'dev', 'xyz'] + +// Vanity Filter: Only show "beautiful" domains to non-authenticated users +function isVanityDomain(auction: Auction): boolean { + const domain = auction.domain + const parts = domain.split('.') + if (parts.length < 2) return false + + const name = parts[0] + const tld = parts.slice(1).join('.').toLowerCase() + + // Check TLD is premium + if (!PREMIUM_TLDS.includes(tld)) return false + + // Check length (max 12 characters for the name) + if (name.length > 12) return false + + // No hyphens + if (name.includes('-')) return false + + // No numbers (unless domain is 4 chars or less - short domains are valuable) + if (name.length > 4 && /\d/.test(name)) return false + + return true +} + +// Generate a mock "Deal Score" for display purposes +function getDealScore(auction: Auction): number | null { + let score = 50 + + const name = auction.domain.split('.')[0] + if (name.length <= 4) score += 20 + else if (name.length <= 6) score += 10 + + if (['com', 'io', 'ai'].includes(auction.tld)) score += 15 + + if (auction.age_years && auction.age_years > 5) score += 10 + + if (auction.num_bids >= 20) score += 15 + else if (auction.num_bids >= 10) score += 10 + + return Math.min(score, 100) +} + +function SortIcon({ field, currentField, direction }: { field: SortField, currentField: SortField, direction: SortDirection }) { + if (field !== currentField) { + return + } + return direction === 'asc' + ? + : +} + +export default function MarketPage() { + const { isAuthenticated, checkAuth, isLoading: authLoading } = useStore() + + const [allAuctions, setAllAuctions] = useState([]) + const [endingSoon, setEndingSoon] = useState([]) + const [hotAuctions, setHotAuctions] = useState([]) + const [pounceItems, setPounceItems] = useState([]) + const [loading, setLoading] = useState(true) + const [activeTab, setActiveTab] = useState('all') + const [sortField, setSortField] = useState('ending') + const [sortDirection, setSortDirection] = useState('asc') + + const [searchQuery, setSearchQuery] = useState('') + const [selectedPlatform, setSelectedPlatform] = useState('All') + const [maxBid, setMaxBid] = useState('') + + useEffect(() => { + checkAuth() + loadAuctions() + }, [checkAuth]) + + const loadAuctions = async () => { + setLoading(true) + try { + const [allFeed, endingFeed, hotFeed, pounceFeed] = await Promise.all([ + api.getMarketFeed({ source: 'all', limit: 100, sortBy: 'time' }), + api.getMarketFeed({ source: 'external', endingWithin: 24, limit: 50, sortBy: 'time' }), + api.getMarketFeed({ source: 'external', limit: 50, sortBy: 'score' }), + api.getMarketFeed({ source: 'pounce', limit: 10 }), + ]) + + const convertToAuction = (item: MarketItem): Auction => ({ + domain: item.domain, + platform: item.source, + platform_url: item.url, + current_bid: item.price, + currency: item.currency, + num_bids: item.num_bids || 0, + end_time: item.end_time || '', + time_remaining: item.time_remaining || '', + buy_now_price: item.price_type === 'fixed' ? item.price : null, + reserve_met: null, + traffic: null, + age_years: null, + tld: item.tld, + affiliate_url: item.url, + }) + + const externalOnly = (items: MarketItem[]) => items.filter(i => !i.is_pounce).map(convertToAuction) + + setAllAuctions(externalOnly(allFeed.items || [])) + setEndingSoon(externalOnly(endingFeed.items || [])) + setHotAuctions(externalOnly(hotFeed.items || [])) + setPounceItems(pounceFeed.items || []) + } catch (error) { + console.error('Failed to load auctions:', error) + } finally { + setLoading(false) + } + } + + const getCurrentAuctions = (): Auction[] => { + switch (activeTab) { + case 'ending': return endingSoon + case 'hot': return hotAuctions + default: return allAuctions + } + } + + // Apply Vanity Filter for non-authenticated users + const displayAuctions = useMemo(() => { + const current = getCurrentAuctions() + if (isAuthenticated) { + return current + } + return current.filter(isVanityDomain) + }, [activeTab, allAuctions, endingSoon, hotAuctions, isAuthenticated]) + + const filteredAuctions = displayAuctions.filter(auction => { + if (searchQuery && !auction.domain.toLowerCase().includes(searchQuery.toLowerCase())) { + return false + } + if (selectedPlatform !== 'All' && auction.platform !== selectedPlatform) { + return false + } + if (maxBid && auction.current_bid > parseFloat(maxBid)) { + return false + } + return true + }) + + const handleSort = (field: SortField) => { + if (sortField === field) { + setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc') + } else { + setSortField(field) + setSortDirection('asc') + } + } + + const sortedAuctions = [...filteredAuctions].sort((a, b) => { + const modifier = sortDirection === 'asc' ? 1 : -1 + switch (sortField) { + case 'domain': + return a.domain.localeCompare(b.domain) * modifier + case 'bid': + return (a.current_bid - b.current_bid) * modifier + case 'bids': + return (a.num_bids - b.num_bids) * modifier + default: + return 0 + } + }) + + const formatCurrency = (amount: number, currency = 'USD') => { + return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount) + } + + const getTimeColor = (timeRemaining: string) => { + if (timeRemaining.includes('m') && !timeRemaining.includes('h')) return 'text-red-400 font-bold' + if (timeRemaining.includes('h') && parseInt(timeRemaining) < 12) return 'text-amber-400 font-bold' + return 'text-white/40' + } + + const hotPreview = hotAuctions.slice(0, 4) + + if (authLoading) { + return ( +
+
+
+ ) + } + + return ( +
+ {/* Cinematic Background - Architectural & Fine */} +
+
+
+
+
+ +
+ +
+
+ {/* Hero Header - High Tech */} +
+
+
+ +
+ Live Liquidity Pool + +

+ Acquire Assets. +

+

+ Global liquidity pool. Verified assets only. + Aggregated from GoDaddy, Sedo, and Pounce Direct. +

+
+
+
+
{formatCurrency(allAuctions.length, 'USD').replace('$', '')}
+
Live Opportunities
+
+
+
{pounceItems.length}
+
Direct Listings
+
+
+
+
+ + {/* Login Banner for non-authenticated users */} + {!isAuthenticated && ( +
+
+
+
+
+ +
+
+
+ +
+
+

Restricted Access

+

+ Sign in to unlock valuations, deal scores, and unfiltered data. +

+
+
+ + Authorize + +
+
+ )} + + {/* Pounce Direct Section - Featured */} + {pounceItems.length > 0 && ( +
+
+
+
+ + Direct Listings +
+ // 0% COMMISSION // INSTANT SETTLEMENT +
+ + How to list my domains? + +
+ +
+ {pounceItems.map((item) => ( + +
+ +
+ +
+
+ + Available Now +
+ +

+ {item.domain} +

+ +
+ {item.verified && ( + + Verified + + )} + + {isAuthenticated ? `Score: ${item.pounce_score}/100` : 'Score: [LOCKED]'} + +
+ +
+
+ Buy Price + {formatCurrency(item.price, item.currency)} +
+
+ Acquire +
+
+
+ + ))} +
+
+ )} + + {/* Search & Filters - Tech Bar */} +
+
+ {/* Search */} +
+ + setSearchQuery(e.target.value)} + className="w-full pl-14 pr-5 py-3.5 bg-[#0A0A0A] border border-white/10 text-white placeholder:text-white/20 font-mono text-base focus:outline-none focus:border-accent focus:bg-[#0F0F0F] transition-all rounded-none" + /> +
+ + {/* Filters */} +
+
+ + +
+ +
+ {[ + { id: 'all' as const, label: 'ALL', icon: Gavel }, + { id: 'ending' as const, label: 'ENDING', icon: Timer }, + { id: 'hot' as const, label: 'HOT', icon: Flame }, + ].map((tab) => ( + + ))} +
+
+
+
+ + {/* Auctions Table - The Terminal */} +
+
+ + + + + + + + + + + + + {loading ? ( + Array.from({ length: 10 }).map((_, idx) => ( + + + + + + + + + )) + ) : sortedAuctions.length === 0 ? ( + + + + ) : ( + sortedAuctions.map((auction) => ( + + + + + {/* Valuation - blurred for non-authenticated */} + + + + + )) + )} + +
+ + + Source + + + + + Valuation + {!isAuthenticated && } + + + +
+ {searchQuery ? `// NO_ASSETS_FOUND: "${searchQuery}"` : '// NO_DATA_AVAILABLE'} +
+
+ + {auction.domain} + +
+ {auction.platform} +
+
+
+
+ {auction.platform} + {auction.platform === 'Pounce' && } +
+
+
+ + {formatCurrency(auction.current_bid)} + + {auction.buy_now_price && ( + Buy Now + )} +
+
+ {isAuthenticated ? ( + + ${(auction.current_bid * 1.5).toFixed(0)} + + ) : ( +
+ + $X,XXX + +
+ )} +
+ + {auction.time_remaining} + + + + + +
+
+
+ + {/* Stats */} + {!loading && ( +
+ System Status: Online + + {searchQuery + ? `Assets Found: ${sortedAuctions.length}` + : `Total Assets: ${allAuctions.length}` + } + +
+ )} + + {/* Bottom CTA */} + {!isAuthenticated && ( +
+
+
+
+
+ +
+

Eliminate Noise.

+

+ Our 'Trader' plan filters 99% of junk domains automatically. + Stop digging through spam. Start acquiring assets. +

+ + Upgrade Intel + + +
+
+
+ )} +
+
+ +
+
+ ) +} diff --git a/frontend/src/app/briefings/page.tsx b/frontend/src/app/briefings/page.tsx new file mode 100644 index 0000000..fcfe6a4 --- /dev/null +++ b/frontend/src/app/briefings/page.tsx @@ -0,0 +1,117 @@ +'use client' + +import { Header } from '@/components/Header' +import { Footer } from '@/components/Footer' +import Link from 'next/link' +import { ArrowRight, Calendar, Tag } from 'lucide-react' + +// Mock Data for Briefings +const briefings = [ + { + id: 1, + title: 'The .AI Gold Rush: Analysis of 2024 Market Trends', + excerpt: 'Deep dive into the explosion of AI domain valuations. Why 2-letter .ai domains are outperforming crypto, and what to watch next.', + date: 'OCT 12, 2024', + category: 'MARKET_INTEL', + slug: 'ai-gold-rush-analysis' + }, + { + id: 2, + title: 'Arbitrage Opportunities in Expiring .IO Domains', + excerpt: 'With the Indian Ocean territory geopolitical shift, uncertainty creates opportunity. Here is our strategy for .io acquisitions.', + date: 'SEP 28, 2024', + category: 'STRATEGY', + slug: 'io-domain-arbitrage' + }, + { + id: 3, + title: 'SEO Impact of Exact Match Domains in 2025', + excerpt: 'Google says EMDs dont matter. The data says otherwise. We analyzed 50,000 SERPs to find the truth.', + date: 'SEP 15, 2024', + category: 'SEO_DATA', + slug: 'seo-emd-analysis-2025' + }, + { + id: 4, + title: 'The Rise of "Micro-SaaS" Domain Flipping', + excerpt: 'Buying domains not for the name, but for the starter-project attached to it. A new asset class emerges.', + date: 'AUG 30, 2024', + category: 'TRENDS', + slug: 'micro-saas-flipping' + } +] + +export default function BriefingsPage() { + return ( +
+ {/* Background Atmosphere */} +
+
+
+
+ +
+ +
+
+ {/* Hero */} +
+ +
+ Intelligence Feed + +

+ Mission Briefings. +

+

+ Tactical analysis, market trends, and operational updates from the Pounce HQ. +

+
+ + {/* Briefings Grid */} +
+ {briefings.map((briefing, i) => ( + +
+ + + {briefing.category} + + + + {briefing.date} + +
+ +

+ {briefing.title} +

+

+ {briefing.excerpt} +

+ +
+ Read Analysis +
+ + ))} +
+ +
+

+ // End of Feed +

+
+ +
+
+
+
+ ) +} + diff --git a/frontend/src/app/contact/page.tsx b/frontend/src/app/contact/page.tsx index 314104d..cacad4c 100644 --- a/frontend/src/app/contact/page.tsx +++ b/frontend/src/app/contact/page.tsx @@ -4,45 +4,45 @@ import { useState } from 'react' import { Header } from '@/components/Header' import { Footer } from '@/components/Footer' import { api } from '@/lib/api' -import { Mail, MessageSquare, Clock, Send, Loader2, CheckCircle, MapPin, Building, AlertCircle } from 'lucide-react' +import { Mail, MessageSquare, Clock, Send, Loader2, CheckCircle, MapPin, Building, AlertCircle, ArrowRight } from 'lucide-react' import Link from 'next/link' const contactMethods = [ { icon: Mail, - title: 'Email', - description: 'Questions? Ideas? Issues?', + title: 'Secure Comms', + description: 'Encrypted channel for general inquiries.', value: 'hello@pounce.ch', href: 'mailto:hello@pounce.ch', }, { icon: MessageSquare, - title: 'Live Chat', - description: 'Mon-Fri, 9am-6pm CET', - value: 'Start a conversation', + title: 'Live Support', + description: 'Mon-Fri, 0900-1800 CET', + value: 'Open Channel', href: '#', }, { icon: Clock, title: 'Response Time', - description: 'We reply fast.', - value: '< 24 hours', + description: 'Average ticket resolution.', + value: '< 4 Hours', href: null, }, ] const faqs = [ { - q: 'Forgot my password?', - a: 'Hit "Forgot Password" on login. Check your email. Done.', + q: 'Forgot credentials?', + a: 'Use the "Forgot Password" protocol on the login screen. Reset link dispatched instantly.', }, { - q: 'Can I upgrade mid-cycle?', - a: 'Yes. Pay the difference. New features unlock instantly.', + q: 'Upgrade mid-cycle?', + a: 'Affirmative. Pro-rated charges apply. Features unlock immediately upon transaction.', }, { - q: 'Refunds?', - a: '14-day money-back. No questions. No hassle.', + q: 'Refund policy?', + a: '14-day money-back guarantee. No questions asked. Risk-free deployment.', }, ] @@ -77,145 +77,160 @@ export default function ContactPage() { }, 5000) } catch (err: any) { setFormState('error') - setError(err.message || 'Failed to send message. Please try again.') + setError(err.message || 'Transmission failed. Retry.') } } return ( -
- {/* Ambient glow */} -
-
+
+ {/* Background Atmosphere */} +
+
+
+
-
-
+
+
{/* Hero */} -
-
- - Get in Touch -
-

- Let's Talk +
+ +
+ Communication Uplink + +

+ Establish Contact.

-

- Question? Idea? Problem? We're listening. +

+ Question? Idea? Glitch in the matrix? We're listening.

{/* Contact Methods */} -
+
{contactMethods.map((method) => (
-
- +
+
-

{method.title}

-

{method.description}

+

{method.title}

+

{method.description}

{method.href ? ( - {method.value} + {method.value} ) : ( - {method.value} + {method.value} )}
))}
-
- {/* Contact Form */} -
-

Send us a message

+
+ {/* Contact Form - Tech Style */} +
+ {/* Tech Corners */} +
+
+
+
+ +

Transmission Form

{formState === 'success' ? ( -
-
- +
+
+
-

Message Sent!

-

- We've sent you a confirmation email. We'll get back to you within 24 hours. +

Message Received

+

+ Your transmission has been logged. Our operators will respond within 4 hours.

) : ( -
+ {formState === 'error' && error && ( -
- -

{error}

+
+ +

{error}

)} -
-
- +
+
+ setFormData({ ...formData, name: e.target.value })} required - className="w-full px-4 py-3 bg-background-secondary border border-border rounded-xl text-body text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-2 focus:ring-accent/30 focus:border-accent transition-all" - placeholder="Your name" + className="w-full bg-[#0A0A0A] border border-white/10 px-4 py-3 text-white font-mono text-sm placeholder:text-white/20 focus:outline-none focus:border-accent transition-all rounded-none" + placeholder="AGENT SMITH" />
-
- +
+ setFormData({ ...formData, email: e.target.value })} required - className="w-full px-4 py-3 bg-background-secondary border border-border rounded-xl text-body text-foreground placeholder:text-foreground-subtle focus:outline-none focus:ring-2 focus:ring-accent/30 focus:border-accent transition-all" - placeholder="you@example.com" + className="w-full bg-[#0A0A0A] border border-white/10 px-4 py-3 text-white font-mono text-sm placeholder:text-white/20 focus:outline-none focus:border-accent transition-all rounded-none" + placeholder="NAME@DOMAIN.COM" />
-
- +
+
-
- +
+