Skip to content

fix(timeslots): respect minimum notice period across timezones#102

Merged
choden-dev merged 1 commit into
mainfrom
fix/timeslot-notice-period-timezone
Jul 17, 2026
Merged

fix(timeslots): respect minimum notice period across timezones#102
choden-dev merged 1 commit into
mainfrom
fix/timeslot-notice-period-timezone

Conversation

@choden-dev

Copy link
Copy Markdown
Owner

Problem

The minimum notice period for booking a pickup timeslot wasn't respected. Slot start times were parsed as timezone-naive datetimes (new Date("YYYY-MM-DDT09:00:00")), which JS interprets in the server's local timezone. In production the server runs in UTC, but slots are wall-clock times in the shop's timezone (NZ), so the notice-period comparison was shifted by the shop's UTC offset (~12–13h, DST-dependent) — letting too-soon slots through.

Fix

  • lib/scheduleGenerator.ts: add DST-aware slotInstant() helper (uses Intl.DateTimeFormat to resolve the correct UTC offset for the slot's date) and a SHOP_TIMEZONE constant (defaults to Pacific/Auckland).
  • app/api/pickup-slots/route.ts: use slotInstant for the notice comparison; compute "today" in the shop timezone so the date filter doesn't drop/add a day around UTC midnight.
  • app/api/shop/[orderId]/select-timeslot/route.ts: enforce the notice period on booking (previously only active + capacity were checked), so it can't be bypassed via a direct/stale POST. Uses the same schedule-override → global-default → 24h resolution.
  • Env sync (per AGENTS.md): new server-only SHOP_TIMEZONE added to env.d.ts, container-worker.js, and .env.local with consistent Pacific/Auckland defaults. No Docker placeholder needed (not client-inlined).

Verification

  • Manually verified slotInstant across DST: NZDT +13 (summer) and NZST +12 (winter) resolve to the correct UTC instants, and the notice-window include/exclude logic is correct.
  • biome check clean; tsc --noEmit passes.

The minimum notice period for booking a pickup timeslot was not enforced
correctly because slot start times were parsed in the server's local
timezone. In production the server runs in UTC while slots are wall-clock
times in the shop's timezone (NZ), so the notice-period comparison was off
by the shop's UTC offset (~12-13h, DST-dependent).

- Add timezone-safe slotInstant() helper (DST-aware via Intl) and a
  SHOP_TIMEZONE constant (defaults to Pacific/Auckland) in
  lib/scheduleGenerator.ts.
- pickup-slots route: use slotInstant for the notice comparison and
  compute 'today' in the shop timezone.
- select-timeslot route: enforce the notice period on booking (previously
  only active + capacity were checked), so it can't be bypassed via a
  direct/stale POST.
- Sync new SHOP_TIMEZONE server-only env var across env.d.ts,
  container-worker.js, and .env.local.
@choden-dev
choden-dev merged commit 30e83d8 into main Jul 17, 2026
4 checks passed
@choden-dev
choden-dev deleted the fix/timeslot-notice-period-timezone branch July 17, 2026 01:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant