update stats
This commit is contained in:
@@ -107,6 +107,39 @@
|
||||
}
|
||||
return map;
|
||||
});
|
||||
// ─── All-time per-member stats ───
|
||||
let allTimeByMember = $derived.by(() => {
|
||||
const map = new Map<string, { points: number; cash: number; chores: number }>();
|
||||
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<string, { count: number; names: string[] }>();
|
||||
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<string, number>();
|
||||
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)}
|
||||
<div class="column col-member" style="--mc: {s.memberColor}">
|
||||
<div class="member-head">
|
||||
<span class="dot" style="background:{s.memberColor}"></span>
|
||||
@@ -438,30 +473,54 @@
|
||||
<span class="donut-label">Overall</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="member-stats">
|
||||
<div class="stat-row">
|
||||
<span class="stat-lbl">Points</span>
|
||||
<span class="stat-val pts">{s.pointsEarned}</span>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-lbl">Cash</span>
|
||||
<span class="stat-val cash">£{Number(s.moneyEarned || 0).toFixed(2)}</span>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<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 class="stat-row">
|
||||
<span class="stat-lbl">Pocket Money</span>
|
||||
<span class="stat-val pm">{pocketMoneyByMember.get(s.memberId) ?? 0}</span>
|
||||
</div>
|
||||
<div class="member-stats">
|
||||
<div class="stat-group-lbl">This week</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-lbl">Points</span>
|
||||
<span class="stat-val pts">{s.pointsEarned}</span>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-lbl">Cash</span>
|
||||
<span class="stat-val cash">£{Number(s.moneyEarned || 0).toFixed(2)}</span>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<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 class="stat-row">
|
||||
<span class="stat-lbl">Pocket Money</span>
|
||||
<span class="stat-val pm">{pocketMoneyByMember.get(s.memberId) ?? 0}</span>
|
||||
</div>
|
||||
<div class="stat-group-lbl">All time</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-lbl">Points</span>
|
||||
<span class="stat-val pts">{at?.points ?? s.pointsEarned}</span>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-lbl">Cash</span>
|
||||
<span class="stat-val cash">£{Number(at?.cash ?? s.moneyEarned ?? 0).toFixed(2)}</span>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-lbl">Done</span>
|
||||
<span class="stat-val">{sc.done}/{sc.total}</span>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-lbl">Goals 🎉</span>
|
||||
<span class="stat-val goals" title={goalsAll?.names.join(' · ')}
|
||||
>{goalsAll?.count ?? 0}</span
|
||||
>
|
||||
</div>
|
||||
<div class="stat-row">
|
||||
<span class="stat-lbl">Pocket Money</span>
|
||||
<span class="stat-val pm">{pocketMoneyAllTimeByMember.get(s.memberId) ?? 0}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user