feat(pitch-deck): add pitch version selection to investor invite form
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 33s
CI / test-python-voice (push) Successful in 36s
CI / test-bqas (push) Successful in 32s

- Version dropdown on the invite form shows all committed versions
- Selected version is assigned to the investor at creation time (no separate step needed)
- API validates version is committed before upserting
- Leaving the dropdown empty keeps any existing assignment (COALESCE behavior)
- version_id included in audit log

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-05-06 23:27:23 +02:00
parent 17b9006b88
commit b0d273d3ab
2 changed files with 60 additions and 5 deletions
@@ -3,7 +3,7 @@
import { useState, useMemo, useEffect, useRef } from 'react'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
import { ArrowLeft, Eye, Send, Link2, Copy, Check, Mail, MailX } from 'lucide-react'
import { ArrowLeft, Eye, Send, Link2, Copy, Check, Mail, MailX, Layers } from 'lucide-react'
import {
DEFAULT_MESSAGE, DEFAULT_CLOSING,
DEFAULT_MESSAGE_EN, DEFAULT_CLOSING_EN,
@@ -12,6 +12,13 @@ import {
type Lang = 'de' | 'en'
interface Version {
id: string
name: string
status: string
created_at: string
}
export default function NewInvestorPage() {
const router = useRouter()
const [email, setEmail] = useState('')
@@ -19,6 +26,8 @@ export default function NewInvestorPage() {
const [company, setCompany] = useState('')
const [lang, setLang] = useState<Lang>('de')
const [sendEmail, setSendEmail] = useState(true)
const [versionId, setVersionId] = useState('')
const [versions, setVersions] = useState<Version[]>([])
const [greeting, setGreeting] = useState('')
const [message, setMessage] = useState(DEFAULT_MESSAGE)
const [closing, setClosing] = useState(DEFAULT_CLOSING)
@@ -33,6 +42,13 @@ export default function NewInvestorPage() {
const ttl = process.env.NEXT_PUBLIC_MAGIC_LINK_TTL_HOURS || '72'
const effectiveGreeting = greeting || getDefaultGreeting(name || null, lang)
useEffect(() => {
fetch('/api/admin/versions')
.then(r => r.json())
.then(d => setVersions((d.versions ?? []).filter((v: Version) => v.status === 'committed')))
.catch(() => {})
}, [])
// When language changes, swap defaults unless the user has manually edited
useEffect(() => {
if (lang === prevLang.current) return
@@ -58,6 +74,7 @@ export default function NewInvestorPage() {
company,
lang,
send_email: sendEmail,
version_id: versionId || null,
...(sendEmail && {
greeting: effectiveGreeting,
message,
@@ -207,6 +224,27 @@ export default function NewInvestorPage() {
/>
</div>
{/* Pitch Version */}
<div>
<label htmlFor="version" className="block text-xs font-medium text-white/60 uppercase tracking-wider mb-2">
<span className="inline-flex items-center gap-1.5"><Layers className="w-3.5 h-3.5" /> Pitch-Version <span className="text-white/30 text-[10px] normal-case">(optional)</span></span>
</label>
<select
id="version"
value={versionId}
onChange={(e) => setVersionId(e.target.value)}
className="w-full bg-black/30 border border-white/10 rounded-lg px-3 py-2.5 text-white focus:outline-none focus:ring-2 focus:ring-indigo-500/40 appearance-none"
>
<option value=""> Standard (keine spezifische Version) </option>
{versions.map(v => (
<option key={v.id} value={v.id}>{v.name}</option>
))}
</select>
{versions.length === 0 && (
<p className="text-[10px] text-white/25 mt-1">Keine committed Versionen vorhanden</p>
)}
</div>
<hr className="border-white/[0.06]" />
{/* Language toggle + Send email toggle */}