Skip to content

fix(email): restore two-arg luxon fromObject in matchTeamIntro timeslots - #64

Open
detail-app[bot] wants to merge 1 commit into
mainfrom
detail/bug-fix/fix-email-restore-two-arg-luxon-fromobject-in-matc-a0c5ba
Open

detail-app[bot] wants to merge 1 commit into
mainfrom
detail/bug-fix/fix-email-restore-two-arg-luxon-fromobject-in-matc-a0c5ba

Conversation

@detail-app

@detail-app detail-app Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Detail bug report: View on Detail

Bug

The match-team intro email (src/email/templates/matchTeamIntro.ts) silently dropped its "Suggested Meeting Times (all students available)" block for any matched team whose students actually supplied weekly availability data, falling back to the generic "Mentors: Send a When2meet" prompt instead.

Root cause: localIntervalToUtc built each luxon DateTime with DateTime.fromObject({ …, zone: tz }) — placing zone inside the values object. Under the installed runtime luxon@3.7.2 this throws InvalidUnitError: Invalid unit zone (zone is not a valid unit there; luxon 3.x takes the zone via a second options argument). A broad try/catch in findCommonTimeslots swallowed the throw and returned {}, which getList collapsed to undefined, so the template's {{#if commonTimeslots}} branch never rendered.

This slipped through typecheck because @types/luxon was pinned to a stale ^1.26.5 whose fromObject signature accepts the extra zone key, masking the runtime/types mismatch — and through testing because the code had no test coverage at all.

Fix

  • Restored the two-argument DateTime.fromObject(values, { zone }) form for both the start and end conversions in localIntervalToUtc — the form the original feature commit used before the regression.
  • Bumped @types/luxon from ^1.26.5 to ^3.7.5 so the type definitions match the ^3.7.2 runtime. This both lets the correct two-arg form typecheck and turns the buggy single-arg form into a compile error (TS2345: 'zone' does not exist in type 'DateObjectUnits'), preventing the identical regression from reoccurring. The whole repo still typechecks cleanly against the upgraded types.
  • Left the findCommonTimeslots try/catch in place; the throw it was masking is gone, and a regression test now asserts no console.warn is emitted for valid data.
  • Added an offline regression test (matchTeamIntro.test.ts, stubbed Prisma) covering the core regression, cross-timezone UTC conversion, the swallowed-error guard, the legitimate-empty fallback, and both template branches.

Testing

  • Unit tests, typecheck (npx tsc --skipLibCheck --noEmit), and the existing unrelated offline test (syncAlumniInteractions.test.ts) all pass. (ESLint is broken environment-wide — eslint 7's parser is incompatible with the installed TS 5.x — and is not a usable signal here.)
  • New offline regression test (npx tsx src/email/templates/matchTeamIntro.test.ts) verifies: overlapping same-timezone availability yields a populated commonTimeslots; cross-timezone overlap (NY 9–11am / LA 6–8am, both 14:00–16:00 UTC) renders the window in each student's own timezone; no "finding common timeslots" warning is emitted for valid data; missing timeManagementPlan legitimately yields undefined; and the actual matchTeamIntro.md Handlebars block renders the "Suggested Meeting Times" block (not When2meet) when data is supplied, and the When2meet fallback (not the timeslot block) when it isn't.
  • Verified end-to-end against a live Postgres DB: installed and started postgresql-16, created a test database, applied the schema via prisma db push, seeded a matched project with two accepted students in distinct timezones and overlapping availability plus an accepted mentor on a matchComplete event, and ran the real dispatch path (getEmailGenerators() → generator.getList() → generator.template() with the app's Handlebars helpers registered). The rendered email body contained the "Suggested Meeting Times" header with both timezone-labeled windows and no When2meet fallback; after clearing the students' plans, it rendered the When2meet fallback instead. Seed data was cleaned up afterward.
  • Confirmed the regression-guard: temporarily reverting to the buggy fromObject({ …, zone }) form produces TS2345 compile errors under the upgraded types, so the build now blocks reintroduction.

Automatic Fixes PRs can be configured here.

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