mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 15:02:04 +00:00
fix(charts): end the mood and intake heatmaps on the user's today
Both heatmaps stepped back from now in 24-hour strides and cut each key in UTC, so in the evening west of UTC, or the morning east of it, the newest cell was a different day from the one the server keyed the readings on. The days now come from today's key in the user's display zone, stepped on keys.
This commit is contained in:
1 parent
73e0653b2c
commit
a1d94a33ed
4 files changed
+94
-41
No files matched your search
@@ -0,0 +1,35 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { heatmapDays } from "../heatmap-days";
|
||||
|
||||
describe("heatmapDays", () => {
|
||||
it.each([
|
||||
// 20:30 in New York is already the next UTC day.
|
||||
["America/New_York", "2026-03-09T00:30:00.000Z", "2026-03-08"],
|
||||
// 08:00 in Auckland and Tonga is still the previous UTC day.
|
||||
["Pacific/Auckland", "2026-04-04T20:00:00.000Z", "2026-04-05"],
|
||||
["Pacific/Tongatapu", "2026-07-27T19:00:00.000Z", "2026-07-28"],
|
||||
["America/Santiago", "2026-09-06T03:30:00.000Z", "2026-09-05"],
|
||||
["Europe/Berlin", "2026-10-25T22:30:00.000Z", "2026-10-25"],
|
||||
])("ends on today's key in %s", (tz, iso, today) => {
|
||||
const days = heatmapDays(new Date(iso), tz, 14);
|
||||
expect(days).toHaveLength(14);
|
||||
expect(days.at(-1)?.dateKey).toBe(today);
|
||||
// Consecutive keys, one per day, no gap or repeat across DST.
|
||||
for (let i = 1; i < days.length; i++) {
|
||||
const prev = Date.parse(`${days[i - 1].dateKey}T00:00:00Z`);
|
||||
const cur = Date.parse(`${days[i].dateKey}T00:00:00Z`);
|
||||
expect(cur - prev).toBe(86_400_000);
|
||||
}
|
||||
});
|
||||
|
||||
it("reads weekday and month off the key", () => {
|
||||
const [last] = heatmapDays(
|
||||
new Date("2026-03-01T03:00:00.000Z"),
|
||||
"America/New_York",
|
||||
1,
|
||||
);
|
||||
// 22:00 on Saturday 28 February in New York.
|
||||
expect(last).toEqual({ dateKey: "2026-02-28", dow: 5, month: 1 });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { shiftDateKey, userDayKey } from "@/lib/tz/format";
|
||||
|
||||
/** One calendar-heatmap column entry: a local day and where it sits. */
|
||||
export interface HeatmapDay {
|
||||
/** `YYYY-MM-DD` in the user's zone. */
|
||||
dateKey: string;
|
||||
/** Weekday with Monday = 0 … Sunday = 6. */
|
||||
dow: number;
|
||||
/** Month index 0–11. */
|
||||
month: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* The last `days` local days in `timeZone`, oldest first, ending with today.
|
||||
*
|
||||
* Built from today's key in the user's zone and stepped on keys. The heatmaps
|
||||
* used to take `now − n·24 h` and cut the key in UTC, so in the evening west
|
||||
* of UTC (or the morning east of it) "today" was a different day from the one
|
||||
* the server had keyed the user's readings on, and the newest cell showed the
|
||||
* wrong day. Weekday and month come from the key itself.
|
||||
*/
|
||||
export function heatmapDays(
|
||||
now: Date,
|
||||
timeZone: string,
|
||||
days: number,
|
||||
): HeatmapDay[] {
|
||||
const today = userDayKey(now, timeZone);
|
||||
const out: HeatmapDay[] = [];
|
||||
for (let back = days - 1; back >= 0; back--) {
|
||||
const dateKey = shiftDateKey(today, -back);
|
||||
const [y, m, d] = dateKey.split("-").map(Number);
|
||||
const utc = new Date(Date.UTC(y, m - 1, d));
|
||||
out.push({ dateKey, dow: (utc.getUTCDay() + 6) % 7, month: m - 1 });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
Reference in new issue
Block a user