Neue Folie "Investition & Cap Table" nach The Ask: - Pie Chart: Gründer 75%, Investor 19,6%, ESOP 5,4% - Pre-Seed Details: 4M Pre-Money, 975k Investment, 4,975M Post-Money - Gründergehälter: 0 (2026) → 7k (2027) → 8k (2028) → 9,1k (2029+) - Gewinnverwendung: 100% Reinvestition, kein Dividende bis Series A - INVEST-Programm (BAFA): 20% Zuschuss = 195.000 EUR zurück - ESOP: 5,4% für Schlüsselmitarbeiter, 4J Vesting, 1J Cliff - Series A Ausblick: 15-25M Bewertung bei 3M+ ARR Finanzplan: Gründer 7.000 EUR/Mo ab Jan 2027, 14% jährl. Erhöhung FAQs: Cap Table + Gewinnverwendung als Fließtext Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
280 lines
9.8 KiB
TypeScript
280 lines
9.8 KiB
TypeScript
'use client'
|
|
|
|
import { useCallback, useState } from 'react'
|
|
import { AnimatePresence } from 'framer-motion'
|
|
import { useSlideNavigation } from '@/lib/hooks/useSlideNavigation'
|
|
import { useKeyboard } from '@/lib/hooks/useKeyboard'
|
|
import { usePitchData } from '@/lib/hooks/usePitchData'
|
|
import { usePresenterMode } from '@/lib/hooks/usePresenterMode'
|
|
import { Language, PitchData } from '@/lib/types'
|
|
|
|
import ParticleBackground from './ParticleBackground'
|
|
import ProgressBar from './ProgressBar'
|
|
import NavigationControls from './NavigationControls'
|
|
import NavigationFAB from './NavigationFAB'
|
|
import ChatFAB from './ChatFAB'
|
|
import SlideOverview from './SlideOverview'
|
|
import SlideContainer from './SlideContainer'
|
|
import PresenterOverlay from './presenter/PresenterOverlay'
|
|
import AvatarPlaceholder from './presenter/AvatarPlaceholder'
|
|
|
|
import IntroPresenterSlide from './slides/IntroPresenterSlide'
|
|
import ExecutiveSummarySlide from './slides/ExecutiveSummarySlide'
|
|
import CoverSlide from './slides/CoverSlide'
|
|
import ProblemSlide from './slides/ProblemSlide'
|
|
import SolutionSlide from './slides/SolutionSlide'
|
|
import RegulatoryLandscapeSlide from './slides/RegulatoryLandscapeSlide'
|
|
import ProductSlide from './slides/ProductSlide'
|
|
import HowItWorksSlide from './slides/HowItWorksSlide'
|
|
import MarketSlide from './slides/MarketSlide'
|
|
import BusinessModelSlide from './slides/BusinessModelSlide'
|
|
import TractionSlide from './slides/TractionSlide'
|
|
import CompetitionSlide from './slides/CompetitionSlide'
|
|
import TeamSlide from './slides/TeamSlide'
|
|
import FinancialsSlide from './slides/FinancialsSlide'
|
|
import TheAskSlide from './slides/TheAskSlide'
|
|
import CapTableSlide from './slides/CapTableSlide'
|
|
import AIQASlide from './slides/AIQASlide'
|
|
import AssumptionsSlide from './slides/AssumptionsSlide'
|
|
import ArchitectureSlide from './slides/ArchitectureSlide'
|
|
import GTMSlide from './slides/GTMSlide'
|
|
import RegulatorySlide from './slides/RegulatorySlide'
|
|
import EngineeringSlide from './slides/EngineeringSlide'
|
|
import AIPipelineSlide from './slides/AIPipelineSlide'
|
|
import SDKDemoSlide from './slides/SDKDemoSlide'
|
|
import StrategySlide from './slides/StrategySlide'
|
|
import FinanzplanSlide from './slides/FinanzplanSlide'
|
|
|
|
interface PitchDeckProps {
|
|
lang: Language
|
|
onToggleLanguage: () => void
|
|
}
|
|
|
|
export default function PitchDeck({ lang, onToggleLanguage }: PitchDeckProps) {
|
|
const { data, loading, error } = usePitchData()
|
|
const nav = useSlideNavigation()
|
|
const [fabOpen, setFabOpen] = useState(false)
|
|
const [theme, setTheme] = useState<'dark' | 'light'>('dark')
|
|
|
|
const toggleTheme = useCallback(() => {
|
|
setTheme(prev => {
|
|
const next = prev === 'dark' ? 'light' : 'dark'
|
|
if (next === 'light') {
|
|
document.documentElement.classList.add('theme-light')
|
|
} else {
|
|
document.documentElement.classList.remove('theme-light')
|
|
}
|
|
return next
|
|
})
|
|
}, [])
|
|
|
|
const presenter = usePresenterMode({
|
|
goToSlide: nav.goToSlide,
|
|
currentSlide: nav.currentIndex,
|
|
totalSlides: nav.totalSlides,
|
|
language: lang,
|
|
})
|
|
|
|
const toggleFullscreen = useCallback(() => {
|
|
if (!document.fullscreenElement) {
|
|
document.documentElement.requestFullscreen()
|
|
} else {
|
|
document.exitFullscreen()
|
|
}
|
|
}, [])
|
|
|
|
const toggleMenu = useCallback(() => {
|
|
setFabOpen(prev => !prev)
|
|
}, [])
|
|
|
|
useKeyboard({
|
|
onNext: nav.nextSlide,
|
|
onPrev: nav.prevSlide,
|
|
onFirst: nav.goToFirst,
|
|
onLast: nav.goToLast,
|
|
onOverview: nav.toggleOverview,
|
|
onFullscreen: toggleFullscreen,
|
|
onLanguageToggle: onToggleLanguage,
|
|
onMenuToggle: toggleMenu,
|
|
onPresenterToggle: presenter.toggle,
|
|
onGoToSlide: nav.goToSlide,
|
|
enabled: !nav.showOverview,
|
|
})
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="h-screen flex items-center justify-center">
|
|
<div className="text-center">
|
|
<div className="w-12 h-12 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
|
|
<p className="text-white/40 text-sm">{lang === 'de' ? 'Lade Pitch-Daten...' : 'Loading pitch data...'}</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (error || !data) {
|
|
return (
|
|
<div className="h-screen flex items-center justify-center">
|
|
<div className="text-center max-w-md">
|
|
<p className="text-red-400 mb-2">{lang === 'de' ? 'Fehler beim Laden' : 'Loading error'}</p>
|
|
<p className="text-white/40 text-sm">{error || 'No data'}</p>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function renderSlide() {
|
|
if (!data) return null
|
|
|
|
switch (nav.currentSlide) {
|
|
case 'intro-presenter':
|
|
return (
|
|
<IntroPresenterSlide
|
|
lang={lang}
|
|
onStartPresenter={presenter.start}
|
|
isPresenting={presenter.state !== 'idle'}
|
|
/>
|
|
)
|
|
case 'executive-summary':
|
|
return <ExecutiveSummarySlide lang={lang} data={data} />
|
|
case 'cover':
|
|
return <CoverSlide lang={lang} onNext={nav.nextSlide} funding={data.funding} />
|
|
case 'problem':
|
|
return <ProblemSlide lang={lang} />
|
|
case 'solution':
|
|
return <SolutionSlide lang={lang} />
|
|
case 'regulatory-landscape':
|
|
return <RegulatoryLandscapeSlide lang={lang} />
|
|
case 'product':
|
|
return <ProductSlide lang={lang} />
|
|
case 'how-it-works':
|
|
return <HowItWorksSlide lang={lang} />
|
|
case 'market':
|
|
return <MarketSlide lang={lang} market={data.market} />
|
|
case 'business-model':
|
|
return <BusinessModelSlide lang={lang} />
|
|
case 'traction':
|
|
return <TractionSlide lang={lang} milestones={data.milestones} metrics={data.metrics} />
|
|
case 'competition':
|
|
return <CompetitionSlide lang={lang} features={data.features} competitors={data.competitors} />
|
|
case 'team':
|
|
return <TeamSlide lang={lang} team={data.team} />
|
|
case 'financials':
|
|
return <FinancialsSlide lang={lang} />
|
|
case 'the-ask':
|
|
return <TheAskSlide lang={lang} funding={data.funding} />
|
|
case 'cap-table':
|
|
return <CapTableSlide lang={lang} />
|
|
case 'ai-qa':
|
|
return <AIQASlide lang={lang} />
|
|
case 'annex-assumptions':
|
|
return <AssumptionsSlide lang={lang} />
|
|
case 'annex-architecture':
|
|
return <ArchitectureSlide lang={lang} />
|
|
case 'annex-gtm':
|
|
return <GTMSlide lang={lang} />
|
|
case 'annex-regulatory':
|
|
return <RegulatorySlide lang={lang} />
|
|
case 'annex-engineering':
|
|
return <EngineeringSlide lang={lang} />
|
|
case 'annex-aipipeline':
|
|
return <AIPipelineSlide lang={lang} />
|
|
case 'annex-sdk-demo':
|
|
return <SDKDemoSlide lang={lang} />
|
|
case 'annex-strategy':
|
|
return <StrategySlide lang={lang} />
|
|
case 'annex-finanzplan':
|
|
return <FinanzplanSlide lang={lang} />
|
|
default:
|
|
return null
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className={`h-screen relative overflow-hidden bg-gradient-to-br ${theme === 'light' ? 'from-[#eef0f5] via-[#f8f9fc] to-[#eef0f5]' : 'from-slate-950 via-[#0a0a1a] to-slate-950'}`}>
|
|
<ParticleBackground />
|
|
<ProgressBar current={nav.currentIndex} total={nav.totalSlides} />
|
|
|
|
{/* Theme Toggle */}
|
|
<button
|
|
onClick={toggleTheme}
|
|
className="fixed top-4 right-4 z-50 p-2 rounded-full bg-white/[0.08] border border-white/10 hover:bg-white/[0.15] transition-colors backdrop-blur-xl"
|
|
title={theme === 'dark' ? 'Tag-Modus' : 'Nacht-Modus'}
|
|
>
|
|
{theme === 'dark' ? (
|
|
<svg className="w-4 h-4 text-amber-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
<circle cx="12" cy="12" r="5" /><path d="M12 1v2m0 18v2M4.22 4.22l1.42 1.42m12.72 12.72l1.42 1.42M1 12h2m18 0h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" />
|
|
</svg>
|
|
) : (
|
|
<svg className="w-4 h-4 text-indigo-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" />
|
|
</svg>
|
|
)}
|
|
</button>
|
|
|
|
<SlideContainer slideKey={nav.currentSlide} direction={nav.direction}>
|
|
{renderSlide()}
|
|
</SlideContainer>
|
|
|
|
<NavigationControls
|
|
onPrev={nav.prevSlide}
|
|
onNext={nav.nextSlide}
|
|
isFirst={nav.isFirst}
|
|
isLast={nav.isLast}
|
|
current={nav.currentIndex}
|
|
total={nav.totalSlides}
|
|
/>
|
|
|
|
<ChatFAB
|
|
lang={lang}
|
|
currentSlide={nav.currentSlide}
|
|
currentIndex={nav.currentIndex}
|
|
visitedSlides={nav.visitedSlides}
|
|
onGoToSlide={nav.goToSlide}
|
|
presenterState={presenter.state}
|
|
onPresenterInterrupt={presenter.pause}
|
|
/>
|
|
|
|
<NavigationFAB
|
|
currentIndex={nav.currentIndex}
|
|
totalSlides={nav.totalSlides}
|
|
visitedSlides={nav.visitedSlides}
|
|
onGoToSlide={nav.goToSlide}
|
|
lang={lang}
|
|
onToggleLanguage={onToggleLanguage}
|
|
/>
|
|
|
|
{/* Presenter UI */}
|
|
<AvatarPlaceholder state={presenter.state} />
|
|
<PresenterOverlay
|
|
state={presenter.state}
|
|
currentIndex={nav.currentIndex}
|
|
totalSlides={nav.totalSlides}
|
|
progress={presenter.progress}
|
|
displayText={presenter.displayText}
|
|
lang={lang}
|
|
onPause={presenter.pause}
|
|
onResume={presenter.resume}
|
|
onStop={presenter.stop}
|
|
onSkip={presenter.skipSlide}
|
|
onPrev={presenter.prevSlide}
|
|
isSpeaking={presenter.isSpeaking}
|
|
ttsAvailable={presenter.ttsAvailable}
|
|
ttsEnabled={presenter.ttsEnabled}
|
|
onToggleTts={() => presenter.setTtsEnabled(!presenter.ttsEnabled)}
|
|
/>
|
|
|
|
<AnimatePresence>
|
|
{nav.showOverview && (
|
|
<SlideOverview
|
|
currentIndex={nav.currentIndex}
|
|
onGoToSlide={nav.goToSlide}
|
|
onClose={() => nav.setShowOverview(false)}
|
|
lang={lang}
|
|
/>
|
|
)}
|
|
</AnimatePresence>
|
|
</div>
|
|
)
|
|
}
|