fix minor dash
This commit is contained in:
@@ -171,30 +171,27 @@
|
||||
function todayPotentialFor(memberId: string) {
|
||||
return assigned.filter((a: any) => a.memberId === memberId && a.frequency === 'daily').length;
|
||||
}
|
||||
// Max points a full "all daily chores done" day is worth for a member.
|
||||
function dailyPointsPotential(memberId: string) {
|
||||
return assigned
|
||||
.filter((a: any) => a.memberId === memberId && a.frequency === 'daily')
|
||||
.reduce((sum: number, a: any) => sum + (a.type === 'points' ? Number(a.value) || 0 : 0), 0);
|
||||
}
|
||||
// All-time average daily points for a member, from the server-computed
|
||||
// weekly series (all history, not just this week). Days active runs from
|
||||
// their earliest recorded week through today (min 1).
|
||||
function avgDailyPointsFor(memberId: string): number {
|
||||
// All-time completion rate for a member: all chores ever done ÷ (current
|
||||
// weekly potential × weeks active). Bounded and meaningful, unlike the old
|
||||
// points-per-day average (bonus points + weeklies done in one day could
|
||||
// push it past a "perfect day" — e.g. Jethro's 100%).
|
||||
function overallRateFor(memberId: string): { done: number; total: number; pct: number } {
|
||||
const line = trend.find((m: any) => m.memberId === memberId);
|
||||
const weeks = line?.weeks || [];
|
||||
if (weeks.length === 0) return 0;
|
||||
const total = weeks.reduce((sum: number, w: any) => sum + (Number(w.points) || 0), 0);
|
||||
const done = weeks.reduce((sum: number, w: any) => sum + (Number(w.chores) || 0), 0);
|
||||
const potential = weeklyPotentialFor(memberId);
|
||||
if (weeks.length === 0 || potential <= 0) return { done, total: 0, pct: 0 };
|
||||
const earliest = weeks.map((w: any) => w.weekStart).sort()[0];
|
||||
const today = todayInTz(famTz);
|
||||
const days = Math.max(
|
||||
const weeksActive = Math.max(
|
||||
1,
|
||||
Math.round(
|
||||
Math.floor(
|
||||
(new Date(today + 'T00:00:00').getTime() - new Date(earliest + 'T00:00:00').getTime()) /
|
||||
86400000
|
||||
(7 * 86400000)
|
||||
) + 1
|
||||
);
|
||||
return total / days;
|
||||
const total = potential * weeksActive;
|
||||
return { done, total, pct: Math.min(100, Math.round((done / total) * 100)) };
|
||||
}
|
||||
// Today's completion count — tolerant of UTC vs fam-local date keys.
|
||||
function todayDone(s: any): number {
|
||||
@@ -277,10 +274,11 @@
|
||||
}
|
||||
const scoreCanvas = donutCanvases[`${s.memberId}:score`];
|
||||
if (scoreCanvas) {
|
||||
const overall = overallRateFor(s.memberId);
|
||||
donutCharts[`${s.memberId}:score`] = makeDonut(
|
||||
scoreCanvas,
|
||||
avgDailyPointsFor(s.memberId),
|
||||
dailyPointsPotential(s.memberId),
|
||||
overall.done,
|
||||
overall.total,
|
||||
s.memberColor
|
||||
);
|
||||
}
|
||||
@@ -413,9 +411,7 @@
|
||||
{@const tdTotal = todayPotentialFor(s.memberId)}
|
||||
{@const tdDone = todayDone(s)}
|
||||
{@const tdPct = tdTotal > 0 ? Math.min(100, Math.round((tdDone / tdTotal) * 100)) : 0}
|
||||
{@const scPot = dailyPointsPotential(s.memberId)}
|
||||
{@const scVal = avgDailyPointsFor(s.memberId)}
|
||||
{@const scPct = scPot > 0 ? Math.min(100, Math.round((scVal / scPot) * 100)) : 0}
|
||||
{@const sc = overallRateFor(s.memberId)}
|
||||
{@const goals = goalsByMember.get(s.memberId)}
|
||||
<div class="column col-member" style="--mc: {s.memberColor}">
|
||||
<div class="member-head">
|
||||
@@ -438,8 +434,8 @@
|
||||
</div>
|
||||
<div class="donut-wrap">
|
||||
<canvas use:captureCanvas={`${s.memberId}:score`} height="100" width="100"></canvas>
|
||||
<div class="donut-center" style="color:{s.memberColor}">{scPct}%</div>
|
||||
<span class="donut-label">Avg/day</span>
|
||||
<div class="donut-center" style="color:{s.memberColor}">{sc.pct}%</div>
|
||||
<span class="donut-label">Overall</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="member-stats">
|
||||
|
||||
Reference in New Issue
Block a user