update stats
This commit is contained in:
@@ -107,6 +107,39 @@
|
|||||||
}
|
}
|
||||||
return map;
|
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. ───
|
// ─── Trend chart window: show current month, expand a month at a time up to 3. ───
|
||||||
let trend = $derived.by(() => {
|
let trend = $derived.by(() => {
|
||||||
@@ -413,6 +446,8 @@
|
|||||||
{@const tdPct = tdTotal > 0 ? Math.min(100, Math.round((tdDone / tdTotal) * 100)) : 0}
|
{@const tdPct = tdTotal > 0 ? Math.min(100, Math.round((tdDone / tdTotal) * 100)) : 0}
|
||||||
{@const sc = overallRateFor(s.memberId)}
|
{@const sc = overallRateFor(s.memberId)}
|
||||||
{@const goals = goalsByMember.get(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="column col-member" style="--mc: {s.memberColor}">
|
||||||
<div class="member-head">
|
<div class="member-head">
|
||||||
<span class="dot" style="background:{s.memberColor}"></span>
|
<span class="dot" style="background:{s.memberColor}"></span>
|
||||||
@@ -438,30 +473,54 @@
|
|||||||
<span class="donut-label">Overall</span>
|
<span class="donut-label">Overall</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="member-stats">
|
<div class="member-stats">
|
||||||
<div class="stat-row">
|
<div class="stat-group-lbl">This week</div>
|
||||||
<span class="stat-lbl">Points</span>
|
<div class="stat-row">
|
||||||
<span class="stat-val pts">{s.pointsEarned}</span>
|
<span class="stat-lbl">Points</span>
|
||||||
</div>
|
<span class="stat-val pts">{s.pointsEarned}</span>
|
||||||
<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>
|
</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>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
@@ -766,6 +825,17 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 0.8rem;
|
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 {
|
.stat-lbl {
|
||||||
color: #6b7280;
|
color: #6b7280;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|||||||
Reference in New Issue
Block a user