fix: finanzplan scenario selector — load from API, no hardcoded UUID
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m4s
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 29s
CI / test-python-voice (push) Successful in 27s
CI / test-bqas (push) Successful in 28s

Replaces the FM-name-based 'wandeldarlehen' hack with a proper scenario
picker. Scenarios are fetched from /api/finanzplan, default is selected
automatically. Dropdown appears when multiple scenarios exist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-17 10:56:52 +02:00
parent 27ef21a4f0
commit 11fa490599

View File

@@ -61,8 +61,12 @@ function formatCell(v: number | undefined): string {
return Math.round(v).toLocaleString('de-DE', { maximumFractionDigits: 0 }) return Math.round(v).toLocaleString('de-DE', { maximumFractionDigits: 0 })
} }
interface FpScenario { id: string; name: string; is_default: boolean }
export default function FinanzplanSlide({ lang, investorId, preferredScenarioId }: FinanzplanSlideProps) { export default function FinanzplanSlide({ lang, investorId, preferredScenarioId }: FinanzplanSlideProps) {
const [sheets, setSheets] = useState<SheetMeta[]>([]) const [sheets, setSheets] = useState<SheetMeta[]>([])
const [scenarios, setScenarios] = useState<FpScenario[]>([])
const [selectedScenarioId, setSelectedScenarioId] = useState<string>('')
const [activeSheet, setActiveSheet] = useState<string>('personalkosten') const [activeSheet, setActiveSheet] = useState<string>('personalkosten')
const [rows, setRows] = useState<SheetRow[]>([]) const [rows, setRows] = useState<SheetRow[]>([])
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
@@ -77,19 +81,26 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId
[fm.activeResults], [fm.activeResults],
) )
// Determine fp_scenario_id from the active FM scenario name // Load sheet list + scenarios
const fpScenarioParam = fm.activeScenario?.name?.toLowerCase().includes('wandeldarlehen')
? '?scenarioId=c0000000-0000-0000-0000-000000000200'
: ''
// Load sheet list
useEffect(() => { useEffect(() => {
fetch('/api/finanzplan', { cache: 'no-store' }) fetch('/api/finanzplan', { cache: 'no-store' })
.then(r => r.json()) .then(r => r.json())
.then(data => setSheets(data.sheets || [])) .then(data => {
setSheets(data.sheets || [])
const scens: FpScenario[] = data.scenarios || []
setScenarios(scens)
// Pick default scenario on first load
if (!selectedScenarioId) {
const def = scens.find(s => s.is_default) ?? scens[0]
if (def) setSelectedScenarioId(def.id)
}
})
.catch(() => {}) .catch(() => {})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []) }, [])
const scenarioParam = selectedScenarioId ? `?scenarioId=${selectedScenarioId}` : ''
// Load sheet data // Load sheet data
const loadSheet = useCallback(async (name: string) => { const loadSheet = useCallback(async (name: string) => {
if (name === 'kpis' || name === 'charts') { if (name === 'kpis' || name === 'charts') {
@@ -99,12 +110,12 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId
} }
setLoading(true) setLoading(true)
try { try {
const r = await fetch(`/api/finanzplan/${name}${fpScenarioParam}`, { cache: 'no-store' }) const r = await fetch(`/api/finanzplan/${name}${scenarioParam}`, { cache: 'no-store' })
const data = await r.json() const data = await r.json()
setRows(data.rows || []) setRows(data.rows || [])
} catch { /* ignore */ } } catch { /* ignore */ }
setLoading(false) setLoading(false)
}, [fpScenarioParam]) }, [scenarioParam])
useEffect(() => { loadSheet(activeSheet) }, [activeSheet, loadSheet]) useEffect(() => { loadSheet(activeSheet) }, [activeSheet, loadSheet])
@@ -112,7 +123,7 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId
const handleCompute = async () => { const handleCompute = async () => {
setComputing(true) setComputing(true)
try { try {
await fetch('/api/finanzplan/compute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' }) await fetch('/api/finanzplan/compute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ scenarioId: selectedScenarioId || undefined }) })
await loadSheet(activeSheet) await loadSheet(activeSheet)
} catch { /* ignore */ } } catch { /* ignore */ }
setComputing(false) setComputing(false)
@@ -182,6 +193,17 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId
</button> </button>
))} ))}
<div className="flex-1" /> <div className="flex-1" />
{scenarios.length > 1 && (
<select
value={selectedScenarioId}
onChange={e => setSelectedScenarioId(e.target.value)}
className="text-[10px] bg-white/[0.06] text-white/60 border border-white/10 rounded-lg px-2 py-1.5 mr-2"
>
{scenarios.map(s => (
<option key={s.id} value={s.id}>{s.name}{s.is_default ? ' ★' : ''}</option>
))}
</select>
)}
<button <button
onClick={handleCompute} onClick={handleCompute}
disabled={computing} disabled={computing}