feat(pitch-deck): Pricing slide, GuV hierarchy, Problem/Solution cards, engine fixes
Some checks failed
Build pitch-deck / build-push-deploy (push) Successful in 1m52s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-python-voice (push) Has been cancelled
CI / test-bqas (push) Has been cancelled
CI / test-go-consent (push) Has been cancelled
Some checks failed
Build pitch-deck / build-push-deploy (push) Successful in 1m52s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-python-voice (push) Has been cancelled
CI / test-bqas (push) Has been cancelled
CI / test-go-consent (push) Has been cancelled
- BusinessModel → Pricing: remove Unit Economics, fullwidth tiers - GuV: major sums (EBIT, Rohergebnis, Jahresüberschuss) larger font + border - Engine: compute Rohergebnis, dynamic financing row matching - Problem slide: amber/orange "Die Konsequenz" card - Solution slide: larger Compliance Optimizer card - DB patch: Stammkapital, 2. Finanzierungsrunde 500k, GuV sort order Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,11 +2,10 @@
|
||||
|
||||
import { Language } from '@/lib/types'
|
||||
import { t } from '@/lib/i18n'
|
||||
import { useFpKPIs } from '@/lib/hooks/useFpKPIs'
|
||||
import GradientText from '../ui/GradientText'
|
||||
import FadeInView from '../ui/FadeInView'
|
||||
import GlassCard from '../ui/GlassCard'
|
||||
import { ArrowRight, TrendingUp, Target, Repeat, DollarSign, Users, BarChart3 } from 'lucide-react'
|
||||
import { ArrowRight } from 'lucide-react'
|
||||
|
||||
interface BusinessModelSlideProps {
|
||||
lang: Language
|
||||
@@ -16,14 +15,9 @@ interface BusinessModelSlideProps {
|
||||
isWandeldarlehen?: boolean
|
||||
}
|
||||
|
||||
export default function BusinessModelSlide({ lang, isWandeldarlehen }: BusinessModelSlideProps) {
|
||||
export default function BusinessModelSlide({ lang }: BusinessModelSlideProps) {
|
||||
const i = t(lang)
|
||||
const de = lang === 'de'
|
||||
const { last } = useFpKPIs(isWandeldarlehen)
|
||||
const finalCustomers = last?.customers || 0
|
||||
const finalArr = last?.arr || 0
|
||||
const acv = finalCustomers > 0 ? Math.round(finalArr / finalCustomers) : 0
|
||||
const grossMargin = last?.grossMargin ?? 0
|
||||
|
||||
const tiers = [
|
||||
{
|
||||
@@ -61,18 +55,6 @@ export default function BusinessModelSlide({ lang, isWandeldarlehen }: BusinessM
|
||||
},
|
||||
]
|
||||
|
||||
// grossMargin already defined above from useFpKPIs
|
||||
const acvLabel = acv > 0
|
||||
? (de ? `${(acv / 1000).toFixed(1).replace('.', ',')}k EUR` : `EUR ${(acv / 1000).toFixed(1)}k`)
|
||||
: '—'
|
||||
|
||||
const metrics = [
|
||||
{ icon: DollarSign, color: 'text-indigo-400', label: 'ACV (2030)', value: acvLabel, sub: de ? 'Durchschnittlicher Vertragswert (berechnet)' : 'Average Contract Value (computed)' },
|
||||
{ icon: TrendingUp, color: 'text-emerald-400', label: 'Gross Margin', value: `${Math.round(grossMargin)}%`, sub: de ? 'Cloud-native, keine Hardware-Kosten' : 'Cloud-native, no hardware costs' },
|
||||
{ icon: Repeat, color: 'text-purple-400', label: 'NRR (2030)', value: last?.nrr ? `${last.nrr}%` : '—', sub: de ? 'Umsatzwachstum Bestandskunden (berechnet)' : 'Revenue growth existing customers (computed)' },
|
||||
{ icon: Target, color: 'text-amber-400', label: de ? 'Payback (2030)' : 'Payback (2030)', value: last?.paybackMonths ? `${last.paybackMonths} ${de ? 'Mon.' : 'mo.'}` : '—', sub: de ? 'CAC / monatlicher Deckungsbeitrag (berechnet)' : 'CAC / monthly contribution margin (computed)' },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<FadeInView className="text-center mb-6">
|
||||
@@ -80,93 +62,45 @@ export default function BusinessModelSlide({ lang, isWandeldarlehen }: BusinessM
|
||||
<GradientText>{i.businessModel.title}</GradientText>
|
||||
</h2>
|
||||
<p className="text-lg text-white/50 max-w-2xl mx-auto">
|
||||
{de ? 'Mitarbeiterbasiertes SaaS — Kunden sparen mehr als sie zahlen' : 'Employee-based SaaS — customers save more than they pay'}
|
||||
{i.businessModel.subtitle}
|
||||
</p>
|
||||
</FadeInView>
|
||||
|
||||
<div className="grid md:grid-cols-12 gap-4">
|
||||
{/* Left: Pricing Tiers */}
|
||||
<div className="md:col-span-7">
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
{tiers.map((tier, idx) => (
|
||||
<FadeInView key={idx} delay={0.1 + idx * 0.1}>
|
||||
<GlassCard hover={false} className={`p-4 h-full ${tier.highlight ? 'border-slate-300/40 bg-gradient-to-b from-slate-200/[0.08] to-slate-400/[0.04] shadow-lg shadow-slate-300/10 ring-1 ring-slate-300/20' : ''}`}>
|
||||
<h3 className="text-base font-bold text-white mb-0.5">{tier.name}</h3>
|
||||
<p className="text-xs text-white/40 mb-2">{tier.target}</p>
|
||||
<p className="text-xs text-white/30 mb-3">{tier.employees} {de ? 'Mitarbeiter' : 'employees'}</p>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
{tiers.map((tier, idx) => (
|
||||
<FadeInView key={idx} delay={0.1 + idx * 0.1}>
|
||||
<GlassCard hover={false} className={`p-5 h-full ${tier.highlight ? 'border-slate-300/40 bg-gradient-to-b from-slate-200/[0.08] to-slate-400/[0.04] shadow-lg shadow-slate-300/10 ring-1 ring-slate-300/20' : ''}`}>
|
||||
<h3 className="text-lg font-bold text-white mb-0.5">{tier.name}</h3>
|
||||
<p className="text-sm text-white/40 mb-2">{tier.target}</p>
|
||||
<p className="text-xs text-white/30 mb-4">{tier.employees} {de ? 'Mitarbeiter' : 'employees'}</p>
|
||||
|
||||
<div className="mb-3">
|
||||
<span className="text-xl font-black text-white">{tier.price}</span>
|
||||
<span className="text-xs text-white/40 ml-1">{tier.period}</span>
|
||||
</div>
|
||||
|
||||
<ul className="space-y-1.5">
|
||||
{tier.features.map((f, i) => (
|
||||
<li key={i} className="flex items-start gap-1.5 text-sm text-white/50">
|
||||
<span className="w-1 h-1 rounded-full bg-indigo-400 mt-1.5 shrink-0" />
|
||||
{f}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</GlassCard>
|
||||
</FadeInView>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Expansion arrow */}
|
||||
<FadeInView delay={0.4} className="flex items-center justify-center gap-2 mt-3">
|
||||
<span className="text-[10px] text-white/30">Starter</span>
|
||||
<ArrowRight className="w-3 h-3 text-indigo-400/40" />
|
||||
<span className="text-[10px] text-white/30">Professional</span>
|
||||
<ArrowRight className="w-3 h-3 text-indigo-400/40" />
|
||||
<span className="text-[10px] text-white/30">Enterprise</span>
|
||||
<span className="text-xs text-white/20 ml-2">{de ? 'Land & Expand' : 'Land & Expand'}</span>
|
||||
</FadeInView>
|
||||
</div>
|
||||
|
||||
{/* Right: Unit Economics */}
|
||||
<div className="md:col-span-5">
|
||||
<FadeInView delay={0.3}>
|
||||
<GlassCard hover={false} className="p-4 h-full">
|
||||
<h3 className="text-xs font-bold text-white/40 uppercase tracking-wider mb-4">
|
||||
Unit Economics
|
||||
</h3>
|
||||
<div className="space-y-4">
|
||||
{metrics.map((m, idx) => {
|
||||
const Icon = m.icon
|
||||
return (
|
||||
<div key={idx} className="flex items-start gap-3">
|
||||
<div className={`w-8 h-8 rounded-lg bg-white/[0.05] border border-white/10 flex items-center justify-center shrink-0`}>
|
||||
<Icon className={`w-4 h-4 ${m.color}`} />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-baseline justify-between">
|
||||
<span className="text-xs text-white/40 uppercase tracking-wider">{m.label}</span>
|
||||
<span className={`text-lg font-black ${m.color}`}>{m.value}</span>
|
||||
</div>
|
||||
<p className="text-xs text-white/50">{m.sub}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<div className="mb-4">
|
||||
<span className="text-2xl font-black text-white">{tier.price}</span>
|
||||
<span className="text-sm text-white/40 ml-1">{tier.period}</span>
|
||||
</div>
|
||||
|
||||
{/* Bottom-up sizing */}
|
||||
<div className="mt-4 pt-3 border-t border-white/5">
|
||||
<div className="flex items-center gap-1.5 mb-1">
|
||||
<BarChart3 className="w-3 h-3 text-white/30" />
|
||||
<span className="text-[10px] text-white/30 uppercase tracking-wider">Bottom-Up</span>
|
||||
</div>
|
||||
<p className="text-xs text-white/50">
|
||||
{de
|
||||
? `${finalCustomers.toLocaleString('de-DE')} Kunden × ${acv.toLocaleString('de-DE')} EUR ACV = ~${(finalArr / 1_000_000).toFixed(1).replace('.', ',')} Mio. EUR ARR (2030)`
|
||||
: `${finalCustomers.toLocaleString('en-US')} customers × EUR ${acv.toLocaleString('en-US')} ACV = ~EUR ${(finalArr / 1_000_000).toFixed(1)}M ARR (2030)`}
|
||||
</p>
|
||||
</div>
|
||||
<ul className="space-y-2">
|
||||
{tier.features.map((f, i) => (
|
||||
<li key={i} className="flex items-start gap-2 text-sm text-white/50">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-indigo-400 mt-1.5 shrink-0" />
|
||||
{f}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</GlassCard>
|
||||
</FadeInView>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Expansion arrow */}
|
||||
<FadeInView delay={0.4} className="flex items-center justify-center gap-3 mt-4">
|
||||
<span className="text-xs text-white/30">Starter</span>
|
||||
<ArrowRight className="w-3.5 h-3.5 text-indigo-400/40" />
|
||||
<span className="text-xs text-white/30">Professional</span>
|
||||
<ArrowRight className="w-3.5 h-3.5 text-indigo-400/40" />
|
||||
<span className="text-xs text-white/30">Enterprise</span>
|
||||
<span className="text-sm text-white/20 ml-3">{de ? 'Land & Expand' : 'Land & Expand'}</span>
|
||||
</FadeInView>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user