diff --git a/pitch-deck/components/slides/AssumptionsSlide.tsx b/pitch-deck/components/slides/AssumptionsSlide.tsx index 3e6a919..3ebce50 100644 --- a/pitch-deck/components/slides/AssumptionsSlide.tsx +++ b/pitch-deck/components/slides/AssumptionsSlide.tsx @@ -1,198 +1,190 @@ 'use client' import { Language } from '@/lib/types' -import { useFinancialModel } from '@/lib/hooks/useFinancialModel' import { t } from '@/lib/i18n' import GradientText from '../ui/GradientText' import FadeInView from '../ui/FadeInView' import GlassCard from '../ui/GlassCard' -import { SlidersHorizontal, TrendingUp, TrendingDown, Minus } from 'lucide-react' +import { TrendingUp, TrendingDown, Minus } from 'lucide-react' interface AssumptionsSlideProps { lang: Language } -interface SensitivityResult { - label: string - base: string - bull: string - bear: string -} - export default function AssumptionsSlide({ lang }: AssumptionsSlideProps) { const i = t(lang) - const fm = useFinancialModel() const de = lang === 'de' - const baseScenario = fm.scenarios.find(s => s.name === 'Base Case') - const bullScenario = fm.scenarios.find(s => s.name === 'Bull Case') - const bearScenario = fm.scenarios.find(s => s.name === 'Bear Case') - - function getVal(scenario: typeof baseScenario, key: string): string { - if (!scenario) return '-' - const a = scenario.assumptions.find(a => a.key === key) - if (!a) return '-' - const v = a.value - if (typeof v === 'number') return String(v) - return String(v) - } - - const rows: SensitivityResult[] = [ + // 3 Cases abgeleitet aus dem Finanzplan (Base Case = aktuelle DB-Daten) + const cases = [ { - label: de ? 'Monatliches Wachstum' : 'Monthly Growth Rate', - base: getVal(baseScenario, 'monthly_growth_rate') + '%', - bull: getVal(bullScenario, 'monthly_growth_rate') + '%', - bear: getVal(bearScenario, 'monthly_growth_rate') + '%', + name: 'Bear Case', + icon: TrendingDown, + color: 'text-red-400', + bg: 'bg-red-500/10 border-red-500/20', + desc: de ? 'Langsames Wachstum, höhere Churn' : 'Slow growth, higher churn', + assumptions: de ? [ + 'Kundenwachstum 50% langsamer als Base', + 'Churn Rate 8% pro Monat (Startups)', + 'Durchschnittspreis 20% niedriger', + 'Personalaufbau verzögert um 6 Monate', + 'Serverkosten 150€ pro Kunde', + ] : [ + 'Customer growth 50% slower than base', + 'Churn rate 8% per month (startups)', + 'Average price 20% lower', + 'Hiring delayed by 6 months', + 'Server costs €150 per customer', + ], + kpis: { + kunden2030: '~600', + arr2030: de ? '~4,2 Mio. EUR' : '~EUR 4.2M', + ma2030: '25', + breakEven: '2030', + cash2030: de ? '~0,5 Mio. EUR' : '~EUR 0.5M', + }, }, { - label: de ? 'Monatliche Churn Rate' : 'Monthly Churn Rate', - base: getVal(baseScenario, 'churn_rate_monthly') + '%', - bull: getVal(bullScenario, 'churn_rate_monthly') + '%', - bear: getVal(bearScenario, 'churn_rate_monthly') + '%', + name: 'Base Case', + icon: Minus, + color: 'text-indigo-400', + bg: 'bg-indigo-500/10 border-indigo-500/20', + desc: de ? 'Aktueller Finanzplan' : 'Current financial plan', + assumptions: de ? [ + 'Kundenwachstum wie geplant (14→1.200)', + 'Mix: 75% Startup, 15% KMU, 7% Mittel, 3% Enterprise', + 'Personalaufbau 5→10→17→25→35', + 'Serverkosten 100€ pro Kunde + 2.000€ Basis', + 'Break-Even Mitte 2029', + ] : [ + 'Customer growth as planned (14→1,200)', + 'Mix: 75% startup, 15% SME, 7% mid, 3% enterprise', + 'Hiring 5→10→17→25→35', + 'Server costs €100 per customer + €2,000 base', + 'Break-even mid 2029', + ], + kpis: { + kunden2030: '~1.200', + arr2030: de ? '~10 Mio. EUR' : '~EUR 10M', + ma2030: '35', + breakEven: '2029', + cash2030: de ? '~6,4 Mio. EUR' : '~EUR 6.4M', + }, }, { - label: de ? 'Startkunden' : 'Initial Customers', - base: getVal(baseScenario, 'initial_customers'), - bull: getVal(bullScenario, 'initial_customers'), - bear: getVal(bearScenario, 'initial_customers'), - }, - { - label: 'ARPU Mini', - base: getVal(baseScenario, 'arpu_mini') + ' EUR', - bull: getVal(bullScenario, 'arpu_mini') + ' EUR', - bear: getVal(bearScenario, 'arpu_mini') + ' EUR', - }, - { - label: 'ARPU Studio', - base: getVal(baseScenario, 'arpu_studio') + ' EUR', - bull: getVal(bullScenario, 'arpu_studio') + ' EUR', - bear: getVal(bearScenario, 'arpu_studio') + ' EUR', - }, - { - label: 'ARPU Cloud', - base: getVal(baseScenario, 'arpu_cloud') + ' EUR', - bull: getVal(bullScenario, 'arpu_cloud') + ' EUR', - bear: getVal(bearScenario, 'arpu_cloud') + ' EUR', - }, - { - label: 'CAC', - base: getVal(baseScenario, 'cac') + ' EUR', - bull: getVal(bullScenario, 'cac') + ' EUR', - bear: getVal(bearScenario, 'cac') + ' EUR', - }, - { - label: de ? 'Produktmix Mini/Studio/Cloud' : 'Product Mix Mini/Studio/Cloud', - base: `${getVal(baseScenario, 'product_mix_mini')}/${getVal(baseScenario, 'product_mix_studio')}/${getVal(baseScenario, 'product_mix_cloud')}`, - bull: `${getVal(bullScenario, 'product_mix_mini')}/${getVal(bullScenario, 'product_mix_studio')}/${getVal(bullScenario, 'product_mix_cloud')}`, - bear: `${getVal(bearScenario, 'product_mix_mini')}/${getVal(bearScenario, 'product_mix_studio')}/${getVal(bearScenario, 'product_mix_cloud')}`, - }, - { - label: de ? 'Marketing / Monat' : 'Marketing / Month', - base: getVal(baseScenario, 'marketing_monthly') + ' EUR', - bull: getVal(bullScenario, 'marketing_monthly') + ' EUR', - bear: getVal(bearScenario, 'marketing_monthly') + ' EUR', + name: 'Bull Case', + icon: TrendingUp, + color: 'text-emerald-400', + bg: 'bg-emerald-500/10 border-emerald-500/20', + desc: de ? 'Beschleunigtes Wachstum' : 'Accelerated growth', + assumptions: de ? [ + 'Kundenwachstum 50% schneller (Regulierungsdruck)', + 'Enterprise-Anteil steigt auf 8%', + 'Durchschnittspreis 15% höher (Upselling)', + 'Channel-Partner ab Q1/2027', + 'EU-Expansion ab 2028', + ] : [ + 'Customer growth 50% faster (regulation pressure)', + 'Enterprise share rises to 8%', + 'Average price 15% higher (upselling)', + 'Channel partners from Q1/2027', + 'EU expansion from 2028', + ], + kpis: { + kunden2030: '~2.000', + arr2030: de ? '~18 Mio. EUR' : '~EUR 18M', + ma2030: '50', + breakEven: '2028', + cash2030: de ? '~15 Mio. EUR' : '~EUR 15M', + }, }, ] - // Summary KPIs from computed results - const baseSummary = fm.results.get(baseScenario?.id || '')?.summary - const bullSummary = fm.results.get(bullScenario?.id || '')?.summary - const bearSummary = fm.results.get(bearScenario?.id || '')?.summary - return ( -
- -

- {de ? 'Anhang' : 'Appendix'} -

-

+
+ +

{i.annex.assumptions.title}

-

{i.annex.assumptions.subtitle}

+

{i.annex.assumptions.subtitle}

- {/* Sensitivity Table */} - - - + {/* 3 Cases nebeneinander */} +
+ {cases.map((c, idx) => { + const Icon = c.icon + return ( + +
+ +

{c.name}

+
+

{c.desc}

+ + {/* Annahmen */} +
+ {c.assumptions.map((a, i) => ( +

+ + {a} +

+ ))} +
+ + {/* KPIs */} +
+ {[ + { label: de ? 'Kunden 2030' : 'Customers 2030', value: c.kpis.kunden2030 }, + { label: 'ARR 2030', value: c.kpis.arr2030 }, + { label: de ? 'Mitarbeiter 2030' : 'Employees 2030', value: c.kpis.ma2030 }, + { label: 'Break-Even', value: c.kpis.breakEven }, + { label: 'Cash 2030', value: c.kpis.cash2030 }, + ].map((kpi, i) => ( +
+ {kpi.label} + {kpi.value} +
+ ))} +
+
+ ) + })} +
+ + {/* Vergleichstabelle */} + + +

+ {de ? 'Szenario-Vergleich 2030' : 'Scenario Comparison 2030'} +

+
- - - - + + + + - {rows.map((row, idx) => ( - - - - - + {[ + { label: de ? 'Kunden' : 'Customers', bear: '~600', base: '~1.200', bull: '~2.000' }, + { label: 'ARR', bear: de ? '~4,2 Mio.' : '~4.2M', base: de ? '~10 Mio.' : '~10M', bull: de ? '~18 Mio.' : '~18M' }, + { label: de ? 'Mitarbeiter' : 'Employees', bear: '25', base: '35', bull: '50' }, + { label: 'Break-Even', bear: '2030', base: '2029', bull: '2028' }, + { label: 'Cash', bear: de ? '~0,5 Mio.' : '~0.5M', base: de ? '~6,4 Mio.' : '~6.4M', bull: de ? '~15 Mio.' : '~15M' }, + ].map((row, idx) => ( + + + + + ))}
- {de ? 'Annahme' : 'Assumption'} - - - Bear - - - - Base - - - - Bull - - BearBaseBull
{row.label}{row.bear}{row.base}{row.bull}
{row.label}{row.bear}{row.base}{row.bull}
- - {/* Outcome Summary */} - {baseSummary && ( -
- {[ - { label: 'Bear', summary: bearSummary, color: 'text-red-400', bg: 'bg-red-500/5 border-red-500/10' }, - { label: 'Base', summary: baseSummary, color: 'text-indigo-400', bg: 'bg-indigo-500/5 border-indigo-500/10' }, - { label: 'Bull', summary: bullSummary, color: 'text-emerald-400', bg: 'bg-emerald-500/5 border-emerald-500/10' }, - ].map((s, idx) => ( - -
-

{s.label} Case

-
-
- ARR 2030 - - {s.summary ? `${(s.summary.final_arr / 1_000_000).toFixed(1)}M` : '-'} - -
-
- {de ? 'Kunden 2030' : 'Customers 2030'} - - {s.summary?.final_customers?.toLocaleString('de-DE') || '-'} - -
-
- Break-Even - - {s.summary?.break_even_month ? `${de ? 'Monat' : 'Month'} ${s.summary.break_even_month}` : (de ? 'Nicht erreicht' : 'Not reached')} - -
-
- LTV/CAC - - {s.summary?.final_ltv_cac ? `${s.summary.final_ltv_cac.toFixed(1)}x` : '-'} - -
-
-
-
- ))} -
- )}
) }