feat(pitch-deck): collapsible year view in Finanzplan + remove section labels
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m6s
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 30s
CI / test-python-voice (push) Successful in 31s
CI / test-bqas (push) Successful in 31s
All checks were successful
Build pitch-deck / build-push-deploy (push) Successful in 1m6s
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 30s
CI / test-python-voice (push) Successful in 31s
CI / test-bqas (push) Successful in 31s
- Year navigation: "Alle Jahre" shows 5 annual columns, individual years show 12 months - Default starts at single year view - Annual view: flow rows show yearly sum, balance rows show Dec value - Removed [section] labels from row display - Footer sum only shown in monthly view (not annual) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -500,18 +500,24 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId,
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Year Navigation — not for GuV, KPIs, Charts (annual views) */}
|
{/* Year Navigation — not for GuV, KPIs, Charts */}
|
||||||
{!['guv', 'kpis', 'charts'].includes(activeSheet) && (
|
{!['guv', 'kpis', 'charts'].includes(activeSheet) && (
|
||||||
<div className="flex items-center justify-center gap-4 mb-2">
|
<div className="flex items-center justify-center gap-1 mb-2">
|
||||||
<button onClick={() => setYearOffset(Math.max(0, yearOffset - 1))} disabled={yearOffset === 0}
|
<button
|
||||||
className="p-1 text-white/40 hover:text-white/70 disabled:opacity-20">
|
onClick={() => setYearOffset(-1)}
|
||||||
<ChevronLeft className="w-4 h-4" />
|
className={`px-3 py-1 text-[10px] font-medium rounded-lg transition-colors ${yearOffset === -1 ? 'bg-indigo-500/20 text-indigo-300 border border-indigo-500/30' : 'text-white/40 hover:text-white/70 hover:bg-white/[0.05]'}`}
|
||||||
|
>
|
||||||
|
{de ? 'Alle Jahre' : 'All Years'}
|
||||||
</button>
|
</button>
|
||||||
<span className="text-sm font-bold text-white">{currentYear}</span>
|
{[2026, 2027, 2028, 2029, 2030].map((y, idx) => (
|
||||||
<button onClick={() => setYearOffset(Math.min(4, yearOffset + 1))} disabled={yearOffset === 4}
|
<button
|
||||||
className="p-1 text-white/40 hover:text-white/70 disabled:opacity-20">
|
key={y}
|
||||||
<ChevronRight className="w-4 h-4" />
|
onClick={() => setYearOffset(idx)}
|
||||||
|
className={`px-3 py-1 text-[10px] font-medium rounded-lg transition-colors ${yearOffset === idx ? 'bg-indigo-500/20 text-indigo-300 border border-indigo-500/30' : 'text-white/40 hover:text-white/70 hover:bg-white/[0.05]'}`}
|
||||||
|
>
|
||||||
|
{y}
|
||||||
</button>
|
</button>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -558,13 +564,20 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId,
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
) : (
|
) : (
|
||||||
/* === Monthly Grid (all other sheets) === */
|
/* === Monthly/Annual Grid (all other sheets) === */
|
||||||
<table className="w-full text-[10px]">
|
<table className="w-full text-[10px]">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-white/10">
|
<tr className="border-b border-white/10">
|
||||||
<th className="text-left py-1.5 px-2 text-white/60 font-medium sticky left-0 bg-slate-900/90 backdrop-blur min-w-[160px]">
|
<th className="text-left py-1.5 px-2 text-white/60 font-medium sticky left-0 bg-slate-900/90 backdrop-blur min-w-[160px]">
|
||||||
{de ? 'Position' : 'Item'}
|
{de ? 'Position' : 'Item'}
|
||||||
</th>
|
</th>
|
||||||
|
{yearOffset === -1 ? (
|
||||||
|
// All years view
|
||||||
|
[2026, 2027, 2028, 2029, 2030].map(y => (
|
||||||
|
<th key={y} className="text-right py-1.5 px-3 text-white/60 font-medium min-w-[80px]">{y}</th>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<th className="text-right py-1.5 px-2 text-white/60 font-medium min-w-[70px]">
|
<th className="text-right py-1.5 px-2 text-white/60 font-medium min-w-[70px]">
|
||||||
{currentYear}
|
{currentYear}
|
||||||
</th>
|
</th>
|
||||||
@@ -573,6 +586,8 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId,
|
|||||||
{label}
|
{label}
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -668,16 +683,35 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId,
|
|||||||
{isEditable && <span className="w-1 h-1 rounded-full bg-indigo-400 flex-shrink-0" />}
|
{isEditable && <span className="w-1 h-1 rounded-full bg-indigo-400 flex-shrink-0" />}
|
||||||
<span className="truncate"><LabelWithTooltip label={label} /></span>
|
<span className="truncate"><LabelWithTooltip label={label} /></span>
|
||||||
{row.position && <span className="text-white/50 ml-1">({row.position})</span>}
|
{row.position && <span className="text-white/50 ml-1">({row.position})</span>}
|
||||||
{row.section && <span className="text-white/50 ml-1">[{row.section}]</span>}
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
{yearOffset === -1 ? (
|
||||||
|
// All years view: show annual values per year
|
||||||
|
[2026, 2027, 2028, 2029, 2030].map(y => {
|
||||||
|
const yStart = (y - 2026) * 12 + 1
|
||||||
|
const yEnd = yStart + 11
|
||||||
|
let yVal = 0
|
||||||
|
if (isUnitPrice) {
|
||||||
|
yVal = values[`m${yEnd}`] || 0
|
||||||
|
} else if (isBalanceRow) {
|
||||||
|
yVal = values[`m${yEnd}`] || 0
|
||||||
|
} else {
|
||||||
|
for (let m = yStart; m <= yEnd; m++) yVal += values[`m${m}`] || 0
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<td key={y} className={`text-right py-1 px-3 ${yVal < 0 ? 'text-red-400' : yVal > 0 ? (isSumRow ? 'text-white/80' : 'text-white/50') : 'text-white/15'} ${isSumRow ? 'font-bold' : ''}`}>
|
||||||
|
{formatCell(Math.round(yVal))}
|
||||||
|
</td>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<td className={`text-right py-1 px-2 font-medium ${annual < 0 ? 'text-red-400' : isSumRow ? 'text-white/80' : 'text-white/50'}`}>
|
<td className={`text-right py-1 px-2 font-medium ${annual < 0 ? 'text-red-400' : isSumRow ? 'text-white/80' : 'text-white/50'}`}>
|
||||||
{formatCell(annual)}
|
{formatCell(annual)}
|
||||||
</td>
|
</td>
|
||||||
{Array.from({ length: 12 }, (_, idx) => {
|
{Array.from({ length: 12 }, (_, idx) => {
|
||||||
const mKey = `m${monthStart + idx}`
|
const mKey = `m${monthStart + idx}`
|
||||||
const v = values[mKey] || 0
|
const v = values[mKey] || 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<td
|
<td
|
||||||
key={idx}
|
key={idx}
|
||||||
@@ -694,13 +728,14 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId,
|
|||||||
</td>
|
</td>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</tr>
|
</tr>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
{/* Summenzeile für relevante Sheets */}
|
{/* Summenzeile für relevante Sheets */}
|
||||||
{['personalkosten', 'betriebliche', 'investitionen', 'sonst_ertraege'].includes(activeSheet) && rows.length > 0 && (() => {
|
{yearOffset !== -1 && ['personalkosten', 'betriebliche', 'investitionen'].includes(activeSheet) && rows.length > 0 && (() => {
|
||||||
// Berechne Summe über alle Zeilen die keine Summenzeilen sind
|
|
||||||
const sumValues: Record<string, number> = {}
|
const sumValues: Record<string, number> = {}
|
||||||
let sumAnnual = 0
|
let sumAnnual = 0
|
||||||
const nonSumRows = rows.filter(r => {
|
const nonSumRows = rows.filter(r => {
|
||||||
@@ -724,10 +759,7 @@ export default function FinanzplanSlide({ lang, investorId, preferredScenarioId,
|
|||||||
{de ? 'SUMME' : 'TOTAL'}
|
{de ? 'SUMME' : 'TOTAL'}
|
||||||
</td>
|
</td>
|
||||||
<td className={`text-right py-1.5 px-2 font-bold text-xs ${sumAnnual < 0 ? 'text-red-400' : 'text-white/80'}`}>
|
<td className={`text-right py-1.5 px-2 font-bold text-xs ${sumAnnual < 0 ? 'text-red-400' : 'text-white/80'}`}>
|
||||||
{['kunden', 'kunden_summary'].includes(activeSheet)
|
{formatCell(sumAnnual)}
|
||||||
? formatCell(sumValues[`m${monthEnd}`] || 0)
|
|
||||||
: formatCell(sumAnnual)
|
|
||||||
}
|
|
||||||
</td>
|
</td>
|
||||||
{Array.from({ length: 12 }, (_, idx) => {
|
{Array.from({ length: 12 }, (_, idx) => {
|
||||||
const mKey = `m${monthStart + idx}`
|
const mKey = `m${monthStart + idx}`
|
||||||
|
|||||||
Reference in New Issue
Block a user