diff --git a/pitch-deck/components/PitchDeck.tsx b/pitch-deck/components/PitchDeck.tsx
index deba086..bbcb751 100644
--- a/pitch-deck/components/PitchDeck.tsx
+++ b/pitch-deck/components/PitchDeck.tsx
@@ -189,7 +189,7 @@ export default function PitchDeck({ lang, onToggleLanguage, investor, onLogout,
case 'financials':
return
case 'the-ask':
- return
+ return
case 'cap-table':
if (isWandeldarlehen) return null
return
diff --git a/pitch-deck/components/slides/TheAskSlide.tsx b/pitch-deck/components/slides/TheAskSlide.tsx
index f108c8c..d8d84bf 100644
--- a/pitch-deck/components/slides/TheAskSlide.tsx
+++ b/pitch-deck/components/slides/TheAskSlide.tsx
@@ -3,6 +3,7 @@
import { motion } from 'framer-motion'
import { Language, PitchFunding } from '@/lib/types'
import { t } from '@/lib/i18n'
+import { useFpKPIs } from '@/lib/hooks/useFpKPIs'
import ProjectionFooter from '../ui/ProjectionFooter'
import GradientText from '../ui/GradientText'
import FadeInView from '../ui/FadeInView'
@@ -14,6 +15,7 @@ import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts'
interface TheAskSlideProps {
lang: Language
funding: PitchFunding
+ isWandeldarlehen?: boolean
}
const COLORS = ['#6366f1', '#a78bfa', '#60a5fa', '#34d399', '#fbbf24']
@@ -39,15 +41,18 @@ function formatTargetDate(dateStr: string, lang: Language): string {
}
}
-export default function TheAskSlide({ lang, funding }: TheAskSlideProps) {
+export default function TheAskSlide({ lang, funding, isWandeldarlehen }: TheAskSlideProps) {
const i = t(lang)
const de = lang === 'de'
- const isWandeldarlehen = (funding?.instrument || '').toLowerCase().includes('wandeldarlehen')
- const rawFunds = funding?.use_of_funds
- const useOfFunds = Array.isArray(rawFunds) ? rawFunds : (typeof rawFunds === 'string' ? JSON.parse(rawFunds) : [])
+ const isWD = isWandeldarlehen || (funding?.instrument || '').toLowerCase() === 'wandeldarlehen'
const amount = Number(funding?.amount_eur) || 0
const { target, suffix } = formatFundingAmount(amount)
- const totalBudget = isWandeldarlehen ? amount * 2 : amount
+ const totalBudget = isWD ? amount * 2 : amount
+
+ // Use of Funds from fp_* data (computed, not manual)
+ const { useOfFunds: fpUseOfFunds } = useFpKPIs(isWD)
+ const rawFunds = fpUseOfFunds.length > 0 ? fpUseOfFunds : (funding?.use_of_funds || [])
+ const useOfFunds = Array.isArray(rawFunds) ? rawFunds : (typeof rawFunds === 'string' ? JSON.parse(rawFunds) : [])
const pieData = useOfFunds.map((item: Record) => ({
name: (de ? item.label_de : item.label_en) as string || 'N/A',
diff --git a/pitch-deck/lib/hooks/useFpKPIs.ts b/pitch-deck/lib/hooks/useFpKPIs.ts
index e7de914..9158971 100644
--- a/pitch-deck/lib/hooks/useFpKPIs.ts
+++ b/pitch-deck/lib/hooks/useFpKPIs.ts
@@ -104,6 +104,72 @@ export function useFpKPIs(isWandeldarlehen?: boolean) {
load()
}, [isWandeldarlehen])
+ // Use of Funds: compute spending breakdown m8-m24 (funding period)
+ const [useOfFunds, setUseOfFunds] = useState>([])
+
+ useEffect(() => {
+ async function loadUoF() {
+ try {
+ const param = isWandeldarlehen ? '?scenarioId=c0000000-0000-0000-0000-000000000200' : ''
+ const [persRes, betriebRes, investRes] = await Promise.all([
+ fetch(`/api/finanzplan/personalkosten${param}`, { cache: 'no-store' }),
+ fetch(`/api/finanzplan/betriebliche${param}`, { cache: 'no-store' }),
+ fetch(`/api/finanzplan/investitionen${param}`, { cache: 'no-store' }),
+ ])
+ const [pers, betrieb, invest] = await Promise.all([persRes.json(), betriebRes.json(), investRes.json()])
+
+ // Sum spending m8-m24
+ const sumRange = (rows: SheetRow[], field: string, m1: number, m2: number) => {
+ let total = 0
+ for (const row of (rows || [])) {
+ const vals = (row as Record)[field] as Record || row.values || {}
+ for (let m = m1; m <= m2; m++) total += vals[`m${m}`] || 0
+ }
+ return total
+ }
+
+ const personalTotal = sumRange(pers.rows || [], 'values_total', 8, 24)
+
+ // Marketing rows from betriebliche
+ const betriebRows: SheetRow[] = betrieb.rows || []
+ const marketingRows = betriebRows.filter((r: SheetRow) =>
+ (r as Record).category === 'marketing' && !(r as Record).is_sum_row
+ )
+ const marketingTotal = sumRange(marketingRows, 'values', 8, 24)
+
+ // All other betriebliche (excl. personal, marketing, abschreibungen, sum rows)
+ const otherBetrieb = betriebRows.filter((r: SheetRow) => {
+ const any = r as Record
+ return any.category !== 'marketing' && any.category !== 'personal' && any.category !== 'abschreibungen' &&
+ !any.is_sum_row && !(r.row_label || '').includes('Summe') && !(r.row_label || '').includes('SUMME')
+ })
+ const operationsTotal = sumRange(otherBetrieb, 'values', 8, 24)
+
+ // Investitionen
+ const investTotal = sumRange(invest.rows || [], 'values_invest', 8, 24)
+
+ const grandTotal = personalTotal + marketingTotal + operationsTotal + investTotal
+ if (grandTotal <= 0) return
+
+ const pctPersonal = Math.round((personalTotal / grandTotal) * 100)
+ const pctMarketing = Math.round((marketingTotal / grandTotal) * 100)
+ const pctOps = Math.round((operationsTotal / grandTotal) * 100)
+ const pctInvest = Math.round((investTotal / grandTotal) * 100)
+ // Adjust rounding to 100%
+ const pctReserve = 100 - pctPersonal - pctMarketing - pctOps - pctInvest
+
+ setUseOfFunds([
+ { category: 'engineering', label_de: 'Engineering & Personal', label_en: 'Engineering & Personnel', percentage: pctPersonal },
+ { category: 'sales', label_de: 'Vertrieb & Marketing', label_en: 'Sales & Marketing', percentage: pctMarketing },
+ { category: 'operations', label_de: 'Betrieb & Infrastruktur', label_en: 'Operations & Infrastructure', percentage: pctOps },
+ { category: 'hardware', label_de: 'Hardware & Ausstattung', label_en: 'Hardware & Equipment', percentage: pctInvest },
+ ...(pctReserve > 0 ? [{ category: 'reserve', label_de: 'Reserve', label_en: 'Reserve', percentage: pctReserve }] : []),
+ ].filter(f => f.percentage > 0))
+ } catch { /* ignore */ }
+ }
+ loadUoF()
+ }, [isWandeldarlehen])
+
const last = kpis.y2030
- return { kpis, loading, last }
+ return { kpis, loading, last, useOfFunds }
}