fix(charts): cut days in the account's zone when a mount passes none

Several chart mounts (the medications page, the coach chat, the
recovery section) pass no zone, and the chart then fell back to a fixed
Europe/Berlin, so those charts cut and labelled days in Berlin for
every user whatever their profile said.

The chart now falls back to the signed-in account's zone, and only
before that has loaded to the shared DEFAULT_TIMEZONE the server's own
resolver ends on. /api/auth/me reports the zone the server resolves:
the stored one, or the instance default when the stored one is
unusable, so the client cuts days where the server does.

Refs #1026
This commit is contained in:
Marc-André Bombeck committed 2026-09-24 08:15:16 +02:00
1 parent 3170a622d1
commit 16ef75e729
4 files changed
+104 -6

No files matched your search

@@ -28,6 +28,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
process.env.ENCRYPTION_KEY ??=
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
import { invalidateServerDefaultTimezone } from "@/lib/tz/resolver";
import { cookieJar, headerJar } from "./mock-next-headers";
import { getPrismaClient, truncateAllTables } from "./setup";
@@ -166,6 +167,36 @@ describe("per-user timezone — Pacific/Auckland end-to-end", () => {
expect(body.data?.timezone).toBe("Pacific/Auckland");
});
// A stored zone the server cannot use falls back to the instance
// default for every server-side day cut. `/api/auth/me` reports that
// same resolved zone, so a client (the charts' day buckets among them)
// never cuts days in a different zone than the server did.
it("GET /api/auth/me reports the resolved zone when the stored one is unusable", async () => {
const user = await seedAucklandUser();
const prisma = getPrismaClient();
await prisma.user.update({
where: { id: user.id },
data: { timezone: "" },
});
await prisma.appSettings.upsert({
where: { id: "singleton" },
create: { id: "singleton", defaultUserTimezone: "Asia/Kolkata" },
update: { defaultUserTimezone: "Asia/Kolkata" },
});
invalidateServerDefaultTimezone();
try {
const { GET } = await import("@/app/api/auth/me/route");
const res = await GET();
expect(res.status).toBe(200);
const body = (await res.json()) as {
data: { timezone?: string } | null;
};
expect(body.data?.timezone).toBe("Asia/Kolkata");
} finally {
invalidateServerDefaultTimezone();
}
});
it("PUT /api/auth/me/timezone rejects an invalid IANA zone with 422", async () => {
await seedAucklandUser();