Some checks failed
CI / Frontend Lint & Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Backend Lint (push) Has been cancelled
CI / Backend Tests (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
Deploy / Build & Push Images (push) Has been cancelled
Deploy / Deploy to Server (push) Has been cancelled
Deploy / Notify (push) Has been cancelled
205 lines
10 KiB
TypeScript
205 lines
10 KiB
TypeScript
'use client'
|
|
|
|
import Link from 'next/link'
|
|
import Image from 'next/image'
|
|
import { Twitter, Mail, Linkedin, ArrowRight } from 'lucide-react'
|
|
import { useStore } from '@/lib/store'
|
|
import { api } from '@/lib/api'
|
|
import { useCallback, useMemo, useState } from 'react'
|
|
|
|
export function Footer() {
|
|
const { isAuthenticated } = useStore()
|
|
const [newsletterEmail, setNewsletterEmail] = useState('')
|
|
const [newsletterState, setNewsletterState] = useState<'idle' | 'loading' | 'success' | 'error'>('idle')
|
|
const [newsletterError, setNewsletterError] = useState<string | null>(null)
|
|
|
|
const canSubmitNewsletter = useMemo(() => {
|
|
const email = newsletterEmail.trim()
|
|
return email.length > 3 && email.includes('@') && email.includes('.')
|
|
}, [newsletterEmail])
|
|
|
|
const handleNewsletterSubmit = useCallback(async (e: React.FormEvent) => {
|
|
e.preventDefault()
|
|
if (!canSubmitNewsletter || newsletterState === 'loading') return
|
|
|
|
setNewsletterState('loading')
|
|
setNewsletterError(null)
|
|
try {
|
|
await api.subscribeNewsletter(newsletterEmail.trim())
|
|
setNewsletterState('success')
|
|
} catch (err: any) {
|
|
setNewsletterState('error')
|
|
setNewsletterError(err?.message || 'Subscription failed. Retry.')
|
|
}
|
|
}, [canSubmitNewsletter, newsletterEmail, newsletterState])
|
|
|
|
return (
|
|
<footer className="relative border-t border-white/10 bg-[#020202] mt-auto overflow-hidden">
|
|
<div className="absolute inset-0 bg-[url('/noise.png')] opacity-[0.03] mix-blend-overlay pointer-events-none" />
|
|
|
|
<div className="max-w-[1400px] mx-auto px-4 sm:px-6 py-12 sm:py-20 relative z-10">
|
|
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 lg:gap-8 mb-10 sm:mb-16">
|
|
|
|
{/* Brand Column */}
|
|
<div className="col-span-2 md:col-span-2 lg:col-span-2">
|
|
<div className="mb-4 sm:mb-6">
|
|
<Link href="/" className="inline-block group">
|
|
<div className="flex items-center gap-2 sm:gap-3">
|
|
<Image
|
|
src="/pounce-puma.png"
|
|
alt="POUNCE"
|
|
width={32}
|
|
height={32}
|
|
className="object-contain opacity-80 group-hover:opacity-100 transition-opacity sm:w-10 sm:h-10"
|
|
/>
|
|
<span className="text-lg sm:text-xl font-black tracking-[0.1em] text-white group-hover:text-accent transition-colors font-display">
|
|
POUNCE
|
|
</span>
|
|
</div>
|
|
</Link>
|
|
</div>
|
|
<p className="text-xs sm:text-sm font-mono text-white/50 mb-6 sm:mb-8 max-w-sm leading-relaxed">
|
|
Global domain intelligence for serious investors. Scan. Acquire. Route. Yield.
|
|
</p>
|
|
|
|
{/* Newsletter - Hidden on Mobile */}
|
|
<div className="hidden sm:block mb-8 max-w-sm">
|
|
<label className="text-[10px] font-mono uppercase tracking-widest text-white/30 mb-2 block">Mission Briefings</label>
|
|
<form onSubmit={handleNewsletterSubmit} className="flex">
|
|
<input
|
|
type="email"
|
|
value={newsletterEmail}
|
|
onChange={(e) => setNewsletterEmail(e.target.value)}
|
|
placeholder="Email address"
|
|
className="w-full bg-[#0A0A0A] border border-white/10 px-4 py-3 text-white font-mono text-xs placeholder:text-white/20 focus:outline-none focus:border-accent transition-all"
|
|
/>
|
|
<button
|
|
type="submit"
|
|
disabled={!canSubmitNewsletter || newsletterState === 'loading'}
|
|
className="px-4 bg-white text-black hover:bg-accent transition-colors border-l border-white/10 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
aria-label="Subscribe to briefings"
|
|
title="Subscribe"
|
|
>
|
|
<ArrowRight className="w-4 h-4" />
|
|
</button>
|
|
</form>
|
|
{newsletterState === 'success' ? (
|
|
<p className="mt-2 text-[10px] font-mono text-accent/80">Subscribed. Briefings inbound.</p>
|
|
) : newsletterState === 'error' ? (
|
|
<p className="mt-2 text-[10px] font-mono text-rose-300/80">{newsletterError}</p>
|
|
) : (
|
|
<p className="mt-2 text-[10px] font-mono text-white/20">Weekly intel. No spam.</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex items-center gap-3 sm:gap-4">
|
|
<a
|
|
href="https://twitter.com/pounce_domains"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center border border-white/5 hover:border-white/20 hover:bg-white/5 transition-all group"
|
|
aria-label="Twitter"
|
|
>
|
|
<Twitter className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-white/40 group-hover:text-white transition-colors" />
|
|
</a>
|
|
<a
|
|
href="https://linkedin.com"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center border border-white/5 hover:border-white/20 hover:bg-white/5 transition-all group"
|
|
aria-label="LinkedIn"
|
|
>
|
|
<Linkedin className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-white/40 group-hover:text-white transition-colors" />
|
|
</a>
|
|
<a
|
|
href="mailto:hello@pounce.ch"
|
|
className="w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center border border-white/5 hover:border-white/20 hover:bg-white/5 transition-all group"
|
|
aria-label="Email"
|
|
>
|
|
<Mail className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-white/40 group-hover:text-white transition-colors" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Protocol Links */}
|
|
<div className="col-span-1">
|
|
<h3 className="text-[10px] sm:text-xs font-bold uppercase tracking-[0.15em] sm:tracking-[0.2em] text-white mb-4 sm:mb-6">Protocol</h3>
|
|
<ul className="space-y-3 sm:space-y-4">
|
|
{[
|
|
{ href: '/acquire', label: 'Acquire' },
|
|
{ href: '/discover', label: 'Discover' },
|
|
{ href: '/yield', label: 'Yield' },
|
|
{ href: '/pricing', label: 'Pricing' },
|
|
].map((link) => (
|
|
<li key={link.href}>
|
|
<Link href={link.href} className="text-xs sm:text-sm font-mono text-white/40 hover:text-accent transition-colors flex items-center gap-1.5 sm:gap-2 group">
|
|
<span className="w-1 h-1 bg-white/20 group-hover:bg-accent transition-colors" /> {link.label}
|
|
</Link>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
{/* Info Links */}
|
|
<div className="col-span-1">
|
|
<h3 className="text-[10px] sm:text-xs font-bold uppercase tracking-[0.15em] sm:tracking-[0.2em] text-white mb-4 sm:mb-6">Intel</h3>
|
|
<ul className="space-y-3 sm:space-y-4">
|
|
<li>
|
|
<Link href="/briefings" className="text-xs sm:text-sm font-mono text-white/40 hover:text-white transition-colors">Briefings</Link>
|
|
</li>
|
|
<li>
|
|
<Link href="/about" className="text-xs sm:text-sm font-mono text-white/40 hover:text-white transition-colors">About</Link>
|
|
</li>
|
|
<li>
|
|
<Link href="/contact" className="text-xs sm:text-sm font-mono text-white/40 hover:text-white transition-colors">Contact</Link>
|
|
</li>
|
|
{!isAuthenticated && (
|
|
<li>
|
|
<Link href="/login" className="text-xs sm:text-sm font-mono text-white/40 hover:text-white transition-colors">Login</Link>
|
|
</li>
|
|
)}
|
|
</ul>
|
|
</div>
|
|
|
|
{/* Legal - Hidden on Small Mobile, Merged into Intel on Mobile */}
|
|
<div className="hidden lg:block lg:col-span-1">
|
|
<h3 className="text-xs font-bold uppercase tracking-[0.2em] text-white mb-6">Legal</h3>
|
|
<ul className="space-y-4">
|
|
<li>
|
|
<Link href="/legal/privacy" className="text-sm font-mono text-white/40 hover:text-white transition-colors">Privacy</Link>
|
|
</li>
|
|
<li>
|
|
<Link href="/legal/terms" className="text-sm font-mono text-white/40 hover:text-white transition-colors">Terms</Link>
|
|
</li>
|
|
<li>
|
|
<Link href="/legal/imprint" className="text-sm font-mono text-white/40 hover:text-white transition-colors">Imprint</Link>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile Legal Links */}
|
|
<div className="lg:hidden flex flex-wrap gap-4 mb-8 text-[10px] font-mono text-white/30">
|
|
<Link href="/legal/privacy" className="hover:text-white transition-colors">Privacy</Link>
|
|
<span className="text-white/10">|</span>
|
|
<Link href="/legal/terms" className="hover:text-white transition-colors">Terms</Link>
|
|
<span className="text-white/10">|</span>
|
|
<Link href="/legal/imprint" className="hover:text-white transition-colors">Imprint</Link>
|
|
</div>
|
|
|
|
{/* Bottom Bar */}
|
|
<div className="pt-6 sm:pt-8 border-t border-white/10 flex flex-col sm:flex-row justify-between items-center gap-3 sm:gap-4 text-[9px] sm:text-[10px] font-mono text-white/20 uppercase tracking-widest">
|
|
<p>© {new Date().getFullYear()} POUNCE AG — ZURICH</p>
|
|
<div className="flex items-center gap-4 sm:gap-6">
|
|
<span className="flex items-center gap-1.5">
|
|
<span className="w-1.5 h-1.5 bg-accent animate-pulse" />
|
|
Online
|
|
</span>
|
|
<span>v2.0.4</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
)
|
|
}
|