mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 06:52:04 +00:00
chore(release): v1.28.35 — timestamps honor the profile timezone
Client-rendered times fell back to the hardcoded display zone (Europe/Berlin) because neither useFormatters() nor the legacy format.ts helpers ever received users.timezone. A third localStorage mirror (timezone-mirror.ts, following the time-format/date-format pattern) carries the validated profile zone from /api/auth/me into both read paths; the fallback chain is strictly profile → Europe/Berlin — never the browser zone, so screen, PDF, and export cannot disagree. makeFormatters validates its zone before Intl (a poison value falls back instead of throwing inside every render). Same pass, per the two-document audit: formatUpdatedLabel boundary and clock now resolve one zone in every state (the undefined-tz browser hole is closed); @db.Date calendar fields render UTC-pinned so profiles west of UTC cannot shift a day; dose-history day headings and GLP-1 weekday labels derive from the display zone; chart day/month labels are encoding-derived and UTC-pinned (bucket math untouched, byte-identical for Berlin profiles); the clinician share view renders in the patient's timezone instead of the container's; Playwright pins Europe/Berlin. Server day-key semantics, streak anchoring, insight cache keys, and verbatim wall-clock strings are untouched by construction and pinned by the new Auckland/New_York/Manila + DST test matrix.
This commit is contained in:
1 parent
136653e3d7
commit
9bbd8a89dc
41 files changed
+958
-90
No files matched your search
@@ -35,7 +35,7 @@ import { prefersReducedMotion } from "@/lib/charts/reduced-motion";
|
||||
import { computePaddedYDomain } from "@/lib/insights/chart-y-domain";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useTranslations, useFormatters } from "@/lib/i18n/context";
|
||||
import { makeFormatters } from "@/lib/format-locale";
|
||||
import { makeBucketLabelFormatters } from "@/lib/charts/bucket-label";
|
||||
import {
|
||||
bucketTimeSeries,
|
||||
pickBucket,
|
||||
@@ -595,14 +595,15 @@ export function HealthChart({
|
||||
const { isAuthenticated, user } = useAuth();
|
||||
const { t, locale } = useTranslations();
|
||||
const fmt = useFormatters();
|
||||
// v1.4.25 W7b — tz-aware formatter for x-axis tick labels + tooltip
|
||||
// date strings. `useFormatters()` reads the active UI locale only;
|
||||
// this builds a locale + userTz pair so a Pacific/Auckland user reads
|
||||
// their own day on the axis.
|
||||
const tzFmt = useMemo(
|
||||
() => makeFormatters(locale, userTimezone),
|
||||
[locale, userTimezone],
|
||||
);
|
||||
// Issue #490 — x-axis tick + tooltip date labels. Every timestamp this
|
||||
// chart formats encodes a CALENDAR DAY (noon-UTC of a profile-tz day
|
||||
// key, or a `bucketTimeSeries` Berlin-day UTC-midnight bucket start),
|
||||
// so labels render UTC-pinned via `makeBucketLabelFormatters` — the
|
||||
// encoded day paints verbatim in every profile zone. Rendering these
|
||||
// encodings through a profile-tz formatter shifted week/month bucket
|
||||
// labels a day/month back for zones west of Berlin. Day-key BUCKETING
|
||||
// below still uses `userTimezone` — only labels are pinned.
|
||||
const tzFmt = useMemo(() => makeBucketLabelFormatters(locale), [locale]);
|
||||
// v1.4.25 W7b — per-row day-key formatter used to bucket measurement
|
||||
// rows by the user's local calendar day. Memoised on userTimezone so
|
||||
// the inner per-row loop reuses a single Intl.DateTimeFormat.
|
||||
|
||||
@@ -19,7 +19,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { makeFormatters } from "@/lib/format-locale";
|
||||
import { makeBucketLabelFormatters } from "@/lib/charts/bucket-label";
|
||||
import type { DataSummary } from "@/lib/analytics/trends";
|
||||
import {
|
||||
bucketTimeSeries,
|
||||
@@ -90,12 +90,6 @@ interface MoodChartProps {
|
||||
* only surface — the cog stays hidden and overlays are clean.
|
||||
*/
|
||||
chartKey?: ChartOverlayKey;
|
||||
/**
|
||||
* v1.4.25 W7b — per-user display timezone. When passed, the x-axis
|
||||
* tick labels and tooltip date render in the user's tz. Defaults to
|
||||
* "Europe/Berlin" so older mount sites stay byte-identical.
|
||||
*/
|
||||
userTimezone?: string;
|
||||
/**
|
||||
* v1.16.0 — fires once the mood analytics query has settled (initial
|
||||
* load finished). The dashboard's shared reveal gate listens here so
|
||||
@@ -304,17 +298,17 @@ export function MoodChart({
|
||||
windowOverride,
|
||||
compareBaseline = "none",
|
||||
chartKey,
|
||||
userTimezone = "Europe/Berlin",
|
||||
onDataReady,
|
||||
}: MoodChartProps) {
|
||||
const { isAuthenticated } = useAuth();
|
||||
const { t, locale } = useTranslations();
|
||||
// v1.4.25 W7b — tz-aware formatter for x-axis tick labels + tooltip
|
||||
// date strings.
|
||||
const tzFmt = useMemo(
|
||||
() => makeFormatters(locale, userTimezone),
|
||||
[locale, userTimezone],
|
||||
);
|
||||
// Issue #490 — x-axis tick + tooltip date labels. Every timestamp this
|
||||
// chart formats encodes a CALENDAR DAY (noon-UTC of a server day key,
|
||||
// or a `bucketTimeSeries` Berlin-day UTC-midnight bucket start), so
|
||||
// labels render UTC-pinned via `makeBucketLabelFormatters` — the
|
||||
// encoded day paints verbatim in every profile zone (a profile-tz
|
||||
// formatter shifted week/month bucket labels for zones west of Berlin).
|
||||
const tzFmt = useMemo(() => makeBucketLabelFormatters(locale), [locale]);
|
||||
const initialRangePoints = windowOverride
|
||||
? MINI_RANGE_POINTS[windowOverride]
|
||||
: 30;
|
||||
|
||||
Reference in new issue
Block a user