mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
fix(medications): bucket the local day in the user's zone, DST-safe
Five timezone-correctness fixes across the medication / compliance surfaces: - getUserTodayBounds now derives both bounds through the DST-safe startOfLocalDayInTz, so the today window is 23h on spring-forward and 25h on fall-back instead of a hardcoded 24h sampled at now. A 23:30 local dose no longer drops off the med cards, dashboard, PWA badge and reminder idempotency near midnight on a transition day. - dailyComplianceRatesFromLedger takes the user's zone and buckets each per-day rate with userDayKey, so a non-Berlin user's evening dose is filed on the local day it was due rather than the next Berlin day. - classifyIntakeTiming interprets the window HH:mm in an optional zone; the achievements perfect-day check passes the user's zone and reads the scheduled minute-of-day in-zone, so a dose far from UTC is graded against local wall time. - The /insights greeting resolves the hour in the user's stored zone via the new hourInTz helper, matching the dashboard hero. - The doctor-report and schedule-anchored compliance queries load schedules through SCHEDULE_COMPLIANCE_SELECT instead of a broad include, so a future engine column reaches both surfaces.
This commit is contained in:
1 parent
6ad2dc858a
commit
fb6813bcdb
10 files changed
+99
-51
No files matched your search
@@ -7,6 +7,7 @@ import { useTranslations, useFormatters } from "@/lib/i18n/context";
|
||||
import { formatUpdatedLabel } from "@/lib/i18n/relative-time";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { useModuleEnabled } from "@/hooks/use-module-enabled";
|
||||
import { hourInTz, DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
import { ProseBlocks } from "@/components/insights/prose-blocks";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
@@ -138,8 +139,7 @@ interface HeroStripProps {
|
||||
* rare to see /insights at 03:00 and "Guten
|
||||
* Morgen" pre-5am reads odd)
|
||||
*/
|
||||
function resolveGreetingKey(now: Date): string {
|
||||
const hour = now.getHours();
|
||||
function resolveGreetingKey(hour: number): string {
|
||||
if (hour >= 5 && hour < 12) return "insights.heroGreetingMorning";
|
||||
if (hour >= 12 && hour < 18) return "insights.heroGreetingAfternoon";
|
||||
// 18:00-22:59 maps to "Good evening"; 23:00-04:59 also maps to
|
||||
@@ -221,7 +221,14 @@ export function HeroStrip({
|
||||
// pillar from the number itself). SSR-safe + default-on, matching the
|
||||
// disabled-allowlist gate.
|
||||
const moodEnabled = useModuleEnabled("mood");
|
||||
const greetingKey = resolveGreetingKey(now ?? new Date());
|
||||
// Greeting hour in the user's configured zone, not the browser's — a
|
||||
// traveller / VPN user / wrong device clock otherwise sees the wrong
|
||||
// salutation. Mirrors the dashboard hero (`hourInTimezone(now, userTz)`).
|
||||
const greetingHour = hourInTz(
|
||||
now ?? new Date(),
|
||||
user?.timezone ?? DEFAULT_TIMEZONE,
|
||||
);
|
||||
const greetingKey = resolveGreetingKey(greetingHour);
|
||||
const greetingBase = t(greetingKey);
|
||||
const greeting = userName ? `${greetingBase}, ${userName}` : greetingBase;
|
||||
const subtitle = briefing?.paragraph ?? t("insights.heroFallbackSubtitle");
|
||||
|
||||
Reference in new issue
Block a user