From fec3638bc4fcbe7de17f7764a843db9c2d81599e Mon Sep 17 00:00:00 2001 From: Alan Daniel Date: Wed, 25 Mar 2026 12:20:41 -0400 Subject: [PATCH] custom schedule ui --- .../api-v2/hubspot-meetings/[slug]/route.ts | 22 +++++++++ .../src/go/sections/HubSpotMeetingSection.tsx | 4 +- .../hubspot-meeting/CalendarPicker.tsx | 15 +++--- .../sections/hubspot-meeting/useScheduler.ts | 49 ++++++++++++++++--- 4 files changed, 74 insertions(+), 16 deletions(-) diff --git a/apps/www/app/api-v2/hubspot-meetings/[slug]/route.ts b/apps/www/app/api-v2/hubspot-meetings/[slug]/route.ts index d9a22932997..eeff09734ba 100644 --- a/apps/www/app/api-v2/hubspot-meetings/[slug]/route.ts +++ b/apps/www/app/api-v2/hubspot-meetings/[slug]/route.ts @@ -37,5 +37,27 @@ export async function GET( } const data = await res.json() + + // HubSpot returns `durations` but our types expect `availableDurations` + if (data.customParams?.durations && !data.customParams.availableDurations) { + data.customParams.availableDurations = data.customParams.durations + } + + // Transform linkAvailability from HubSpot's nested structure to a flat Record + // HubSpot returns: { linkAvailabilityByDuration: { "1800000": { availabilities: [...] } } } + // We need: { "1800000": [...] } + if (data.linkAvailability?.linkAvailabilityByDuration) { + const flat: Record> = {} + for (const [duration, value] of Object.entries( + data.linkAvailability.linkAvailabilityByDuration as Record< + string, + { availabilities?: Array<{ startMillisUtc: number; endMillisUtc: number }> } + > + )) { + flat[duration] = value.availabilities ?? [] + } + data.linkAvailability = flat + } + return NextResponse.json(data) } diff --git a/packages/marketing/src/go/sections/HubSpotMeetingSection.tsx b/packages/marketing/src/go/sections/HubSpotMeetingSection.tsx index fea02fbb012..2ddc491b993 100644 --- a/packages/marketing/src/go/sections/HubSpotMeetingSection.tsx +++ b/packages/marketing/src/go/sections/HubSpotMeetingSection.tsx @@ -38,7 +38,7 @@ export default function HubSpotMeetingSection({ section }: { section: GoHubSpotM timezone, availableDates, slotsForSelectedDate, - maxMonthOffset, + availableMonthOffsets, selectDate, selectSlot, goBackToDate, @@ -120,7 +120,7 @@ export default function HubSpotMeetingSection({ section }: { section: GoHubSpotM {state.step === 'date-select' && ( selectedDate: string | null @@ -15,7 +15,7 @@ const DAY_LABELS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] export default function CalendarPicker({ monthOffset, - maxMonthOffset, + availableMonthOffsets, timezone, availableDates, selectedDate, @@ -55,16 +55,19 @@ export default function CalendarPicker({ const today = new Date().toLocaleDateString('en-CA', { timeZone: timezone }) + const hasPrev = availableMonthOffsets.some((o) => o < monthOffset) + const hasNext = availableMonthOffsets.some((o) => o > monthOffset) + return (