mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 06:40:50 +00:00
refactor(tz): take the medication and reminder trees off the zone literal
The medication and measurement-reminder code now imports DEFAULT_TIMEZONE from the tz module like every other fallback, so the lint rule no longer exempts those paths.
This commit is contained in:
1 parent
e2814336e5
commit
314e9c1aa3
13 files changed
+29
-42
No files matched your search
@@ -30,11 +30,10 @@ import { annotate } from "@/lib/logging/context";
|
||||
import { satisfyReminder } from "@/lib/measurement-reminders/satisfy";
|
||||
import { toMeasurementReminderDto } from "@/lib/measurement-reminders/dto";
|
||||
import { isScreeningReminderType } from "@/lib/validations/measurement-reminders";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
type RouteParams = { params: Promise<{ id: string }> };
|
||||
|
||||
const DEFAULT_TIMEZONE = "Europe/Berlin";
|
||||
|
||||
export const POST = apiHandler(
|
||||
async (request: NextRequest, { params }: RouteParams) => {
|
||||
// v1.37.0 — MANAGE. Marking a reminder satisfied re-anchors a schedule the level
|
||||
|
||||
@@ -33,13 +33,11 @@ import {
|
||||
} from "@/lib/measurement-reminders/scheduling";
|
||||
import { toMeasurementReminderDto } from "@/lib/measurement-reminders/dto";
|
||||
import { wallClockInTz, zonedWallClockToUtc } from "@/lib/tz/wall-clock";
|
||||
import { userDayKey } from "@/lib/tz/format";
|
||||
import { DEFAULT_TIMEZONE, userDayKey } from "@/lib/tz/format";
|
||||
import { holdsOpenAfterReminder } from "@/lib/measurement-reminders/holds-open";
|
||||
|
||||
type RouteParams = { params: Promise<{ id: string }> };
|
||||
|
||||
const DEFAULT_TIMEZONE = "Europe/Berlin";
|
||||
|
||||
async function resolveTimezone(userId: string): Promise<string> {
|
||||
const row = await prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
|
||||
@@ -16,11 +16,10 @@ import { annotate } from "@/lib/logging/context";
|
||||
import { satisfyReminder } from "@/lib/measurement-reminders/satisfy";
|
||||
import { toMeasurementReminderDto } from "@/lib/measurement-reminders/dto";
|
||||
import { isScreeningReminderType } from "@/lib/validations/measurement-reminders";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
type RouteParams = { params: Promise<{ id: string }> };
|
||||
|
||||
const DEFAULT_TIMEZONE = "Europe/Berlin";
|
||||
|
||||
export const POST = apiHandler(
|
||||
async (request: NextRequest, { params }: RouteParams) => {
|
||||
// v1.37.0 — MANAGE. The same primitive from the checklist side re-anchors a schedule the level
|
||||
|
||||
@@ -22,11 +22,10 @@ import { apiSuccess, apiError, getClientIp } from "@/lib/api-response";
|
||||
import { annotate } from "@/lib/logging/context";
|
||||
import { skipReminder } from "@/lib/measurement-reminders/satisfy";
|
||||
import { toMeasurementReminderDto } from "@/lib/measurement-reminders/dto";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
type RouteParams = { params: Promise<{ id: string }> };
|
||||
|
||||
const DEFAULT_TIMEZONE = "Europe/Berlin";
|
||||
|
||||
export const POST = apiHandler(
|
||||
async (request: NextRequest, { params }: RouteParams) => {
|
||||
// MANAGE — the same level as satisfy/complete: deciding to let a cycle
|
||||
|
||||
@@ -29,11 +29,10 @@ import { annotate } from "@/lib/logging/context";
|
||||
import { toMeasurementReminderDto } from "@/lib/measurement-reminders/dto";
|
||||
import { snoozeMeasurementReminderSchema } from "@/lib/validations/measurement-reminders";
|
||||
import { zonedWallClockToUtc } from "@/lib/tz/wall-clock";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
type RouteParams = { params: Promise<{ id: string }> };
|
||||
|
||||
const DEFAULT_TIMEZONE = "Europe/Berlin";
|
||||
|
||||
/** Furthest a snooze may reach: five years from now. */
|
||||
const SNOOZE_CAP_MS = 5 * 365.25 * 24 * 60 * 60 * 1000;
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@ import {
|
||||
} from "@/lib/measurement-reminders/scheduling";
|
||||
import { toMeasurementReminderDto } from "@/lib/measurement-reminders/dto";
|
||||
import { listMeasurementReminders } from "@/lib/measurement-reminders/list-read";
|
||||
|
||||
const DEFAULT_TIMEZONE = "Europe/Berlin";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
async function resolveTimezone(userId: string): Promise<string> {
|
||||
const row = await prisma.user.findUnique({
|
||||
|
||||
@@ -59,6 +59,7 @@ import { satisfyReminder } from "@/lib/measurement-reminders/satisfy";
|
||||
import { evaluateCoachContextReminders } from "@/lib/ai/coach/context-reminders";
|
||||
import { calendarDaysUntil } from "@/lib/measurement-reminders/due-day";
|
||||
import { holdsOpenAfterReminder } from "@/lib/measurement-reminders/holds-open";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
/**
|
||||
* v1.18.0 — map a reminder's `measurementType` to the toggleable module
|
||||
@@ -231,7 +232,7 @@ export function evaluateMeasurementReminderDue(
|
||||
if (!reminder.enabled || reminder.nextDueAt === null) {
|
||||
return { fire: false, inHourWindow: false, isDue: false };
|
||||
}
|
||||
const tz = timezone || "Europe/Berlin";
|
||||
const tz = timezone || DEFAULT_TIMEZONE;
|
||||
const isDue = now.getTime() >= reminder.nextDueAt.getTime();
|
||||
const parts = wallClockInTz(now, tz);
|
||||
const inHourWindow = parts.hour === reminderSlotHour(reminder, tz);
|
||||
@@ -326,7 +327,7 @@ export async function runMeasurementReminderTick(
|
||||
for (const reminder of reminders) {
|
||||
summary.candidatesScanned += 1;
|
||||
try {
|
||||
const timezone = reminder.user.timezone || "Europe/Berlin";
|
||||
const timezone = reminder.user.timezone || DEFAULT_TIMEZONE;
|
||||
|
||||
// v1.39.2 — a reminder already sent for its current slot stays in
|
||||
// this scan every tick until it is satisfied. Outside its notify hour
|
||||
@@ -587,7 +588,7 @@ export async function runReminderSatisfyForUser(
|
||||
where: { id: userId },
|
||||
select: { timezone: true },
|
||||
});
|
||||
const timezone = user?.timezone || "Europe/Berlin";
|
||||
const timezone = user?.timezone || DEFAULT_TIMEZONE;
|
||||
|
||||
const reminders = await prisma.measurementReminder.findMany({
|
||||
where: { userId, deletedAt: null, enabled: true },
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
nextOccurrenceAfter,
|
||||
} from "@/lib/medications/scheduling/recurrence";
|
||||
import { wallClockInTz } from "@/lib/tz/wall-clock";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
/**
|
||||
* The reminder fields this module reads. A subset of the Prisma row so
|
||||
@@ -133,7 +134,7 @@ export function buildReminderRecurrence(
|
||||
// `anchorDate` / `endsOn` are instants instead (the form sends local
|
||||
// midnight, a Coach course sends `now + days`), so hand the engine the
|
||||
// calendar day each instant falls on in the user's zone.
|
||||
const tz = timeZone || "Europe/Berlin";
|
||||
const tz = timeZone || DEFAULT_TIMEZONE;
|
||||
const startsOn = calendarDayInZone(
|
||||
reminder.anchorDate ?? reminder.createdAt,
|
||||
tz,
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
reduceCurrentWindowStatus,
|
||||
type ScheduleWindowInput,
|
||||
} from "@/lib/medications/window-status";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
export interface DefaultMedicationOption {
|
||||
id: string;
|
||||
@@ -24,8 +25,6 @@ const DEFAULT_THRESHOLDS: MedicationDueThresholds = {
|
||||
missedMinutes: 240,
|
||||
};
|
||||
|
||||
const DEFAULT_TIMEZONE = "Europe/Berlin";
|
||||
|
||||
/**
|
||||
* Pick the medication that should be pre-selected when an intake form opens.
|
||||
* Current, late, and overdue schedule windows win; otherwise the fallback is
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
} from "@/lib/medications/intake-tracking";
|
||||
import { liveEraStartsByMedication } from "@/lib/medications/scheduling/live-era";
|
||||
import { floorWhole } from "@/lib/medications/units-per-dose";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
export type MedicationsListResult = Array<Record<string, unknown>>;
|
||||
|
||||
@@ -327,7 +328,7 @@ export async function readMedicationsListCached(user: {
|
||||
id: string;
|
||||
timezone: string | null;
|
||||
}): Promise<MedicationsListResult> {
|
||||
const userTz = user.timezone || "Europe/Berlin";
|
||||
const userTz = user.timezone || DEFAULT_TIMEZONE;
|
||||
return cachedSwr(
|
||||
caches.medications as ServerCache<MedicationsListResult>,
|
||||
user.id,
|
||||
|
||||
@@ -48,6 +48,7 @@ import {
|
||||
wallClockInTz,
|
||||
type WallClockParts,
|
||||
} from "@/lib/tz/wall-clock";
|
||||
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
|
||||
|
||||
/** One explicit per-dose on-time window as the API serialises it. */
|
||||
export interface DoseWindowEntryInput {
|
||||
@@ -123,9 +124,6 @@ export interface NextDueGate {
|
||||
overdue: boolean;
|
||||
}
|
||||
|
||||
/** Fallback timezone until every call site threads the user's own. */
|
||||
const DEFAULT_TZ = "Europe/Berlin";
|
||||
|
||||
/**
|
||||
* Minute-of-day an observer in the target zone reads off the wall clock.
|
||||
* Every band comparison below is minute-of-day arithmetic, so this is the
|
||||
@@ -516,7 +514,7 @@ export function reduceCurrentWindowStatus<
|
||||
active,
|
||||
lastTakenAt,
|
||||
todayEventCount,
|
||||
tz = DEFAULT_TZ,
|
||||
tz = DEFAULT_TIMEZONE,
|
||||
nextDue,
|
||||
} = options;
|
||||
const nowParts = wallClockInTz(now, tz);
|
||||
|
||||
Reference in new issue
Block a user