From 5820078008ef6d7e68be93dfc1123ac7e3f403b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 1 Oct 2026 09:39:09 +0200 Subject: [PATCH] fix(environment): default the date fields to the user's own day The travel and backfill pickers defaulted to the UTC day, which was tomorrow east of UTC in the small hours and yesterday west of it in the evening, and the backfill start cut the home's effective instant the same way. Both now read the day in the account's zone. --- .../environment-section-dates.test.tsx | 58 +++++++++++++++++++ .../settings/environment-section.tsx | 20 +++++-- 2 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 src/components/settings/__tests__/environment-section-dates.test.tsx diff --git a/src/components/settings/__tests__/environment-section-dates.test.tsx b/src/components/settings/__tests__/environment-section-dates.test.tsx new file mode 100644 index 000000000..a37b6c670 --- /dev/null +++ b/src/components/settings/__tests__/environment-section-dates.test.tsx @@ -0,0 +1,58 @@ +/** + * The environment settings default their date fields to today. "Today" is + * the user's day: the UTC day was yesterday west of UTC in the evening and + * tomorrow east of it in the small hours. + */ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { renderToStaticMarkup } from "react-dom/server"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; + +import { I18nProvider } from "@/lib/i18n/context"; + +const auth = vi.hoisted(() => ({ timezone: "America/Los_Angeles" })); +vi.mock("@/hooks/use-auth", () => ({ + useAuth: () => ({ + user: { timezone: auth.timezone, modules: { environment: true } }, + isAuthenticated: true, + }), +})); +vi.mock("next/navigation", () => ({ + useRouter: () => ({ push: vi.fn(), replace: vi.fn() }), + usePathname: () => "/settings/environment", + useSearchParams: () => new URLSearchParams(""), +})); + +import { EnvironmentSection } from "../environment-section"; + +function backfillEnd(): string | undefined { + const client = new QueryClient({ defaultOptions: { queries: { retry: 0 } } }); + const html = renderToStaticMarkup( + + + + + , + ); + return /id="env-backfill-end"[^>]*value="([^"]*)"/.exec(html)?.[1]; +} + +beforeEach(() => { + vi.useFakeTimers({ toFake: ["Date"] }); +}); +afterEach(() => { + vi.useRealTimers(); +}); + +describe(" date defaults", () => { + it("defaults to the user's day west of UTC", () => { + auth.timezone = "America/Los_Angeles"; + vi.setSystemTime(new Date("2026-07-03T03:00:00.000Z")); // 2 July, 20:00 + expect(backfillEnd()).toBe("2026-07-02"); + }); + + it("defaults to the user's day east of UTC", () => { + auth.timezone = "Pacific/Kiritimati"; + vi.setSystemTime(new Date("2026-07-02T12:00:00.000Z")); // 3 July, 02:00 + expect(backfillEnd()).toBe("2026-07-03"); + }); +}); diff --git a/src/components/settings/environment-section.tsx b/src/components/settings/environment-section.tsx index 0a9de3eb6..166500a69 100644 --- a/src/components/settings/environment-section.tsx +++ b/src/components/settings/environment-section.tsx @@ -32,6 +32,12 @@ import { formatDateTime } from "@/lib/format"; import { useTranslations } from "@/lib/i18n/context"; import { apiDelete, apiGet, apiPost, apiPut } from "@/lib/api/api-fetch"; import { queryKeys } from "@/lib/query-keys"; +import { + DEFAULT_TIMEZONE, + detectBrowserTimezone, + userDayKey, + validTimezoneOr, +} from "@/lib/tz/format"; interface GeocodeResult { lat: number; @@ -72,14 +78,18 @@ interface EnvironmentOverview { attribution: string; } -function todayKey(): string { - return new Date().toISOString().slice(0, 10); -} - export function EnvironmentSection() { const { t, tCount } = useTranslations(); const { user } = useAuth(); const queryClient = useQueryClient(); + // Date defaults are the user's own days. The UTC day was tomorrow for + // anyone east of UTC in the small hours and yesterday west of it in the + // evening. + const tz = validTimezoneOr( + user?.timezone ?? detectBrowserTimezone(), + DEFAULT_TIMEZONE, + ); + const todayKey = () => userDayKey(new Date(), tz); const enabled = user?.modules?.environment === true; @@ -217,7 +227,7 @@ export function EnvironmentSection() { // user can still type an earlier start, but pre-home days resolve to SKIP on // the server — to fill the deep past they add an explicit location period. const effectiveBackfillStart = - backfillStart || home?.since?.slice(0, 10) || ""; + backfillStart || (home?.since ? userDayKey(new Date(home.since), tz) : ""); return (