mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 13:52:20 +00:00
fix(reminders): read a first-due date sent as a date as that day in the user's zone
A reminder's first-due date could only be sent as a date-time, and the web form sent the browser's local midnight, so a browser set to a zone other than the profile's could move the day. The API now also takes a bare calendar date and stores it as that day's midnight in the user's zone, and the web form sends the date itself. A date-time still means the instant it names.
This commit is contained in:
1 parent
b6b51fcb5e
commit
9311337997
8 files changed
+101
-20
No files matched your search
@@ -29,6 +29,7 @@ import { annotate } from "@/lib/logging/context";
|
||||
import { updateMeasurementReminderSchema } from "@/lib/validations/measurement-reminders";
|
||||
import {
|
||||
computeReminderNextDueAt,
|
||||
parseReminderAnchor,
|
||||
type ReminderScheduleInput,
|
||||
} from "@/lib/measurement-reminders/scheduling";
|
||||
import { toMeasurementReminderDto } from "@/lib/measurement-reminders/dto";
|
||||
@@ -141,9 +142,12 @@ export const PATCH = apiHandler(
|
||||
updateData.intervalDays = null;
|
||||
}
|
||||
}
|
||||
const timezone = await resolveTimezone(user.id);
|
||||
if (data.anchorDate !== undefined) {
|
||||
updateData.anchorDate =
|
||||
data.anchorDate != null ? new Date(data.anchorDate) : null;
|
||||
data.anchorDate != null
|
||||
? parseReminderAnchor(data.anchorDate, timezone)
|
||||
: null;
|
||||
}
|
||||
if (data.notifyHour !== undefined) updateData.notifyHour = data.notifyHour;
|
||||
if (data.location !== undefined) updateData.location = data.location;
|
||||
@@ -166,7 +170,6 @@ export const PATCH = apiHandler(
|
||||
// auto-clear a few lines up — so keying off its own keys (present, even
|
||||
// when the value is `null`) can never diverge from what the database
|
||||
// ends up holding.
|
||||
const timezone = await resolveTimezone(user.id);
|
||||
const now = new Date();
|
||||
const merged: ReminderScheduleInput = {
|
||||
intervalDays: Object.hasOwn(updateData, "intervalDays")
|
||||
@@ -193,10 +196,10 @@ export const PATCH = apiHandler(
|
||||
// open, overdue check-up quietly moved it to its next slot. Compared by
|
||||
// value, because a client may resend every field on each save.
|
||||
//
|
||||
// The first due date is compared by CALENDAR DAY in the profile zone. The
|
||||
// web form sends a date as the browser's local midnight, and a booster
|
||||
// row stores the dose instant plus N days, so the same day arrives as a
|
||||
// different instant. A resent same-day anchor is dropped from the write
|
||||
// The first due date is compared by CALENDAR DAY in the profile zone. A
|
||||
// client may send a date-time (older web builds sent the browser's local
|
||||
// midnight), and a booster row stores the dose instant plus N days, so the
|
||||
// same day arrives as a different instant. A resent same-day anchor is dropped from the write
|
||||
// altogether, so the stored instant stays what it was.
|
||||
const sameInstant = (a: Date | null, b: Date | null) =>
|
||||
(a?.getTime() ?? null) === (b?.getTime() ?? null);
|
||||
|
||||
@@ -21,6 +21,7 @@ import { withIdempotency } from "@/lib/idempotency";
|
||||
import { createMeasurementReminderSchema } from "@/lib/validations/measurement-reminders";
|
||||
import {
|
||||
computeReminderNextDueAt,
|
||||
parseReminderAnchor,
|
||||
type ReminderScheduleInput,
|
||||
} from "@/lib/measurement-reminders/scheduling";
|
||||
import { toMeasurementReminderDto } from "@/lib/measurement-reminders/dto";
|
||||
@@ -88,7 +89,10 @@ async function postReminder(request: NextRequest): Promise<Response> {
|
||||
|
||||
const timezone = await resolveTimezone(user.id);
|
||||
const now = new Date();
|
||||
const anchorDate = data.anchorDate != null ? new Date(data.anchorDate) : null;
|
||||
const anchorDate =
|
||||
data.anchorDate != null
|
||||
? parseReminderAnchor(data.anchorDate, timezone)
|
||||
: null;
|
||||
|
||||
// Server-authoritative next-due. No satisfy yet → anchors on
|
||||
// anchorDate ?? createdAt (createdAt ≈ now for a fresh row).
|
||||
|
||||
Reference in new issue
Block a user