V3.8
This commit is contained in:
+29
-8
@@ -140,8 +140,7 @@ function annualForecast(data, accountId = 'all') {
|
||||
|
||||
function categoryStats(data, accountId = 'all') {
|
||||
const categoryMap = new Map((data.categories || []).map(c => [c.id, c.name]));
|
||||
const filteredEntries = items => accountId === 'all' ? items : items.filter(x => x.accountId === accountId);
|
||||
const filteredTransfers = items => accountId === 'all' ? items : items.filter(x => x.fromAccountId === accountId || x.toAccountId === accountId);
|
||||
const isAll = accountId === 'all';
|
||||
const aggregate = items => {
|
||||
const buckets = new Map();
|
||||
for (const item of items) {
|
||||
@@ -156,10 +155,32 @@ function categoryStats(data, accountId = 'all') {
|
||||
const rows = [...buckets.values()].sort((a,b)=>b.amount-a.amount).map(x=>({...x,percent:total>0?(x.amount/total)*100:0}));
|
||||
return { total, rows };
|
||||
};
|
||||
|
||||
if (isAll) {
|
||||
return {
|
||||
incomes: aggregate(filteredEntries(data.incomes)),
|
||||
expenses: aggregate(filteredEntries(data.expenses)),
|
||||
transfers: aggregate(filteredTransfers(data.transfers)),
|
||||
incomes: aggregate(data.incomes),
|
||||
expenses: aggregate(data.expenses),
|
||||
transfers: aggregate(data.transfers),
|
||||
transfersMerged: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Bei einer Einzelkonto-Auswertung sind Transfers echte Zu-/Abflüsse
|
||||
// dieses Kontos: Zielkonto = Eingang, Quellkonto = Ausgang.
|
||||
const incomeItems = [
|
||||
...data.incomes.filter(x => x.accountId === accountId),
|
||||
...data.transfers.filter(x => x.toAccountId === accountId),
|
||||
];
|
||||
const expenseItems = [
|
||||
...data.expenses.filter(x => x.accountId === accountId),
|
||||
...data.transfers.filter(x => x.fromAccountId === accountId),
|
||||
];
|
||||
|
||||
return {
|
||||
incomes: aggregate(incomeItems),
|
||||
expenses: aggregate(expenseItems),
|
||||
transfers: { total:0, rows:[] },
|
||||
transfersMerged: true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -231,9 +252,9 @@ function StatisticsPage({data,onAddCategory,onEditCategory,onDeleteCategory}){
|
||||
return <div className="content-stack stats-page">
|
||||
<section className="year-account-filter stats-filter"><div className="year-filter-copy"><span>Statistik für</span><strong>{selectedName}</strong></div><label><span>Konto auswählen</span><select value={accountId} onChange={e=>setAccountId(e.target.value)}><option value="all">Alle Konten</option>{data.accounts.map(a=><option key={a.id} value={a.id}>{a.name}</option>)}</select></label></section>
|
||||
<section className="summary-grid stats-summary"><Metric label="Eingänge Ø / Monat" value={stats.incomes.total} positive/><Metric label="Ausgänge Ø / Monat" value={stats.expenses.total} negative/><CountMetric label="Kategorien" value={data.categories.length}/><CountMetric label="Ohne Kategorie" value={uncategorized}/></section>
|
||||
<CategoryDistribution title="Ausgaben nach Kategorien" subtitle="Verteilung auf Basis des durchschnittlichen Monatswerts. Periodische Ausgaben werden heruntergerechnet." stats={stats.expenses} tone="expense"/>
|
||||
<CategoryDistribution title="Eingänge nach Kategorien" subtitle="Verteilung der regelmäßigen Eingänge auf Kategorien, ebenfalls als Monatsdurchschnitt." stats={stats.incomes} tone="income"/>
|
||||
<CategoryDistribution title="Transfers nach Kategorien" subtitle="Interne Verschiebungen separat nach Kategorien. Sie verändern den Gesamtsaldo weiterhin nicht." stats={stats.transfers} tone="transfer"/>
|
||||
<CategoryDistribution title="Ausgaben nach Kategorien" subtitle={stats.transfersMerged?'Ausgaben dieses Kontos inklusive ausgehender Transfers, jeweils als Monatsdurchschnitt.':'Verteilung auf Basis des durchschnittlichen Monatswerts. Periodische Ausgaben werden heruntergerechnet.'} stats={stats.expenses} tone="expense"/>
|
||||
<CategoryDistribution title="Eingänge nach Kategorien" subtitle={stats.transfersMerged?'Eingänge dieses Kontos inklusive eingehender Transfers, jeweils als Monatsdurchschnitt.':'Verteilung der regelmäßigen Eingänge auf Kategorien, ebenfalls als Monatsdurchschnitt.'} stats={stats.incomes} tone="income"/>
|
||||
{!stats.transfersMerged&&<CategoryDistribution title="Transfers nach Kategorien" subtitle="Interne Verschiebungen separat nach Kategorien. Sie verändern den Gesamtsaldo weiterhin nicht." stats={stats.transfers} tone="transfer"/>}
|
||||
<section className="panel"><div className="section-head"><div><h2>Kategorien verwalten</h2><p>Kategorien gelten für Eingänge, Ausgänge und Transfers gemeinsam.</p></div><button className="secondary" onClick={onAddCategory}>+ Kategorie</button></div>{data.categories.length===0?<Empty text="Noch keine Kategorien angelegt."/>:<div className="category-manager-list">{data.categories.map(c=><div className="category-manager-row" key={c.id}><div><strong>{c.name}</strong><span>{usage(c.id)} {usage(c.id)===1?'zugeordneter Eintrag':'zugeordnete Einträge'}</span></div><div className="actions"><button onClick={()=>onEditCategory(c)}>Bearbeiten</button><button className="danger" onClick={()=>onDeleteCategory(c.id)}>Löschen</button></div></div>)}</div>}</section>
|
||||
</div>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user