api.ts72 lines · main
1import type { BookingConfirmation, BookingInfo, BookingRequest } from './types'
2
3const BASE = '/api-v2/hubspot-meetings'
4
5async function parseErrorResponse(res: Response, fallback: string): Promise<string> {
6 try {
7 const body = await res.json()
8 return body.error || body.message || fallback
9 } catch {
10 return fallback
11 }
12}
13
14function wrapNetworkError(err: unknown): never {
15 if (
16 err instanceof TypeError &&
17 (err.message === 'Failed to fetch' || err.message === 'Load failed')
18 ) {
19 throw new Error('Unable to connect. Please check your internet connection and try again.')
20 }
21 throw err
22}
23
24export async function fetchBookingInfo(
25 slug: string,
26 timezone: string,
27 monthOffset = 0
28): Promise<BookingInfo> {
29 const params = new URLSearchParams({ timezone, monthOffset: String(monthOffset) })
30 let res: Response
31 try {
32 res = await fetch(`${BASE}/${encodeURIComponent(slug)}?${params}`)
33 } catch (err) {
34 wrapNetworkError(err)
35 }
36 if (!res.ok) {
37 if (res.status === 404) throw new Error('This meeting calendar could not be found.')
38 throw new Error(await parseErrorResponse(res, `Failed to load calendar (${res.status})`))
39 }
40 return res.json()
41}
42
43export async function fetchAvailability(slug: string, timezone: string): Promise<BookingInfo> {
44 const params = new URLSearchParams({ timezone })
45 let res: Response
46 try {
47 res = await fetch(`${BASE}/${encodeURIComponent(slug)}/availability?${params}`)
48 } catch (err) {
49 wrapNetworkError(err)
50 }
51 if (!res.ok) {
52 throw new Error(await parseErrorResponse(res, `Failed to load availability (${res.status})`))
53 }
54 return res.json()
55}
56
57export async function bookMeeting(request: BookingRequest): Promise<BookingConfirmation> {
58 let res: Response
59 try {
60 res = await fetch(`${BASE}/book`, {
61 method: 'POST',
62 headers: { 'Content-Type': 'application/json' },
63 body: JSON.stringify(request),
64 })
65 } catch (err) {
66 wrapNetworkError(err)
67 }
68 if (!res.ok) {
69 throw new Error(await parseErrorResponse(res, `Booking failed (${res.status})`))
70 }
71 return res.json()
72}