mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
refactor(tz): route coach/verdict/mood day-keys through userDayKey
The coach snapshot tzDayKey, the dashboard verdict dayKeyInTz, and the mood-entry moodDateKey each carried their own Intl day-key formatter (en-CA / en-CA / sv-SE). Delegate all three to the canonical userDayKey so every day-bucket key stays byte-aligned and the locale decision lives in one place. Behaviour-preserving.
This commit is contained in:
1 parent
e15e8ef428
commit
f22e39872e
3 files changed
+13
-23
No files matched your search
@@ -23,6 +23,7 @@ import {
|
||||
type CoachDataCluster,
|
||||
} from "@/lib/validations/coach-prefs";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/resolver";
|
||||
import { userDayKey } from "@/lib/tz/format";
|
||||
import { convertGlucose, resolveGlucoseUnit } from "@/lib/glucose";
|
||||
import {
|
||||
computeGlucoseClinicalMetrics,
|
||||
@@ -223,15 +224,11 @@ function windowToDays(window: CoachScopeWindow): number {
|
||||
* "last night" answer has to use the user's clock, not UTC. Up to
|
||||
* v1.4.24 the day-key was UTC, so a 23:50 Pacific/Auckland reading
|
||||
* landed in the next UTC day's bucket and the Coach couldn't pair it
|
||||
* with the user's mental model.
|
||||
* with the user's mental model. Delegates to the canonical
|
||||
* `userDayKey` so every day-bucket surface stays byte-aligned.
|
||||
*/
|
||||
function tzDayKey(date: Date, tz: string): string {
|
||||
return new Intl.DateTimeFormat("en-CA", {
|
||||
timeZone: tz,
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
}).format(date);
|
||||
return userDayKey(date, tz);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
COACH_NUDGE_SLEEP_DEFICIT_MARGIN_H,
|
||||
} from "@/lib/jobs/coach-nudge-thresholds";
|
||||
import { buildWeightRangeFromHeight } from "@/lib/analytics/value-bands";
|
||||
import { userDayKey } from "@/lib/tz/format";
|
||||
import type { DashboardSnapshot } from "@/lib/dashboard/snapshot";
|
||||
|
||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
@@ -93,16 +94,6 @@ export interface DashboardVerdict {
|
||||
cta: DashboardVerdictCta | null;
|
||||
}
|
||||
|
||||
/** YYYY-MM-DD key of `d`'s calendar day in `tz`. */
|
||||
function dayKeyInTz(d: Date, tz: string): string {
|
||||
return new Intl.DateTimeFormat("en-CA", {
|
||||
timeZone: tz,
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
}).format(d);
|
||||
}
|
||||
|
||||
/** HH:mm wall-clock of `d` in `tz`. */
|
||||
function hmInTz(d: Date, tz: string): string {
|
||||
const parts = new Intl.DateTimeFormat("en-GB", {
|
||||
@@ -176,7 +167,7 @@ export function resolveDashboardVerdict(
|
||||
if (
|
||||
untilDue >= 0 &&
|
||||
untilDue <= DOSE_UPCOMING_WINDOW_MS &&
|
||||
dayKeyInTz(new Date(dueMs), tz) === dayKeyInTz(now, tz)
|
||||
userDayKey(new Date(dueMs), tz) === userDayKey(now, tz)
|
||||
) {
|
||||
return {
|
||||
variant: "doseUpcoming",
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
* legacy date string (`effectiveMoodTz`).
|
||||
*/
|
||||
|
||||
import { userDayKey } from "@/lib/tz/format";
|
||||
|
||||
export const DEFAULT_TIMEZONE = "Europe/Berlin";
|
||||
|
||||
/**
|
||||
@@ -35,14 +37,14 @@ export const DEFAULT_TIMEZONE = "Europe/Berlin";
|
||||
* timezone at write time. Used by `POST /api/mood-entries` and the
|
||||
* `PUT /api/mood-entries/:id` route when `moodLoggedAt` changes.
|
||||
*
|
||||
* The Swedish locale ("sv-SE") is the historical choice for ISO 8601
|
||||
* day output via `Intl.DateTimeFormat`; we keep it so the new path
|
||||
* produces byte-identical strings to the legacy `toBerlinDate()` for
|
||||
* Europe/Berlin users (the only path tested under the v1.4.24 suite).
|
||||
* Delegates to the canonical `userDayKey` so the mood day-bucket key
|
||||
* stays byte-identical to every other day-bucket surface. The ISO
|
||||
* YYYY-MM-DD shape is unchanged from the legacy sv-SE formatter; the
|
||||
* empty-tz fallback to Europe/Berlin is preserved here.
|
||||
*/
|
||||
export function moodDateKey(date: Date, tz: string): string {
|
||||
const safe = tz && tz.length > 0 ? tz : DEFAULT_TIMEZONE;
|
||||
return new Intl.DateTimeFormat("sv-SE", { timeZone: safe }).format(date);
|
||||
return userDayKey(date, safe);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user