fix(activity): never rate today's partial day in the activity calendar

Today is shown as in_progress instead of being placed against whole
days, and a running period is compared over its completed days only:
the total through yesterday against the usual rate times the days
completed. The period total and goal progress still count today. The
comparison gains completedDays and completedValue.
This commit is contained in:
Marc-André Bombeck committed 2026-10-21 22:47:07 +02:00
1 parent e482f76508
commit 89b30ebdee
14 files changed
+218 -49

No files matched your search

@@ -58,6 +58,16 @@ function calendar() {
load: null,
});
}
// This morning: a few hundred steps so far.
input.push({
date: today,
steps: 400,
exerciseMinutes: null,
workoutMinutes: 0,
workoutCount: 0,
workoutsBySport: {},
load: null,
});
input.push({
date: "2026-10-05",
steps: 20000,
@@ -113,10 +123,19 @@ describe("ActivityCalendarCard", () => {
state.data = calendar();
const html = render();
expect(html).toContain('data-metric="steps"');
expect(html).toContain("Your usual by this point:");
// A running month is compared through yesterday, not on today.
expect(html).toContain("Through yesterday");
expect(html).toContain("your usual by then");
expect(html).toContain("Running: 1");
});
it("marks today as in progress rather than rating it", () => {
state.data = calendar();
const html = render();
expect(html).toMatch(/data-date="2026-10-21" data-level="in_progress"/);
expect(html).toContain("Today, still in progress");
});
it("shows goal progress and a week tick column", () => {
state.data = calendar();
const html = render();
@@ -41,6 +41,7 @@ type DayLevel = CalendarDay["level"]["steps"];
const LEVEL_BAR: Record<DayLevel, string> = {
none: "bg-transparent",
unrated: "bg-muted-foreground/60",
in_progress: "bg-muted-foreground/30",
low: "bg-chart-2/20",
below: "bg-chart-2/40",
usual: "bg-chart-2/60",
@@ -412,10 +413,13 @@ export function ActivityCalendarCard() {
.filter((m) => data.available[m])
.map((m) => {
const s = data.summary[m];
// Compared over completed days only: today has not ended.
const delta =
s.value !== null && s.usualToDate
? (s.value - s.usualToDate) / s.usualToDate
s.completedValue !== null && s.usualToDate
? (s.completedValue - s.usualToDate) / s.usualToDate
: null;
const running =
data.today >= data.start && data.today <= data.end;
return (
<li
key={m}
@@ -431,11 +435,24 @@ export function ActivityCalendarCard() {
})}
</p>
<p className="text-muted-foreground text-xs">
{s.usualToDate === null
? t("activityCalendar.summary.noUsual")
: t("activityCalendar.summary.usual", {
value: formatMetric(m, s.usualToDate),
})}
{s.usual !== null && s.completedDays === 0
? t("activityCalendar.summary.firstDay")
: s.usualToDate === null
? t("activityCalendar.summary.noUsual")
: running
? t(
"activityCalendar.summary.usualThroughYesterday",
{
value:
s.completedValue === null
? "–"
: formatMetric(m, s.completedValue),
usual: formatMetric(m, s.usualToDate),
},
)
: t("activityCalendar.summary.usual", {
value: formatMetric(m, s.usualToDate),
})}
</p>
</div>
{delta !== null ? (