import { __ } from '@wordpress/i18n'; export interface BookingConfig { privacyPolicyUrl?: string; locale?: string; timeFormat?: string; requestLocale?: 'user' | 'site'; timezone?: string; membershipsEnabled?: boolean; restUrl: string; nonce: string; authenticated?: boolean; loginUrl?: string; } export class BookingError extends Error { constructor(message: string, public readonly status: number, public readonly code = '', public readonly data?: { participant_share_applies?: boolean; blockers?: { message: string; }[]; usage_limit_warnings?: import('./usage').Usage[]; customer_restriction_warnings?: { message?: string; }[]; }) { super(message); } } export class BookingApi { constructor(private config: BookingConfig) { } privacyPolicyUrl(): string { return this.config.privacyPolicyUrl ?? ''; } private async response(route: string, method = 'GET', payload?: unknown, query: Record = {}, signal?: AbortSignal): Promise { const url = new URL(this.config.restUrl); const restRoute = url.searchParams.get('rest_route'); if (restRoute !== null) url.searchParams.set('rest_route', restRoute + route); else url.pathname += route; if (this.config.requestLocale !== 'site') url.searchParams.set('_locale', 'user'); Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v)); const response = await fetch(url, { method, signal, credentials: 'same-origin', headers: { 'X-WP-Nonce': this.config.nonce, 'Content-Type': 'application/json' }, body: payload === undefined ? undefined : JSON.stringify(payload) }); if (!response.ok) { const data = await response.json().catch(() => null); throw new BookingError(data?.message ?? __('The request failed. Please try again.', 'abece-booking'), response.status, data?.code, data?.data); } return response; } async request(route: string, method = 'GET', payload?: unknown, query: Record = {}, signal?: AbortSignal): Promise { return (await this.response(route, method, payload, query, signal)).json(); } async list(route: string, query: Record = {}): Promise<{ items: T[]; total: number; }> { const r = await this.response(route, 'GET', undefined, query); return { items: await r.json(), total: Number(r.headers.get('X-WP-Total') ?? 0) }; } async all(route: string, query: Record = {}): Promise<{ items: T[]; }> { const items: T[] = []; for (let page = 1;; page++) { const result = await this.list(route, { ...query, per_page: '100', page: String(page) }); items.push(...result.items); if (result.items.length === 0 || page * 100 >= result.total) break; } return { items }; } }