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
298 lines
13 KiB
TypeScript
298 lines
13 KiB
TypeScript
'use client'
|
||
|
||
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, ArrowRight } from 'lucide-react'
|
||
import Link from 'next/link'
|
||
|
||
const contactMethods = [
|
||
{
|
||
icon: Mail,
|
||
title: 'Secure Comms',
|
||
description: 'Support, partnerships, and product intel.',
|
||
value: 'hello@pounce.ch',
|
||
href: 'mailto:hello@pounce.ch',
|
||
},
|
||
{
|
||
icon: MessageSquare,
|
||
title: 'Support Desk',
|
||
description: 'Email support. Mon–Fri, 0900–1800 CET.',
|
||
value: 'Send ticket',
|
||
href: 'mailto:hello@pounce.ch?subject=Support',
|
||
},
|
||
{
|
||
icon: Clock,
|
||
title: 'Response Time',
|
||
description: 'Typical response window.',
|
||
value: '< 24 Hours',
|
||
href: null,
|
||
},
|
||
]
|
||
|
||
const faqs = [
|
||
{
|
||
q: 'Forgot credentials?',
|
||
a: 'Use the "Forgot Password" protocol on the login screen. Reset link dispatched instantly.',
|
||
},
|
||
{
|
||
q: 'Upgrade mid-cycle?',
|
||
a: 'Affirmative. Pro-rated charges apply. Features unlock immediately upon transaction.',
|
||
},
|
||
{
|
||
q: 'Refund policy?',
|
||
a: '14-day money-back guarantee. No questions asked. Risk-free deployment.',
|
||
},
|
||
]
|
||
|
||
export default function ContactPage() {
|
||
const [formState, setFormState] = useState<'idle' | 'loading' | 'success' | 'error'>('idle')
|
||
const [error, setError] = useState<string | null>(null)
|
||
const [formData, setFormData] = useState({
|
||
name: '',
|
||
email: '',
|
||
subject: '',
|
||
message: '',
|
||
})
|
||
|
||
const handleSubmit = async (e: React.FormEvent) => {
|
||
e.preventDefault()
|
||
setFormState('loading')
|
||
setError(null)
|
||
|
||
try {
|
||
await api.submitContact(
|
||
formData.name,
|
||
formData.email,
|
||
formData.subject,
|
||
formData.message
|
||
)
|
||
setFormState('success')
|
||
|
||
// Reset after showing success
|
||
setTimeout(() => {
|
||
setFormState('idle')
|
||
setFormData({ name: '', email: '', subject: '', message: '' })
|
||
}, 5000)
|
||
} catch (err: any) {
|
||
setFormState('error')
|
||
setError(err.message || 'Transmission failed. Retry.')
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div className="min-h-screen bg-[#020202] text-white relative overflow-x-hidden selection:bg-accent/30 selection:text-white">
|
||
{/* Background Atmosphere */}
|
||
<div className="fixed inset-0 pointer-events-none z-0">
|
||
<div className="absolute inset-0 bg-[url('/noise.png')] opacity-[0.03] mix-blend-overlay" />
|
||
<div
|
||
className="absolute inset-0 opacity-[0.03]"
|
||
style={{
|
||
backgroundImage: `linear-gradient(rgba(255,255,255,0.3) 0.5px, transparent 0.5px), linear-gradient(90deg, rgba(255,255,255,0.3) 0.5px, transparent 0.5px)`,
|
||
backgroundSize: '160px 160px',
|
||
}}
|
||
/>
|
||
<div className="absolute top-0 left-1/3 w-[500px] h-[400px] bg-accent/[0.02] rounded-full blur-[120px]" />
|
||
</div>
|
||
|
||
<Header />
|
||
|
||
<main className="relative pt-32 sm:pt-40 pb-20 px-4 sm:px-6 flex-1">
|
||
<div className="max-w-6xl mx-auto">
|
||
{/* Hero */}
|
||
<div className="text-center mb-20 animate-fade-in">
|
||
<span className="text-accent font-mono text-xs uppercase tracking-[0.2em] mb-4 block flex items-center justify-center gap-2">
|
||
<div className="w-1.5 h-1.5 bg-accent animate-pulse" />
|
||
Communication Uplink
|
||
</span>
|
||
<h1 className="font-display text-[3.5rem] sm:text-[5rem] leading-[0.9] tracking-[-0.04em] text-white mb-6">
|
||
Establish Contact.
|
||
</h1>
|
||
<p className="text-lg text-white/50 max-w-xl mx-auto font-light">
|
||
Support request, bug report, or partnership intel. We'll respond fast.
|
||
</p>
|
||
</div>
|
||
|
||
{/* Contact Methods */}
|
||
<div className="grid sm:grid-cols-3 gap-6 mb-20 animate-slide-up">
|
||
{contactMethods.map((method) => (
|
||
<div
|
||
key={method.title}
|
||
className="p-8 bg-[#050505] border border-white/10 hover:border-accent/30 transition-all group"
|
||
>
|
||
<div className="w-12 h-12 bg-white/5 flex items-center justify-center mb-6 group-hover:bg-accent/10 transition-colors">
|
||
<method.icon className="w-6 h-6 text-white/60 group-hover:text-accent transition-colors" />
|
||
</div>
|
||
<h3 className="font-display text-xl text-white mb-2">{method.title}</h3>
|
||
<p className="text-xs font-mono text-white/40 mb-4">{method.description}</p>
|
||
{method.href ? (
|
||
<a
|
||
href={method.href}
|
||
className="text-xs font-bold uppercase tracking-widest text-white hover:text-accent transition-colors flex items-center gap-2"
|
||
>
|
||
{method.value} <ArrowRight className="w-3 h-3" />
|
||
</a>
|
||
) : (
|
||
<span className="text-xs font-bold uppercase tracking-widest text-accent">{method.value}</span>
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="grid lg:grid-cols-2 gap-16 lg:gap-24">
|
||
{/* Contact Form - Tech Style */}
|
||
<div className="animate-slide-up bg-[#050505] border border-white/10 p-8 sm:p-10 relative">
|
||
{/* Tech Corners */}
|
||
<div className="absolute -top-px -left-px w-4 h-4 border-t border-l border-white/40" />
|
||
<div className="absolute -top-px -right-px w-4 h-4 border-t border-r border-white/40" />
|
||
<div className="absolute -bottom-px -left-px w-4 h-4 border-b border-l border-white/40" />
|
||
<div className="absolute -bottom-px -right-px w-4 h-4 border-b border-r border-white/40" />
|
||
|
||
<h2 className="font-display text-2xl text-white mb-8">Transmission Form</h2>
|
||
|
||
{formState === 'success' ? (
|
||
<div className="p-10 bg-accent/5 border border-accent/20 text-center">
|
||
<div className="w-16 h-16 bg-accent/10 flex items-center justify-center mx-auto mb-6 rounded-full">
|
||
<CheckCircle className="w-8 h-8 text-accent" />
|
||
</div>
|
||
<h3 className="font-display text-xl text-white mb-2">Message Received</h3>
|
||
<p className="text-xs font-mono text-white/60">
|
||
Your transmission has been logged. Our operators will respond within 4 hours.
|
||
</p>
|
||
</div>
|
||
) : (
|
||
<form onSubmit={handleSubmit} className="space-y-6">
|
||
{formState === 'error' && error && (
|
||
<div className="p-4 bg-red-500/10 border border-red-500/20 flex items-center gap-3">
|
||
<AlertCircle className="w-5 h-5 text-red-500 flex-shrink-0" />
|
||
<p className="text-xs font-mono text-red-500">{error}</p>
|
||
</div>
|
||
)}
|
||
<div className="grid sm:grid-cols-2 gap-6">
|
||
<div className="group">
|
||
<label className="text-[10px] font-mono text-white/40 uppercase tracking-widest mb-2 block group-focus-within:text-white/70">Codename</label>
|
||
<input
|
||
type="text"
|
||
value={formData.name}
|
||
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
||
required
|
||
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"
|
||
/>
|
||
</div>
|
||
<div className="group">
|
||
<label className="text-[10px] font-mono text-white/40 uppercase tracking-widest mb-2 block group-focus-within:text-white/70">Comms ID</label>
|
||
<input
|
||
type="email"
|
||
value={formData.email}
|
||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||
required
|
||
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"
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div className="group">
|
||
<label className="text-[10px] font-mono text-white/40 uppercase tracking-widest mb-2 block group-focus-within:text-white/70">Subject</label>
|
||
<select
|
||
value={formData.subject}
|
||
onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
|
||
required
|
||
className="w-full bg-[#0A0A0A] border border-white/10 px-4 py-3 text-white font-mono text-sm focus:outline-none focus:border-accent transition-all rounded-none appearance-none"
|
||
>
|
||
<option value="">SELECT PROTOCOL</option>
|
||
<option value="support">Technical Support</option>
|
||
<option value="billing">Billing Inquiry</option>
|
||
<option value="sales">Sales / Enterprise</option>
|
||
<option value="partnership">Partnership</option>
|
||
<option value="other">Other</option>
|
||
</select>
|
||
</div>
|
||
<div className="group">
|
||
<label className="text-[10px] font-mono text-white/40 uppercase tracking-widest mb-2 block group-focus-within:text-white/70">Message</label>
|
||
<textarea
|
||
value={formData.message}
|
||
onChange={(e) => setFormData({ ...formData, message: e.target.value })}
|
||
required
|
||
rows={5}
|
||
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 resize-none"
|
||
placeholder="INITIATE TRANSMISSION..."
|
||
/>
|
||
</div>
|
||
<button
|
||
type="submit"
|
||
disabled={formState === 'loading'}
|
||
className="w-full py-4 bg-white text-black text-xs font-bold uppercase tracking-[0.2em] hover:bg-accent transition-all disabled:opacity-50 flex items-center justify-center gap-2"
|
||
style={{ clipPath: 'polygon(10px 0, 100% 0, 100% 100%, 0 100%, 0 10px)' }}
|
||
>
|
||
{formState === 'loading' ? (
|
||
<Loader2 className="w-4 h-4 animate-spin" />
|
||
) : (
|
||
<>
|
||
Send Transmission
|
||
<Send className="w-4 h-4" />
|
||
</>
|
||
)}
|
||
</button>
|
||
</form>
|
||
)}
|
||
</div>
|
||
|
||
{/* FAQ & Info */}
|
||
<div className="space-y-12 animate-slide-up" style={{ animationDelay: '100ms' }}>
|
||
{/* Quick FAQs */}
|
||
<div>
|
||
<h2 className="font-display text-2xl text-white mb-8">Standard Procedures</h2>
|
||
<div className="space-y-4">
|
||
{faqs.map((faq) => (
|
||
<div
|
||
key={faq.q}
|
||
className="p-6 border border-white/10 bg-[#050505]"
|
||
>
|
||
<h3 className="font-display text-lg text-white mb-2">{faq.q}</h3>
|
||
<p className="text-xs font-mono text-white/50 leading-relaxed">{faq.a}</p>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Office Info */}
|
||
<div className="p-8 border border-white/10 bg-[#050505] relative">
|
||
<div className="absolute top-0 left-0 p-2 bg-white/5 border-r border-b border-white/10">
|
||
<Building className="w-4 h-4 text-white/40" />
|
||
</div>
|
||
<h3 className="font-display text-xl text-white mb-6 mt-2">HQ Coordinates</h3>
|
||
<div className="space-y-4 text-sm font-mono text-white/60">
|
||
<div className="flex items-start gap-4">
|
||
<MapPin className="w-4 h-4 text-accent mt-1" />
|
||
<div>
|
||
<p className="text-white font-bold">Gugger Digital Services</p>
|
||
<p>Bahnhofstrasse 100</p>
|
||
<p>8001 Zurich, Switzerland</p>
|
||
</div>
|
||
</div>
|
||
<div className="flex items-start gap-4">
|
||
<Mail className="w-4 h-4 text-accent mt-1" />
|
||
<div>
|
||
<a
|
||
href="mailto:hello@pounce.ch"
|
||
className="text-white hover:text-accent transition-colors"
|
||
>
|
||
hello@pounce.ch
|
||
</a>
|
||
<p>General Inquiries</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<Footer />
|
||
</div>
|
||
)
|
||
}
|