diff --git a/apps/www/app/api-v2/hubspot-meetings/book/route.ts b/apps/www/app/api-v2/hubspot-meetings/book/route.ts
index 2eeea5991ef..b50e08fe8aa 100644
--- a/apps/www/app/api-v2/hubspot-meetings/book/route.ts
+++ b/apps/www/app/api-v2/hubspot-meetings/book/route.ts
@@ -47,8 +47,9 @@ export async function POST(request: NextRequest) {
if (!res.ok) {
const text = await res.text()
+ console.error('[HubSpot booking error]', { status: res.status, body: text })
return NextResponse.json(
- { error: 'HubSpot booking failed', detail: text },
+ { error: 'Booking failed. Please try again or contact support.' },
{ status: res.status }
)
}
diff --git a/packages/marketing/src/go/sections/HubSpotMeetingSection.tsx b/packages/marketing/src/go/sections/HubSpotMeetingSection.tsx
index 2ddc491b993..6ac6048c9cd 100644
--- a/packages/marketing/src/go/sections/HubSpotMeetingSection.tsx
+++ b/packages/marketing/src/go/sections/HubSpotMeetingSection.tsx
@@ -1,6 +1,5 @@
'use client'
-import { Loader2 } from 'lucide-react'
import { useEffect, useMemo, useRef, useState } from 'react'
import type { GoHubSpotMeetingSection } from '../schemas'
@@ -75,7 +74,7 @@ export default function HubSpotMeetingSection({ section }: { section: GoHubSpotM
{state.step === 'loading' && (
)}
diff --git a/packages/marketing/src/go/sections/hubspot-meeting/TimezoneSelector.tsx b/packages/marketing/src/go/sections/hubspot-meeting/TimezoneSelector.tsx
index 42ee7c814f8..2ddfea500b4 100644
--- a/packages/marketing/src/go/sections/hubspot-meeting/TimezoneSelector.tsx
+++ b/packages/marketing/src/go/sections/hubspot-meeting/TimezoneSelector.tsx
@@ -114,7 +114,7 @@ function getUtcOffset(tzId: string): { label: string; minutes: number } {
function buildGroups(userTz: string): { userEntry: TimezoneEntry; groups: TimezoneGroup[] } {
const entries: TimezoneEntry[] = TIMEZONE_DATA.map((tz) => {
const offset = getUtcOffset(tz.id)
- return { id: tz.id, label: tz.label, offset: offset.label, offsetMinutes: offset.offsetMinutes }
+ return { id: tz.id, label: tz.label, offset: offset.label, offsetMinutes: offset.minutes }
})
// Build user entry
diff --git a/packages/marketing/src/go/sections/hubspot-meeting/useScheduler.ts b/packages/marketing/src/go/sections/hubspot-meeting/useScheduler.ts
index d61f8fdbcf6..05d8b93df1f 100644
--- a/packages/marketing/src/go/sections/hubspot-meeting/useScheduler.ts
+++ b/packages/marketing/src/go/sections/hubspot-meeting/useScheduler.ts
@@ -41,8 +41,14 @@ export interface SchedulerState {
}
export function useScheduler(slug: string, enabled = true) {
- const [timezone, setTimezoneState] = useState(() => getUserTimezone())
- const locale = useMemo(() => getUserLocale(), [])
+ const [timezone, setTimezoneState] = useState('America/New_York')
+ const [locale, setLocale] = useState('en-US')
+
+ // Hydrate timezone/locale from browser after mount to avoid SSR mismatches
+ useEffect(() => {
+ setTimezoneState(getUserTimezone())
+ setLocale(getUserLocale())
+ }, [])
/** Cached booking info keyed by month offset */
const [monthCache, setMonthCache] = useState
>({})
@@ -208,13 +214,15 @@ export function useScheduler(slug: string, enabled = true) {
/** Month offsets that have at least one available slot */
const availableMonthOffsets = useMemo(() => {
- const now = new Date()
+ // Compute "now" in the selected timezone to avoid ±1 month drift near boundaries
+ const nowStr = new Date().toLocaleDateString('en-CA', { timeZone: timezone })
+ const [nowY, nowM] = nowStr.split('-').map(Number)
const offsets = new Set()
for (const slot of allSlots) {
const date = new Date(slot.startMillisUtc)
const localDateStr = date.toLocaleDateString('en-CA', { timeZone: timezone })
const [y, m] = localDateStr.split('-').map(Number)
- const offset = (y - now.getFullYear()) * 12 + (m - 1 - now.getMonth())
+ const offset = (y - nowY) * 12 + (m - nowM)
if (offset >= 0 && offset < MONTHS_TO_FETCH) {
offsets.add(offset)
}