fix(pitch-deck): all financial slides now read from fp_* tables via useFpKPIs
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m18s
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 34s
CI / test-python-voice (push) Successful in 32s
CI / test-bqas (push) Successful in 32s
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m18s
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 34s
CI / test-python-voice (push) Successful in 32s
CI / test-bqas (push) Successful in 32s
New shared hook: useFpKPIs — loads annual KPIs from fp_guv/liquiditaet/personal/kunden. Replaces useFinancialModel (simplified model) for KPI display on all slides. Slides updated: - CompetitionSlide: "110 Gesetze" → "380+ Regularien & Normen" - BusinessModelSlide: ACV + Gross Margin from fp_* (was useFinancialModel) - ExecutiveSummarySlide: Unternehmensentwicklung from fp_* (was useFinancialModel) - FinancialsSlide: KPI cards from fp_* (ARR, Customers, Break-Even, EBIT 2030) All slides now show consistent numbers from the same source of truth (fp_* tables). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { Language } from '@/lib/types'
|
||||
import { t } from '@/lib/i18n'
|
||||
import ProjectionFooter from '../ui/ProjectionFooter'
|
||||
import { useFinancialModel } from '@/lib/hooks/useFinancialModel'
|
||||
import { useFpKPIs } from '@/lib/hooks/useFpKPIs'
|
||||
import GradientText from '../ui/GradientText'
|
||||
import FadeInView from '../ui/FadeInView'
|
||||
import FinancialChart from '../ui/FinancialChart'
|
||||
@@ -23,9 +24,10 @@ interface FinancialsSlideProps {
|
||||
lang: Language
|
||||
investorId: string | null
|
||||
preferredScenarioId?: string | null
|
||||
isWandeldarlehen?: boolean
|
||||
}
|
||||
|
||||
export default function FinancialsSlide({ lang, investorId, preferredScenarioId }: FinancialsSlideProps) {
|
||||
export default function FinancialsSlide({ lang, investorId, preferredScenarioId, isWandeldarlehen }: FinancialsSlideProps) {
|
||||
const i = t(lang)
|
||||
const fm = useFinancialModel(investorId, preferredScenarioId)
|
||||
const [activeTab, setActiveTab] = useState<FinTab>('overview')
|
||||
@@ -35,6 +37,18 @@ export default function FinancialsSlide({ lang, investorId, preferredScenarioId
|
||||
const summary = activeResults?.summary
|
||||
const lastResult = activeResults?.results[activeResults.results.length - 1]
|
||||
|
||||
// KPI cards from fp_* tables (source of truth)
|
||||
const { last: fpLast, kpis: fpKPIs } = useFpKPIs(isWandeldarlehen)
|
||||
const kpiArr = fpLast?.arr || summary?.final_arr || 0
|
||||
const kpiCustomers = fpLast?.customers || summary?.final_customers || 0
|
||||
const kpiEbit = fpKPIs?.y2029?.ebit // First profitable year
|
||||
const kpiBreakEven = (() => {
|
||||
for (const y of [2026, 2027, 2028, 2029, 2030]) {
|
||||
if ((fpKPIs[`y${y}`]?.ebit || 0) > 0) return y
|
||||
}
|
||||
return 0
|
||||
})()
|
||||
|
||||
// Build scenario color map
|
||||
const scenarioColors: Record<string, string> = {}
|
||||
fm.scenarios.forEach(s => { scenarioColors[s.id] = s.color })
|
||||
@@ -74,9 +88,9 @@ export default function FinancialsSlide({ lang, investorId, preferredScenarioId
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-2 mb-3">
|
||||
<KPICard
|
||||
label={`ARR 2030`}
|
||||
value={summary ? Math.round(summary.final_arr / 1_000_000 * 10) / 10 : 0}
|
||||
suffix=" Mio."
|
||||
decimals={1}
|
||||
value={kpiArr >= 1_000_000 ? Math.round(kpiArr / 1_000_000 * 10) / 10 : Math.round(kpiArr / 1000)}
|
||||
suffix={kpiArr >= 1_000_000 ? ' Mio.' : 'k'}
|
||||
decimals={kpiArr >= 1_000_000 ? 1 : 0}
|
||||
trend="up"
|
||||
color="#6366f1"
|
||||
delay={0.1}
|
||||
@@ -84,28 +98,28 @@ export default function FinancialsSlide({ lang, investorId, preferredScenarioId
|
||||
/>
|
||||
<KPICard
|
||||
label={de ? 'Kunden 2030' : 'Customers 2030'}
|
||||
value={summary?.final_customers || 0}
|
||||
value={kpiCustomers}
|
||||
trend="up"
|
||||
color="#22c55e"
|
||||
delay={0.15}
|
||||
/>
|
||||
<KPICard
|
||||
label="Break-Even"
|
||||
value={summary?.break_even_month || 0}
|
||||
suffix={de ? ' Mo.' : ' mo.'}
|
||||
trend={summary?.break_even_month && summary.break_even_month <= 24 ? 'up' : 'down'}
|
||||
value={kpiBreakEven || 0}
|
||||
trend={kpiBreakEven && kpiBreakEven <= 2029 ? 'up' : 'down'}
|
||||
color="#eab308"
|
||||
delay={0.2}
|
||||
subLabel={summary?.break_even_month ? `~${Math.ceil((summary.break_even_month) / 12) + 2025}` : ''}
|
||||
subLabel=""
|
||||
/>
|
||||
<KPICard
|
||||
label="LTV/CAC"
|
||||
value={summary?.final_ltv_cac || 0}
|
||||
suffix="x"
|
||||
label="EBIT 2030"
|
||||
value={fpLast?.ebit ? Math.round(fpLast.ebit / 1_000_000 * 10) / 10 : 0}
|
||||
suffix=" Mio."
|
||||
decimals={1}
|
||||
trend={(summary?.final_ltv_cac || 0) >= 3 ? 'up' : 'down'}
|
||||
trend={(fpLast?.ebit || 0) > 0 ? 'up' : 'down'}
|
||||
color="#a855f7"
|
||||
delay={0.25}
|
||||
subLabel="EUR"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user