fix(telegram): snooze a skipped dose to the end of the person's own day

The skip button set the rest-of-day snooze with `setHours(23, 59, …)` in
the process zone, which runs in UTC, so a skip after midnight UTC but
before local midnight east of it silenced the next local day's reminders
too, and one west of it ended the snooze hours early. The snooze now ends
at the last instant of the account's local day.
This commit is contained in:
Marc-André Bombeck committed 2026-10-20 03:35:36 +02:00
1 parent 1ee73908ae
commit e452dd62e2
2 files changed
+12 -6

No files matched your search

@@ -210,6 +210,7 @@ beforeEach(() => {
});
afterEach(() => {
vi.useRealTimers();
if (ORIGINAL_SECRET === undefined) delete process.env.TELEGRAM_WEBHOOK_SECRET;
else process.env.TELEGRAM_WEBHOOK_SECRET = ORIGINAL_SECRET;
});
@@ -396,7 +397,11 @@ describe("Telegram webhook — callback dispatch", () => {
expect(ackText).toMatch(/1 hour/i);
});
it("'skip:<medId>' creates an intake event with skipped=true and snoozes through end-of-day", async () => {
it("'skip:<medId>' creates an intake event with skipped=true and snoozes through the person's own end of day", async () => {
// 23:30 UTC is already 01:30 the next day in Berlin: the snooze ends at
// Berlin's next midnight, not at the end of the UTC day half an hour on.
vi.useFakeTimers({ toFake: ["Date"] });
vi.setSystemTime(new Date("2026-06-10T23:30:00.000Z"));
const res = await POST(tgRequest(callbackUpdate("skip:med-1")));
expect(res.status).toBe(200);
@@ -417,8 +422,7 @@ describe("Telegram webhook — callback dispatch", () => {
const updateArgs = vi.mocked(prisma.medication.update).mock.calls[0][0];
const snoozedUntil = (updateArgs.data as { snoozedUntil: Date })
.snoozedUntil;
expect(snoozedUntil.getHours()).toBe(23);
expect(snoozedUntil.getMinutes()).toBe(59);
expect(snoozedUntil.toISOString()).toBe("2026-06-11T21:59:59.999Z");
// Skip row + rest-of-day snooze commit atomically.
expect(prisma.$transaction).toHaveBeenCalledTimes(1);
// v1.16.10 — an explicit skip refunds a previously-consumed stamp
+5 -3
View File
@@ -20,7 +20,7 @@ import {
consumeForIntake,
restoreForIntake,
} from "@/lib/medications/inventory/consumption";
import { localHmAsUtc } from "@/lib/tz/local-day";
import { getUserTodayBounds, localHmAsUtc } from "@/lib/tz/local-day";
import { wallClockInTz } from "@/lib/tz/wall-clock";
import { DEFAULT_TIMEZONE } from "@/lib/tz/format";
import {
@@ -597,10 +597,12 @@ export async function handleCallback(update: TelegramUpdate) {
let skippedScheduledFor: Date | null = null;
if (!existing) {
const endOfDay = new Date();
endOfDay.setHours(23, 59, 59, 999);
const skipMoment = new Date();
const tz = user.timezone || DEFAULT_TIMEZONE;
// The rest of the person's own day, not of the server's: the process
// runs in UTC, so a Berlin skip after 01:00 used to snooze the next
// local morning's reminders as well.
const endOfDay = getUserTodayBounds(skipMoment, tz).end;
// v1.16.9 — a Telegram skip answers a specific dose prompt, so it
// must converge onto the slot's pending row like a take does. The