370143b643
Build pitch-deck / build-push-deploy (push) Successful in 1m33s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 37s
CI / test-python-voice (push) Successful in 31s
CI / test-bqas (push) Successful in 27s
Dataroom routes were reading x-investor-id from request headers which the middleware sets as response headers — these don't reach route handlers when the admin fallback path runs (NextResponse.next() without header). Switch to getSessionFromCookie() consistent with all other investor routes. Auth page DSGVO footer switched from absolute bottom-0 to normal flow so the expanded Art. 13 notice doesn't overlap the login card. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
141 lines
6.6 KiB
TypeScript
141 lines
6.6 KiB
TypeScript
'use client'
|
||
|
||
import { motion } from 'framer-motion'
|
||
import { useState, FormEvent } from 'react'
|
||
|
||
type Status = 'idle' | 'submitting' | 'sent' | 'error'
|
||
|
||
export default function AuthPage() {
|
||
const [email, setEmail] = useState('')
|
||
const [status, setStatus] = useState<Status>('idle')
|
||
const [message, setMessage] = useState<string | null>(null)
|
||
|
||
async function handleSubmit(e: FormEvent) {
|
||
e.preventDefault()
|
||
if (!email.trim()) return
|
||
|
||
setStatus('submitting')
|
||
setMessage(null)
|
||
|
||
try {
|
||
const res = await fetch('/api/auth/request-link', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ email: email.trim() }),
|
||
})
|
||
const data = await res.json().catch(() => ({}))
|
||
|
||
if (res.ok) {
|
||
setStatus('sent')
|
||
setMessage(data.message || 'If this email was invited, a fresh access link has been sent.')
|
||
} else {
|
||
setStatus('error')
|
||
setMessage(data.error || 'Something went wrong. Please try again.')
|
||
}
|
||
} catch {
|
||
setStatus('error')
|
||
setMessage('Network error. Please try again.')
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div className="min-h-screen flex flex-col bg-[#0a0a1a] relative overflow-x-hidden">
|
||
{/* Background gradient */}
|
||
<div className="absolute inset-0 bg-gradient-to-br from-indigo-950/30 via-transparent to-purple-950/20 pointer-events-none" />
|
||
|
||
<div className="flex-1 flex items-center justify-center py-12 px-6">
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ duration: 0.6 }}
|
||
className="relative z-10 text-center max-w-md w-full mx-auto"
|
||
>
|
||
<div className="mb-8">
|
||
<h1 className="text-3xl font-bold bg-gradient-to-r from-indigo-400 to-purple-400 bg-clip-text text-transparent mb-2">
|
||
BreakPilot ComplAI
|
||
</h1>
|
||
<p className="text-white/30 text-sm">Investor Pitch Deck</p>
|
||
</div>
|
||
|
||
<div className="bg-white/[0.03] border border-white/[0.06] rounded-2xl p-8 backdrop-blur-sm">
|
||
<div className="w-16 h-16 mx-auto mb-6 rounded-full bg-indigo-500/10 flex items-center justify-center">
|
||
<svg className="w-8 h-8 text-indigo-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5}
|
||
d="M21.75 9v.906a2.25 2.25 0 01-1.183 1.981l-6.478 3.488M2.25 9v.906a2.25 2.25 0 001.183 1.981l6.478 3.488m8.839 2.51l-4.66-2.51m0 0l-1.023-.55a2.25 2.25 0 00-2.134 0l-1.022.55m0 0l-4.661 2.51m16.5-1.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75A2.25 2.25 0 014.5 4.5h15a2.25 2.25 0 012.25 2.25v11.25z" />
|
||
</svg>
|
||
</div>
|
||
|
||
<h2 className="text-xl font-semibold text-white/90 mb-3">
|
||
Invitation Required
|
||
</h2>
|
||
|
||
<p className="text-white/50 text-sm leading-relaxed mb-6">
|
||
This interactive pitch deck is available by invitation only.
|
||
If you were invited, enter your email below and we'll send you a fresh access link.
|
||
</p>
|
||
|
||
{status === 'sent' ? (
|
||
<div className="text-left bg-indigo-500/10 border border-indigo-500/20 rounded-lg p-4 mb-5">
|
||
<p className="text-indigo-200/90 text-sm leading-relaxed">
|
||
{message}
|
||
</p>
|
||
</div>
|
||
) : (
|
||
<form onSubmit={handleSubmit} className="text-left mb-5">
|
||
<label htmlFor="email" className="block text-white/60 text-xs mb-2 uppercase tracking-wide">
|
||
Email address
|
||
</label>
|
||
<input
|
||
id="email"
|
||
type="email"
|
||
required
|
||
autoComplete="email"
|
||
value={email}
|
||
onChange={(e) => setEmail(e.target.value)}
|
||
disabled={status === 'submitting'}
|
||
placeholder="you@example.com"
|
||
className="w-full bg-white/[0.04] border border-white/[0.08] rounded-lg px-4 py-3 text-white/90 text-sm placeholder:text-white/20 focus:outline-none focus:border-indigo-400/50 focus:bg-white/[0.06] transition-colors disabled:opacity-50"
|
||
/>
|
||
{status === 'error' && message && (
|
||
<p className="mt-2 text-rose-300/80 text-xs">{message}</p>
|
||
)}
|
||
<button
|
||
type="submit"
|
||
disabled={status === 'submitting' || !email.trim()}
|
||
className="w-full mt-4 bg-gradient-to-br from-indigo-500 to-purple-500 hover:from-indigo-400 hover:to-purple-400 disabled:opacity-40 disabled:cursor-not-allowed text-white text-sm font-medium rounded-lg px-4 py-3 transition-all"
|
||
>
|
||
{status === 'submitting' ? 'Sending…' : 'Send access link'}
|
||
</button>
|
||
</form>
|
||
)}
|
||
|
||
<div className="border-t border-white/[0.06] pt-5">
|
||
<p className="text-white/30 text-xs">
|
||
Questions? Contact us at{' '}
|
||
<a href="mailto:pitch@breakpilot.ai" className="text-indigo-400/80 hover:text-indigo-400 transition-colors">
|
||
pitch@breakpilot.ai
|
||
</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<p className="mt-6 text-white/20 text-xs">
|
||
We are an AI-first company. No PDFs. No slide decks. Just code.
|
||
</p>
|
||
</motion.div>
|
||
</div>
|
||
|
||
{/* Privacy Notice Footer */}
|
||
<div className="relative z-10 px-8 py-5 border-t border-white/5">
|
||
<div className="max-w-2xl mx-auto">
|
||
<p className="text-[10px] text-white/20 leading-relaxed text-center">
|
||
<strong className="text-white/25">Datenschutzhinweis (Art. 13 DSGVO):</strong> Beim Zugriff werden technische Zugriffsdaten (IP-Adresse, Zeitpunkt, Browser) sowie – soweit eingeladen – personenbezogene Kontaktdaten (E-Mail, Name, Unternehmen) verarbeitet. Zweck: Zugangsverwaltung und Missbrauchsprävention. Rechtsgrundlage: Art. 6 Abs. 1 lit. f DSGVO (berechtigtes Interesse). Speicherdauer: max. 30 Tage nach letztem Zugriff; nicht aktivierte Zugänge nach 90 Tagen. Danach automatische Anonymisierung. Ihre Rechte gem. Art. 15–21 DSGVO (Auskunft, Berichtigung, Löschung, Einschränkung, Datenübertragbarkeit, Widerspruch): Anfragen an pitch@breakpilot.ai. Beschwerderecht bei der Aufsichtsbehörde: LfDI Baden-Württemberg (www.baden-wuerttemberg.datenschutz.de).</p>
|
||
<p className="text-[10px] text-white/15 text-center mt-1">
|
||
Verantwortlich: Benjamin Bönisch & Sharang Parnerkar · Kontakt: info@breakpilot.com
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|