diff --git a/frontend/src/routes/[fam]/+page.svelte b/frontend/src/routes/[fam]/+page.svelte index 8a6c630..21b2667 100644 --- a/frontend/src/routes/[fam]/+page.svelte +++ b/frontend/src/routes/[fam]/+page.svelte @@ -107,6 +107,39 @@ } return map; }); + // ─── All-time per-member stats ─── + let allTimeByMember = $derived.by(() => { + const map = new Map(); + for (const m of trend as any[]) { + const pts = (m.weeks || []).reduce((s: number, w: any) => s + (Number(w.points) || 0), 0); + const cash = (m.weeks || []).reduce((s: number, w: any) => s + (Number(w.cash) || 0), 0); + const chores = (m.weeks || []).reduce((s: number, w: any) => s + (Number(w.chores) || 0), 0); + map.set(m.memberId, { points: pts, cash, chores }); + } + return map; + }); + let goalsAllTimeByMember = $derived.by(() => { + const pmIds = new Set(bonusConfigs.filter((c: any) => c.isPocketMoney).map((c: any) => c.id)); + const map = new Map(); + for (const r of rewards as any[]) { + if (!r.bonusConfigId || pmIds.has(r.bonusConfigId)) continue; + const cfg = bonusConfigs.find((c: any) => c.id === r.bonusConfigId); + const entry = map.get(r.memberId) || { count: 0, names: [] }; + entry.count++; + if (cfg?.name && !entry.names.includes(cfg.name)) entry.names.push(cfg.name); + map.set(r.memberId, entry); + } + return map; + }); + let pocketMoneyAllTimeByMember = $derived.by(() => { + const pmIds = new Set(bonusConfigs.filter((c: any) => c.isPocketMoney).map((c: any) => c.id)); + const map = new Map(); + for (const r of rewards as any[]) { + if (!r.bonusConfigId || !pmIds.has(r.bonusConfigId)) continue; + map.set(r.memberId, (map.get(r.memberId) || 0) + 1); + } + return map; + }); // ─── Trend chart window: show current month, expand a month at a time up to 3. ─── let trend = $derived.by(() => { @@ -413,6 +446,8 @@ {@const tdPct = tdTotal > 0 ? Math.min(100, Math.round((tdDone / tdTotal) * 100)) : 0} {@const sc = overallRateFor(s.memberId)} {@const goals = goalsByMember.get(s.memberId)} + {@const goalsAll = goalsAllTimeByMember.get(s.memberId)} + {@const at = allTimeByMember.get(s.memberId)}
@@ -438,30 +473,54 @@ Overall
-
-
- Points - {s.pointsEarned} -
-
- Cash - £{Number(s.moneyEarned || 0).toFixed(2)} -
-
- Done - {wkDone}/{wkTotal} -
-
- Goals 🎉 - {goals?.count ?? 0} -
-
- Pocket Money - {pocketMoneyByMember.get(s.memberId) ?? 0} -
+
+
This week
+
+ Points + {s.pointsEarned}
+
+ Cash + £{Number(s.moneyEarned || 0).toFixed(2)} +
+
+ Done + {wkDone}/{wkTotal} +
+
+ Goals 🎉 + {goals?.count ?? 0} +
+
+ Pocket Money + {pocketMoneyByMember.get(s.memberId) ?? 0} +
+
All time
+
+ Points + {at?.points ?? s.pointsEarned} +
+
+ Cash + £{Number(at?.cash ?? s.moneyEarned ?? 0).toFixed(2)} +
+
+ Done + {sc.done}/{sc.total} +
+
+ Goals 🎉 + {goalsAll?.count ?? 0} +
+
+ Pocket Money + {pocketMoneyAllTimeByMember.get(s.memberId) ?? 0} +
+
{/each} @@ -766,6 +825,17 @@ align-items: center; font-size: 0.8rem; } + .stat-group-lbl { + font-size: 0.65rem; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.07em; + color: #9ca3af; + margin-top: 0.35rem; + } + .stat-group-lbl:first-child { + margin-top: 0; + } .stat-lbl { color: #6b7280; font-weight: 500;