Files
breakpilot-core/pitch-deck/app/auth/page.tsx
T
Sharang Parnerkar 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
fix(dataroom): use getSessionFromCookie() instead of middleware headers; fix auth page overflow
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>
2026-05-01 16:03:21 +02:00

141 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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&apos;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. 1521 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>
)
}