clean pass update with rewards and completions

This commit is contained in:
JCEEE
2026-09-09 19:02:29 +01:00
parent 9d7915eb60
commit 3f95d50d2e
6 changed files with 1126 additions and 590 deletions
+33
View File
@@ -4,6 +4,7 @@
import { Chart, registerables } from 'chart.js';
import { ViewHeader, CardGrid, Card } from '$lib/components';
import { formatDDMMYY } from '$lib/format';
import { famStore } from '$lib/stores/fam.svelte';
import { handleOf } from '@shared/slugify';
import { addDaysStr, resolveTz, todayInTz } from '@shared/timezone';
@@ -54,6 +55,28 @@
let allTimeCash = $derived(Number(stats.allTimeCash) || 0);
let allTimeChores = $derived(Number(stats.allTimeChores) || 0);
// ─── Goals completed (rewards from bonus configs, pocket money excluded) ───
// Derived from famStore so realtime updates (a goal met / revoked) flow in.
let rewards = $derived(famStore.initialized ? famStore.rewards : data.rewards || []);
let bonusConfigs = $derived(
famStore.initialized ? famStore.bonusConfigs : data.bonusConfigs || []
);
let goalsByMember = $derived.by(() => {
const ws = (summary?.weekStart as string) || todayInTz(famTz);
const pmIds = new Set(bonusConfigs.filter((c: any) => c.isPocketMoney).map((c: any) => c.id));
const map = new Map<string, { count: number; names: string[] }>();
for (const r of rewards as any[]) {
if (!r.bonusConfigId || pmIds.has(r.bonusConfigId)) continue;
if ((r.date || '').slice(0, 10) < ws) 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;
});
// ─── Trend chart window: show current month, expand a month at a time up to 3. ───
let trend = $derived.by(() => {
const series = Array.isArray(stats.series) ? stats.series : [];
@@ -340,6 +363,7 @@
{@const scPot = dailyPointsPotential(s.memberId)}
{@const scVal = avgDailyPointsFor(s)}
{@const scPct = scPot > 0 ? Math.min(100, Math.round((scVal / scPot) * 100)) : 0}
{@const goals = goalsByMember.get(s.memberId)}
<div class="column col-member">
<div class="member-head">
<span class="dot" style="background:{s.memberColor}"></span>
@@ -378,6 +402,12 @@
<span class="stat-lbl">Done</span>
<span class="stat-val">{wkDone}/{wkTotal}</span>
</div>
<div class="stat-row">
<span class="stat-lbl">Goals 🎉</span>
<span class="stat-val goals" title={goals?.names.join(' · ')}
>{goals?.count ?? 0}</span
>
</div>
</div>
</div>
{/each}
@@ -656,6 +686,9 @@
.stat-val.cash {
color: #059669;
}
.stat-val.goals {
color: #059669;
}
/* ── Chart ── */
.chart-wrap {