@mrcharles/sdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -1
- package/dist/mrcharles.esm.js +685 -19
- package/dist/mrcharles.esm.js.map +12 -10
- package/dist/mrcharles.min.js +2 -2
- package/dist/mrcharles.min.js.map +12 -10
- package/dist/types/client.d.ts +16 -0
- package/dist/types/embed.d.ts +3 -1
- package/dist/types/env.d.ts +7 -1
- package/dist/types/format.d.ts +24 -0
- package/dist/types/http.d.ts +1 -1
- package/dist/types/i18n.d.ts +50 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/links.d.ts +4 -3
- package/dist/types/rooms.d.ts +15 -3
- package/dist/types/types.d.ts +8 -5
- package/package.json +1 -1
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/env.ts", "../src/errors.ts", "../src/http.ts", "../src/links.ts", "../src/embed.ts", "../src/uuid.ts", "../src/slots.ts", "../src/rooms.ts", "../src/client.ts", "../src/index.ts"],
|
|
3
|
+
"sources": ["../src/env.ts", "../src/errors.ts", "../src/http.ts", "../src/i18n.ts", "../src/links.ts", "../src/embed.ts", "../src/uuid.ts", "../src/slots.ts", "../src/rooms.ts", "../src/format.ts", "../src/client.ts", "../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"export type Environment = 'production';\n\nexport interface Endpoints {\n /** e.g. https://api.mrcharles.app/api/v1 */\n apiBase: string;\n /** e.g. https://app.mrcharles.app — where lessons are booked */\n appBase: string;\n /** e.g. sites.mrcharles.app — hosted studio sites live at <slug>.<sitesBase> */\n sitesBase: string;\n}\n\n/**\n * There is one public environment. Testing happens against a studio site in\n * sandbox mode on that same API — see developers.mrcharles.app/getting-started/sandbox —\n * so an integration never has to change hosts between development and launch.\n */\nexport const ENVIRONMENTS: Record<Environment, Endpoints> = {\n production: {\n apiBase: 'https://api.mrcharles.app/api/v1',\n appBase: 'https://app.mrcharles.app',\n sitesBase: 'sites.mrcharles.app',\n },\n};\n\nexport interface ClientConfig {\n /** Only 'production' exists; kept so a future environment is a non-breaking addition. */\n env?: Environment;\n /** Endpoint overrides — for Mr Charles' own deployments and tests, not for integrators. */\n apiBase?: string;\n appBase?: string;\n sitesBase?: string;\n /** Custom fetch (tests, server runtimes, proxies). Defaults to globalThis.fetch. */\n fetch?: typeof fetch;\n
|
|
5
|
+
"export type Environment = 'production';\n\nexport interface Endpoints {\n /** e.g. https://api.mrcharles.app/api/v1 */\n apiBase: string;\n /** e.g. https://app.mrcharles.app — where lessons are booked */\n appBase: string;\n /** e.g. sites.mrcharles.app — hosted studio sites live at <slug>.<sitesBase> */\n sitesBase: string;\n}\n\n/**\n * There is one public environment. Testing happens against a studio site in\n * sandbox mode on that same API — see developers.mrcharles.app/getting-started/sandbox —\n * so an integration never has to change hosts between development and launch.\n */\nexport const ENVIRONMENTS: Record<Environment, Endpoints> = {\n production: {\n apiBase: 'https://api.mrcharles.app/api/v1',\n appBase: 'https://app.mrcharles.app',\n sitesBase: 'sites.mrcharles.app',\n },\n};\n\nexport interface ClientConfig {\n /** Only 'production' exists; kept so a future environment is a non-breaking addition. */\n env?: Environment;\n /** Endpoint overrides — for Mr Charles' own deployments and tests, not for integrators. */\n apiBase?: string;\n appBase?: string;\n sitesBase?: string;\n /** Custom fetch (tests, server runtimes, proxies). Defaults to globalThis.fetch. */\n fetch?: typeof fetch;\n /**\n * The client's language: default for the embedded screen (`lang`), the\n * guest's messages (hold `locale`), `Accept-Language`, `mc.t()` and\n * `mc.format`. Any BCP-47 tag (\"ca-ES\", \"pt-BR\"); es, ca, en, fr, pt, it,\n * de have SDK strings, others fall back to English. Change it later with\n * `mc.setLocale()`.\n */\n locale?: string;\n /** Extra headers, e.g. X-Forwarded-For when calling from your server on a guest's behalf. */\n headers?: Record<string, string>;\n}\n\nexport function resolveEndpoints(config: ClientConfig = {}): Endpoints {\n const base = ENVIRONMENTS[config.env ?? 'production'];\n return {\n apiBase: trimSlash(config.apiBase ?? base.apiBase),\n appBase: trimSlash(config.appBase ?? base.appBase),\n sitesBase: (config.sitesBase ?? base.sitesBase).replace(/^https?:\\/\\//, '').replace(/\\/+$/, ''),\n };\n}\n\nfunction trimSlash(s: string): string {\n return s.replace(/\\/+$/, '');\n}\n",
|
|
6
6
|
"/** Stable error codes of the public API. Branch on these; show `message` as-is. */\nexport type ErrorCode =\n | 'VALIDATION_ERROR'\n | 'RESOURCE_NOT_FOUND'\n | 'SITE_NOT_LIVE'\n | 'ROOM_NOT_BOOKABLE'\n | 'STUDIO_NOT_VERIFIED'\n | 'OUTSIDE_HOURS'\n | 'OUTSIDE_BOOKING_WINDOW'\n | 'SLOT_TAKEN'\n | 'HOLD_EXPIRED'\n | 'HOLD_NOT_VERIFIED'\n | 'HOLD_ALREADY_CONFIRMED'\n | 'CODE_INVALID'\n | 'TOO_MANY_ATTEMPTS'\n | 'RATE_LIMIT_EXCEEDED'\n | 'CAPTCHA_FAILED'\n | 'SMS_UNAVAILABLE'\n | 'PAYMENTS_UNAVAILABLE'\n | 'PAYMENT_MODE_DENIED'\n | 'CANCEL_TOO_LATE'\n | 'INVALID_STATE'\n | 'INTERNAL_ERROR'\n | 'NETWORK_ERROR'\n | (string & {});\n\nexport class MrCharlesError extends Error {\n readonly code: ErrorCode;\n readonly status: number;\n readonly requestId?: string;\n\n constructor(code: ErrorCode, message: string, status = 0, requestId?: string) {\n super(message);\n this.name = 'MrCharlesError';\n this.code = code;\n this.status = status;\n this.requestId = requestId;\n }\n\n /** The hold is gone — start the flow again with a fresh idempotency key. */\n get holdIsDead(): boolean {\n return this.code === 'HOLD_EXPIRED' || this.code === 'TOO_MANY_ATTEMPTS';\n }\n\n /** The slot is no longer available — refresh availability, keep the guest's details. */\n get slotIsGone(): boolean {\n return this.code === 'SLOT_TAKEN' || this.code === 'OUTSIDE_HOURS' || this.code === 'OUTSIDE_BOOKING_WINDOW';\n }\n\n /** Worth retrying the same request, with the same idempotency key. */\n get isTransient(): boolean {\n return this.code === 'NETWORK_ERROR' || this.status >= 500;\n }\n}\n\nexport function isMrCharlesError(e: unknown): e is MrCharlesError {\n return e instanceof MrCharlesError || (typeof e === 'object' && e !== null && (e as { name?: string }).name === 'MrCharlesError');\n}\n",
|
|
7
|
-
"import { MrCharlesError } from './errors';\nimport type { ClientConfig } from './env';\n\nexport interface Http {\n get<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T>;\n post<T>(path: string, body?: unknown): Promise<T>;\n}\n\n/** Envelope-aware fetch against the API: unwraps `data`, throws MrCharlesError. */\nexport function createHttp(apiBase: string, config: ClientConfig): Http {\n const resolved = config.fetch ?? (typeof fetch === 'function' ? fetch.bind(globalThis) : undefined);\n if (!resolved) throw new Error('@mrcharles/sdk: no fetch available — pass { fetch } in the client config');\n const doFetch: typeof fetch = resolved;\n\n async function request<T>(method: 'GET' | 'POST', path: string, body?: unknown, params?: Record<string, string | number | undefined>): Promise<T> {\n let url = apiBase + path;\n if (params) {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) if (v !== undefined && v !== '') q.set(k, String(v));\n const s = q.toString();\n if (s) url += (url.includes('?') ? '&' : '?') + s;\n }\n const headers: Record<string, string> = { Accept: 'application/json', ...(config.headers ?? {}) };\n if (
|
|
8
|
-
"import type { Endpoints } from './env';\nimport type { Locale } from './types';\n\nexport interface RoomLinkOptions {\n slug: string;\n roomId: string;\n /** YYYY-MM-DD in the studio's zone */\n date?: string;\n /** HH:MM */\n start?: string;\n durationMinutes?: number;\n lang?: Locale;\n /** Hide the hosted site's header and footer (for iframes) */\n embed?: boolean;\n}\n\nexport function createLinks(endpoints: Endpoints) {\n const siteOrigin = (slug: string) => `https://${slug}.${endpoints.sitesBase}`;\n\n return {\n /** The studio's hosted site */\n site(slug: string): string {\n return `${siteOrigin(slug)}/`;\n },\n\n /** Hosted booking screen for a room, optionally pre-filled */\n bookRoom(o: RoomLinkOptions): string {\n const q = new URLSearchParams();\n if (o.date) q.set('date', o.date);\n if (o.start) q.set('start', o.start);\n if (o.durationMinutes) q.set('duration', String(o.durationMinutes));\n if (o.lang) q.set('lang', o.lang);\n if (o.embed) q.set('embed', '1');\n const s = q.toString();\n return `${siteOrigin(o.slug)}/reservar/${o.roomId}${s ? `?${s}` : ''}`;\n },\n\n /** A guest's booking page (cancel, details) from the manage token */\n manage(slug: string, manageToken: string): string {\n return `${siteOrigin(slug)}/r/${manageToken}`;\n },\n\n /**\n * Book a lesson in the Mr Charles app. Students need an account there;\n * this is the hand-off. `instructorId` is the teacher's **user** id.\n */\n bookLesson(o: { offerId?: string; instructorId: string }): string {\n const q = new URLSearchParams({ instructorId: o.instructorId });\n if (o.offerId) q.set('offerId', o.offerId);\n return `${endpoints.appBase}/bookings/book?${q.toString()}`;\n },\n\n /** The teacher's public profile in the app */\n teacherProfile(instructorUserId: string): string {\n return `${endpoints.appBase}/instructors/${instructorUserId}`;\n },\n };\n}\n\nexport type Links = ReturnType<typeof createLinks>;\n",
|
|
9
|
-
"import type { Endpoints } from './env';\nimport {
|
|
7
|
+
"import { MrCharlesError } from './errors';\nimport type { ClientConfig } from './env';\n\nexport interface Http {\n get<T>(path: string, params?: Record<string, string | number | undefined>): Promise<T>;\n post<T>(path: string, body?: unknown): Promise<T>;\n}\n\n/** Envelope-aware fetch against the API: unwraps `data`, throws MrCharlesError. */\nexport function createHttp(apiBase: string, config: ClientConfig, getLocale: () => string | undefined = () => config.locale): Http {\n const resolved = config.fetch ?? (typeof fetch === 'function' ? fetch.bind(globalThis) : undefined);\n if (!resolved) throw new Error('@mrcharles/sdk: no fetch available — pass { fetch } in the client config');\n const doFetch: typeof fetch = resolved;\n\n async function request<T>(method: 'GET' | 'POST', path: string, body?: unknown, params?: Record<string, string | number | undefined>): Promise<T> {\n let url = apiBase + path;\n if (params) {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) if (v !== undefined && v !== '') q.set(k, String(v));\n const s = q.toString();\n if (s) url += (url.includes('?') ? '&' : '?') + s;\n }\n const headers: Record<string, string> = { Accept: 'application/json', ...(config.headers ?? {}) };\n const locale = getLocale();\n if (locale) headers['Accept-Language'] = locale;\n if (body !== undefined) headers['Content-Type'] = 'application/json';\n\n let res: Response;\n try {\n res = await doFetch(url, { method, headers, body: body !== undefined ? JSON.stringify(body) : undefined, cache: 'no-store' });\n } catch (e) {\n throw new MrCharlesError('NETWORK_ERROR', (e as Error)?.message || 'Network error', 0);\n }\n\n const requestId = res.headers?.get?.('x-request-id') ?? undefined;\n const text = await res.text();\n let json: unknown = null;\n try {\n json = text ? JSON.parse(text) : null;\n } catch {\n json = null;\n }\n const envelope = (json && typeof json === 'object' ? json : {}) as { success?: boolean; data?: unknown; error?: { code?: string; message?: string } };\n\n if (!res.ok || envelope.success === false) {\n const code = envelope.error?.code ?? (res.status === 429 ? 'RATE_LIMIT_EXCEEDED' : res.status === 404 ? 'RESOURCE_NOT_FOUND' : 'INTERNAL_ERROR');\n const message = envelope.error?.message ?? res.statusText ?? 'Request failed';\n throw new MrCharlesError(code, message, res.status, requestId);\n }\n return ('data' in envelope ? envelope.data : json) as T;\n }\n\n return {\n get: (path, params) => request('GET', path, undefined, params),\n post: (path, body) => request('POST', path, body ?? {}),\n };\n}\n",
|
|
8
|
+
"/**\n * Languages.\n *\n * Two notions, on purpose:\n * - `HostedLocale` — what the hosted booking screen and the server's\n * messages (SMS, email, reminders) speak: es, ca, en.\n * - `Locale` — what the SDK itself speaks: those three plus fr, pt, it, de.\n * A custom UI in French gets French labels and error sentences from the\n * SDK; the guest's code and confirmation arrive in English (the closest\n * hosted locale) unless the site is Spanish/Catalan.\n *\n * Any BCP-47 tag is accepted as input (\"ca-ES\", \"pt-BR\", \"en_GB\") and\n * normalised; unknown languages fall back to English.\n */\nimport type { ErrorCode, MrCharlesError } from './errors';\n\nexport type HostedLocale = 'es' | 'ca' | 'en';\nexport type Locale = HostedLocale | 'fr' | 'pt' | 'it' | 'de';\n/** Anything a page might hand us: a Locale, or a BCP-47 tag like \"ca-ES\". */\nexport type LocaleInput = Locale | (string & {});\n\nexport const LOCALES: readonly Locale[] = ['es', 'ca', 'en', 'fr', 'pt', 'it', 'de'];\nexport const HOSTED_LOCALES: readonly HostedLocale[] = ['es', 'ca', 'en'];\n\n/** \"ca-ES\" → \"ca\", \"pt_BR\" → \"pt\", \"EN\" → \"en\", \"zh\" → \"en\". */\nexport function normalizeLocale(input: LocaleInput | null | undefined, fallback: Locale = 'en'): Locale {\n if (!input) return fallback;\n const lang = String(input).trim().toLowerCase().split(/[-_]/)[0];\n return (LOCALES as readonly string[]).includes(lang) ? (lang as Locale) : fallback;\n}\n\n/** The hosted screen / server language for an SDK locale: fr, pt, it, de → en. */\nexport function toHostedLocale(input: LocaleInput | null | undefined, fallback: HostedLocale = 'en'): HostedLocale {\n const l = normalizeLocale(input, fallback);\n return (HOSTED_LOCALES as readonly string[]).includes(l) ? (l as HostedLocale) : fallback;\n}\n\n/** A full Intl tag for formatting: \"es\" → \"es-ES\", \"en\" → \"en-GB\" (24 h, day-first), … */\nexport function intlTag(input: LocaleInput | null | undefined): string {\n const raw = input ? String(input).trim().replace('_', '-') : '';\n if (/^[a-z]{2,3}-[A-Za-z]{2,4}/.test(raw)) return raw;\n const l = normalizeLocale(raw);\n return { es: 'es-ES', ca: 'ca-ES', en: 'en-GB', fr: 'fr-FR', pt: 'pt-PT', it: 'it-IT', de: 'de-DE' }[l];\n}\n\n/**\n * Pick a string out of a localized object from the site payload\n * (`{ es, ca, en }`): the wanted language, then the site's default, then\n * anything that is filled in.\n */\nexport function pick(localized: Partial<Record<string, string>> | null | undefined, locale: LocaleInput, defaultLocale?: LocaleInput): string {\n if (!localized) return '';\n const want = toHostedLocale(locale);\n const def = defaultLocale ? toHostedLocale(defaultLocale) : undefined;\n for (const k of [want, def, 'es', 'ca', 'en']) {\n if (k && localized[k]) return localized[k] as string;\n }\n const first = Object.values(localized).find((v) => !!v);\n return first ?? '';\n}\n\n// ── Dictionaries ─────────────────────────────────────────────────────────\n\nexport type MessageKey =\n | 'step.slot' | 'step.details' | 'step.verify' | 'step.pay' | 'step.done' | 'step.expired'\n | 'label.date' | 'label.time' | 'label.duration' | 'label.name' | 'label.phone' | 'label.email' | 'label.contact' | 'label.code' | 'label.notes'\n | 'label.price' | 'label.deposit' | 'label.total' | 'label.perHour'\n | 'action.continue' | 'action.back' | 'action.sendCode' | 'action.verify' | 'action.resend' | 'action.confirm' | 'action.payCard' | 'action.payOnSite' | 'action.startOver' | 'action.manage' | 'action.cancel'\n | 'hint.codeSent' | 'hint.resendsLeft' | 'hint.holdExpiresIn' | 'hint.payOnSite' | 'hint.payCard' | 'hint.cancelNotice' | 'hint.sandbox' | 'hint.noSlots' | 'hint.pickDate'\n | 'done.title' | 'done.reference' | 'done.manage'\n | 'channel.phone' | 'channel.email'\n | 'pay.card' | 'pay.on_site'\n | `error.${string}`;\n\ntype Dict = Record<string, string>;\n\nconst en: Dict = {\n 'step.slot': 'Pick a time', 'step.details': 'Your details', 'step.verify': 'Enter the code', 'step.pay': 'Confirm', 'step.done': 'Booked', 'step.expired': 'Time ran out',\n 'label.date': 'Date', 'label.time': 'Time', 'label.duration': 'Duration', 'label.name': 'Name', 'label.phone': 'Mobile', 'label.email': 'Email', 'label.contact': 'Where to send the code', 'label.code': 'Code', 'label.notes': 'Notes for the studio',\n 'label.price': 'Price', 'label.deposit': 'Deposit', 'label.total': 'Total', 'label.perHour': 'per hour',\n 'action.continue': 'Continue', 'action.back': 'Back', 'action.sendCode': 'Send me a code', 'action.verify': 'Verify', 'action.resend': 'Send it again', 'action.confirm': 'Confirm booking', 'action.payCard': 'Pay by card', 'action.payOnSite': 'Pay at the studio', 'action.startOver': 'Start again', 'action.manage': 'See or cancel the booking', 'action.cancel': 'Cancel',\n 'hint.codeSent': 'We sent a code to {contact}.', 'hint.resendsLeft': '{n} resends left', 'hint.holdExpiresIn': 'Your slot is held for {time}', 'hint.payOnSite': 'Nothing to pay now; settle at the studio.', 'hint.payCard': 'A deposit of {amount} is charged now.', 'hint.cancelNotice': 'Free cancellation up to {hours} h before.', 'hint.sandbox': 'Test mode: nothing is sent or charged, and this booking will be deleted.', 'hint.noSlots': 'No free times that day.', 'hint.pickDate': 'Choose a day to see free times.',\n 'done.title': 'Booking confirmed', 'done.reference': 'Reference {ref}', 'done.manage': 'Keep this link to see or cancel the booking.',\n 'channel.phone': 'SMS', 'channel.email': 'Email',\n 'pay.card': 'Card', 'pay.on_site': 'At the studio',\n 'error.VALIDATION_ERROR': 'Please check what you typed.', 'error.RESOURCE_NOT_FOUND': 'That was not found.', 'error.SITE_NOT_LIVE': 'This studio is not taking online bookings yet.', 'error.ROOM_NOT_BOOKABLE': 'This room cannot be booked online right now.', 'error.STUDIO_NOT_VERIFIED': 'This studio is not taking online bookings yet.',\n 'error.OUTSIDE_HOURS': 'The studio is closed at that time.', 'error.OUTSIDE_BOOKING_WINDOW': 'That date cannot be booked yet — try one closer.', 'error.SLOT_TAKEN': 'That time was just taken. Pick another one.', 'error.HOLD_EXPIRED': 'Time ran out. Pick a time again.', 'error.HOLD_NOT_VERIFIED': 'Enter the code first.', 'error.HOLD_ALREADY_CONFIRMED': 'This booking is already confirmed.',\n 'error.CODE_INVALID': 'That code is not right.', 'error.TOO_MANY_ATTEMPTS': 'Too many tries. Start again.', 'error.RATE_LIMIT_EXCEEDED': 'Too many requests. Wait a minute and try again.', 'error.CAPTCHA_FAILED': 'Please complete the verification challenge.', 'error.SMS_UNAVAILABLE': 'We cannot send SMS right now — use email.', 'error.PAYMENTS_UNAVAILABLE': 'Card payments are unavailable right now — pay at the studio.', 'error.PAYMENT_MODE_DENIED': 'That payment method is not accepted for this room.',\n 'error.CANCEL_TOO_LATE': 'It is too late to cancel online — call the studio.', 'error.INVALID_STATE': 'That action is not possible right now.', 'error.INTERNAL_ERROR': 'Something went wrong. Try again.', 'error.NETWORK_ERROR': 'No connection. Check your network and try again.', 'error.default': 'Something went wrong. Try again.',\n};\n\nconst es: Dict = {\n 'step.slot': 'Elige una hora', 'step.details': 'Tus datos', 'step.verify': 'Introduce el código', 'step.pay': 'Confirmar', 'step.done': 'Reservado', 'step.expired': 'Se agotó el tiempo',\n 'label.date': 'Fecha', 'label.time': 'Hora', 'label.duration': 'Duración', 'label.name': 'Nombre', 'label.phone': 'Móvil', 'label.email': 'Email', 'label.contact': 'Dónde enviamos el código', 'label.code': 'Código', 'label.notes': 'Notas para el estudio',\n 'label.price': 'Precio', 'label.deposit': 'Señal', 'label.total': 'Total', 'label.perHour': 'por hora',\n 'action.continue': 'Continuar', 'action.back': 'Atrás', 'action.sendCode': 'Enviarme un código', 'action.verify': 'Verificar', 'action.resend': 'Reenviar', 'action.confirm': 'Confirmar reserva', 'action.payCard': 'Pagar con tarjeta', 'action.payOnSite': 'Pagar en el estudio', 'action.startOver': 'Empezar de nuevo', 'action.manage': 'Ver o cancelar la reserva', 'action.cancel': 'Cancelar',\n 'hint.codeSent': 'Hemos enviado un código a {contact}.', 'hint.resendsLeft': 'Quedan {n} reenvíos', 'hint.holdExpiresIn': 'Tu hora está reservada durante {time}', 'hint.payOnSite': 'No pagas nada ahora; se paga en el estudio.', 'hint.payCard': 'Se cobra ahora una señal de {amount}.', 'hint.cancelNotice': 'Cancelación gratuita hasta {hours} h antes.', 'hint.sandbox': 'Modo pruebas: no se envía ni se cobra nada, y esta reserva se borrará.', 'hint.noSlots': 'No hay horas libres ese día.', 'hint.pickDate': 'Elige un día para ver las horas libres.',\n 'done.title': 'Reserva confirmada', 'done.reference': 'Referencia {ref}', 'done.manage': 'Guarda este enlace para ver o cancelar la reserva.',\n 'channel.phone': 'SMS', 'channel.email': 'Email',\n 'pay.card': 'Tarjeta', 'pay.on_site': 'En el estudio',\n 'error.VALIDATION_ERROR': 'Revisa lo que has escrito.', 'error.RESOURCE_NOT_FOUND': 'No lo encontramos.', 'error.SITE_NOT_LIVE': 'Este estudio aún no acepta reservas online.', 'error.ROOM_NOT_BOOKABLE': 'Esta sala no se puede reservar online ahora mismo.', 'error.STUDIO_NOT_VERIFIED': 'Este estudio aún no acepta reservas online.',\n 'error.OUTSIDE_HOURS': 'El estudio está cerrado a esa hora.', 'error.OUTSIDE_BOOKING_WINDOW': 'Esa fecha aún no se puede reservar: prueba una más cercana.', 'error.SLOT_TAKEN': 'Esa hora acaba de ocuparse. Elige otra.', 'error.HOLD_EXPIRED': 'Se agotó el tiempo. Vuelve a elegir una hora.', 'error.HOLD_NOT_VERIFIED': 'Introduce primero el código.', 'error.HOLD_ALREADY_CONFIRMED': 'Esta reserva ya está confirmada.',\n 'error.CODE_INVALID': 'El código no es correcto.', 'error.TOO_MANY_ATTEMPTS': 'Demasiados intentos. Empieza de nuevo.', 'error.RATE_LIMIT_EXCEEDED': 'Demasiadas peticiones. Espera un minuto y vuelve a intentarlo.', 'error.CAPTCHA_FAILED': 'Completa la verificación de seguridad.', 'error.SMS_UNAVAILABLE': 'Ahora no podemos enviar SMS: usa el email.', 'error.PAYMENTS_UNAVAILABLE': 'El pago con tarjeta no está disponible: paga en el estudio.', 'error.PAYMENT_MODE_DENIED': 'Esta sala no acepta ese método de pago.',\n 'error.CANCEL_TOO_LATE': 'Ya es tarde para cancelar online: llama al estudio.', 'error.INVALID_STATE': 'Esa acción no es posible ahora.', 'error.INTERNAL_ERROR': 'Algo ha fallado. Inténtalo de nuevo.', 'error.NETWORK_ERROR': 'Sin conexión. Revisa tu red e inténtalo de nuevo.', 'error.default': 'Algo ha fallado. Inténtalo de nuevo.',\n};\n\nconst ca: Dict = {\n 'step.slot': 'Tria una hora', 'step.details': 'Les teves dades', 'step.verify': 'Introdueix el codi', 'step.pay': 'Confirmar', 'step.done': 'Reservat', 'step.expired': \"S'ha esgotat el temps\",\n 'label.date': 'Data', 'label.time': 'Hora', 'label.duration': 'Durada', 'label.name': 'Nom', 'label.phone': 'Mòbil', 'label.email': 'Correu', 'label.contact': 'On enviem el codi', 'label.code': 'Codi', 'label.notes': \"Notes per a l'estudi\",\n 'label.price': 'Preu', 'label.deposit': 'Paga i senyal', 'label.total': 'Total', 'label.perHour': 'per hora',\n 'action.continue': 'Continuar', 'action.back': 'Enrere', 'action.sendCode': 'Envia’m un codi', 'action.verify': 'Verificar', 'action.resend': 'Torna a enviar', 'action.confirm': 'Confirmar la reserva', 'action.payCard': 'Pagar amb targeta', 'action.payOnSite': \"Pagar a l'estudi\", 'action.startOver': 'Tornar a començar', 'action.manage': 'Veure o cancel·lar la reserva', 'action.cancel': 'Cancel·lar',\n 'hint.codeSent': 'Hem enviat un codi a {contact}.', 'hint.resendsLeft': 'Queden {n} reenviaments', 'hint.holdExpiresIn': 'La teva hora està reservada durant {time}', 'hint.payOnSite': \"No pagues res ara; es paga a l'estudi.\", 'hint.payCard': 'Ara es cobra una paga i senyal de {amount}.', 'hint.cancelNotice': 'Cancel·lació gratuïta fins a {hours} h abans.', 'hint.sandbox': \"Mode de proves: no s'envia ni es cobra res, i aquesta reserva s'esborrarà.\", 'hint.noSlots': 'No hi ha hores lliures aquell dia.', 'hint.pickDate': 'Tria un dia per veure les hores lliures.',\n 'done.title': 'Reserva confirmada', 'done.reference': 'Referència {ref}', 'done.manage': 'Guarda aquest enllaç per veure o cancel·lar la reserva.',\n 'channel.phone': 'SMS', 'channel.email': 'Correu',\n 'pay.card': 'Targeta', 'pay.on_site': \"A l'estudi\",\n 'error.VALIDATION_ERROR': 'Revisa el que has escrit.', 'error.RESOURCE_NOT_FOUND': 'No ho hem trobat.', 'error.SITE_NOT_LIVE': 'Aquest estudi encara no accepta reserves en línia.', 'error.ROOM_NOT_BOOKABLE': 'Aquesta sala no es pot reservar en línia ara mateix.', 'error.STUDIO_NOT_VERIFIED': 'Aquest estudi encara no accepta reserves en línia.',\n 'error.OUTSIDE_HOURS': \"L'estudi està tancat a aquella hora.\", 'error.OUTSIDE_BOOKING_WINDOW': 'Aquesta data encara no es pot reservar: prova’n una de més propera.', 'error.SLOT_TAKEN': \"Aquesta hora s'acaba d'ocupar. Tria’n una altra.\", 'error.HOLD_EXPIRED': \"S'ha esgotat el temps. Torna a triar una hora.\", 'error.HOLD_NOT_VERIFIED': 'Introdueix primer el codi.', 'error.HOLD_ALREADY_CONFIRMED': 'Aquesta reserva ja està confirmada.',\n 'error.CODE_INVALID': 'El codi no és correcte.', 'error.TOO_MANY_ATTEMPTS': 'Massa intents. Torna a començar.', 'error.RATE_LIMIT_EXCEEDED': 'Massa peticions. Espera un minut i torna-ho a provar.', 'error.CAPTCHA_FAILED': 'Completa la verificació de seguretat.', 'error.SMS_UNAVAILABLE': 'Ara no podem enviar SMS: fes servir el correu.', 'error.PAYMENTS_UNAVAILABLE': \"El pagament amb targeta no està disponible: paga a l'estudi.\", 'error.PAYMENT_MODE_DENIED': 'Aquesta sala no accepta aquest mètode de pagament.',\n 'error.CANCEL_TOO_LATE': \"Ja és tard per cancel·lar en línia: truca a l'estudi.\", 'error.INVALID_STATE': 'Aquesta acció no és possible ara.', 'error.INTERNAL_ERROR': 'Alguna cosa ha fallat. Torna-ho a provar.', 'error.NETWORK_ERROR': 'Sense connexió. Revisa la xarxa i torna-ho a provar.', 'error.default': 'Alguna cosa ha fallat. Torna-ho a provar.',\n};\n\nconst fr: Dict = {\n 'step.slot': 'Choisissez un horaire', 'step.details': 'Vos coordonnées', 'step.verify': 'Saisissez le code', 'step.pay': 'Confirmer', 'step.done': 'Réservé', 'step.expired': 'Temps écoulé',\n 'label.date': 'Date', 'label.time': 'Heure', 'label.duration': 'Durée', 'label.name': 'Nom', 'label.phone': 'Mobile', 'label.email': 'E-mail', 'label.contact': 'Où envoyer le code', 'label.code': 'Code', 'label.notes': 'Notes pour le studio',\n 'label.price': 'Prix', 'label.deposit': 'Acompte', 'label.total': 'Total', 'label.perHour': 'par heure',\n 'action.continue': 'Continuer', 'action.back': 'Retour', 'action.sendCode': 'Recevoir un code', 'action.verify': 'Vérifier', 'action.resend': 'Renvoyer', 'action.confirm': 'Confirmer la réservation', 'action.payCard': 'Payer par carte', 'action.payOnSite': 'Payer au studio', 'action.startOver': 'Recommencer', 'action.manage': 'Voir ou annuler la réservation', 'action.cancel': 'Annuler',\n 'hint.codeSent': 'Nous avons envoyé un code à {contact}.', 'hint.resendsLeft': '{n} renvois restants', 'hint.holdExpiresIn': 'Votre créneau est bloqué pendant {time}', 'hint.payOnSite': 'Rien à payer maintenant ; réglez au studio.', 'hint.payCard': 'Un acompte de {amount} est débité maintenant.', 'hint.cancelNotice': \"Annulation gratuite jusqu'à {hours} h avant.\", 'hint.sandbox': \"Mode test : rien n'est envoyé ni débité, et cette réservation sera supprimée.\", 'hint.noSlots': 'Aucun horaire libre ce jour-là.', 'hint.pickDate': 'Choisissez un jour pour voir les horaires libres.',\n 'done.title': 'Réservation confirmée', 'done.reference': 'Référence {ref}', 'done.manage': 'Conservez ce lien pour voir ou annuler la réservation.',\n 'channel.phone': 'SMS', 'channel.email': 'E-mail',\n 'pay.card': 'Carte', 'pay.on_site': 'Au studio',\n 'error.VALIDATION_ERROR': 'Vérifiez ce que vous avez saisi.', 'error.RESOURCE_NOT_FOUND': 'Introuvable.', 'error.SITE_NOT_LIVE': \"Ce studio n'accepte pas encore les réservations en ligne.\", 'error.ROOM_NOT_BOOKABLE': 'Cette salle ne peut pas être réservée en ligne pour le moment.', 'error.STUDIO_NOT_VERIFIED': \"Ce studio n'accepte pas encore les réservations en ligne.\",\n 'error.OUTSIDE_HOURS': 'Le studio est fermé à cette heure.', 'error.OUTSIDE_BOOKING_WINDOW': 'Cette date ne peut pas encore être réservée — essayez une date plus proche.', 'error.SLOT_TAKEN': \"Ce créneau vient d'être pris. Choisissez-en un autre.\", 'error.HOLD_EXPIRED': 'Temps écoulé. Choisissez à nouveau un horaire.', 'error.HOLD_NOT_VERIFIED': \"Saisissez d'abord le code.\", 'error.HOLD_ALREADY_CONFIRMED': 'Cette réservation est déjà confirmée.',\n 'error.CODE_INVALID': 'Ce code est incorrect.', 'error.TOO_MANY_ATTEMPTS': 'Trop de tentatives. Recommencez.', 'error.RATE_LIMIT_EXCEEDED': 'Trop de requêtes. Patientez une minute et réessayez.', 'error.CAPTCHA_FAILED': 'Veuillez compléter la vérification de sécurité.', 'error.SMS_UNAVAILABLE': \"Impossible d'envoyer des SMS pour le moment — utilisez l'e-mail.\", 'error.PAYMENTS_UNAVAILABLE': 'Le paiement par carte est indisponible — payez au studio.', 'error.PAYMENT_MODE_DENIED': \"Ce moyen de paiement n'est pas accepté pour cette salle.\",\n 'error.CANCEL_TOO_LATE': 'Trop tard pour annuler en ligne — appelez le studio.', 'error.INVALID_STATE': \"Cette action n'est pas possible pour le moment.\", 'error.INTERNAL_ERROR': \"Une erreur s'est produite. Réessayez.\", 'error.NETWORK_ERROR': 'Pas de connexion. Vérifiez votre réseau et réessayez.', 'error.default': \"Une erreur s'est produite. Réessayez.\",\n};\n\nconst pt: Dict = {\n 'step.slot': 'Escolha uma hora', 'step.details': 'Os seus dados', 'step.verify': 'Introduza o código', 'step.pay': 'Confirmar', 'step.done': 'Reservado', 'step.expired': 'O tempo esgotou-se',\n 'label.date': 'Data', 'label.time': 'Hora', 'label.duration': 'Duração', 'label.name': 'Nome', 'label.phone': 'Telemóvel', 'label.email': 'E-mail', 'label.contact': 'Para onde enviamos o código', 'label.code': 'Código', 'label.notes': 'Notas para o estúdio',\n 'label.price': 'Preço', 'label.deposit': 'Sinal', 'label.total': 'Total', 'label.perHour': 'por hora',\n 'action.continue': 'Continuar', 'action.back': 'Voltar', 'action.sendCode': 'Enviar-me um código', 'action.verify': 'Verificar', 'action.resend': 'Reenviar', 'action.confirm': 'Confirmar reserva', 'action.payCard': 'Pagar com cartão', 'action.payOnSite': 'Pagar no estúdio', 'action.startOver': 'Recomeçar', 'action.manage': 'Ver ou cancelar a reserva', 'action.cancel': 'Cancelar',\n 'hint.codeSent': 'Enviámos um código para {contact}.', 'hint.resendsLeft': 'Restam {n} reenvios', 'hint.holdExpiresIn': 'A sua hora está reservada durante {time}', 'hint.payOnSite': 'Não paga nada agora; paga no estúdio.', 'hint.payCard': 'É cobrado agora um sinal de {amount}.', 'hint.cancelNotice': 'Cancelamento gratuito até {hours} h antes.', 'hint.sandbox': 'Modo de testes: nada é enviado nem cobrado, e esta reserva será apagada.', 'hint.noSlots': 'Não há horas livres nesse dia.', 'hint.pickDate': 'Escolha um dia para ver as horas livres.',\n 'done.title': 'Reserva confirmada', 'done.reference': 'Referência {ref}', 'done.manage': 'Guarde esta ligação para ver ou cancelar a reserva.',\n 'channel.phone': 'SMS', 'channel.email': 'E-mail',\n 'pay.card': 'Cartão', 'pay.on_site': 'No estúdio',\n 'error.VALIDATION_ERROR': 'Verifique o que escreveu.', 'error.RESOURCE_NOT_FOUND': 'Não encontrado.', 'error.SITE_NOT_LIVE': 'Este estúdio ainda não aceita reservas online.', 'error.ROOM_NOT_BOOKABLE': 'Esta sala não pode ser reservada online neste momento.', 'error.STUDIO_NOT_VERIFIED': 'Este estúdio ainda não aceita reservas online.',\n 'error.OUTSIDE_HOURS': 'O estúdio está fechado a essa hora.', 'error.OUTSIDE_BOOKING_WINDOW': 'Essa data ainda não pode ser reservada — tente uma mais próxima.', 'error.SLOT_TAKEN': 'Essa hora acabou de ser ocupada. Escolha outra.', 'error.HOLD_EXPIRED': 'O tempo esgotou-se. Volte a escolher uma hora.', 'error.HOLD_NOT_VERIFIED': 'Introduza primeiro o código.', 'error.HOLD_ALREADY_CONFIRMED': 'Esta reserva já está confirmada.',\n 'error.CODE_INVALID': 'Esse código não está correto.', 'error.TOO_MANY_ATTEMPTS': 'Demasiadas tentativas. Recomece.', 'error.RATE_LIMIT_EXCEEDED': 'Demasiados pedidos. Aguarde um minuto e tente novamente.', 'error.CAPTCHA_FAILED': 'Complete a verificação de segurança.', 'error.SMS_UNAVAILABLE': 'Não é possível enviar SMS agora — use o e-mail.', 'error.PAYMENTS_UNAVAILABLE': 'O pagamento com cartão está indisponível — pague no estúdio.', 'error.PAYMENT_MODE_DENIED': 'Esse método de pagamento não é aceite nesta sala.',\n 'error.CANCEL_TOO_LATE': 'É tarde para cancelar online — ligue ao estúdio.', 'error.INVALID_STATE': 'Essa ação não é possível agora.', 'error.INTERNAL_ERROR': 'Algo correu mal. Tente novamente.', 'error.NETWORK_ERROR': 'Sem ligação. Verifique a rede e tente novamente.', 'error.default': 'Algo correu mal. Tente novamente.',\n};\n\nconst it: Dict = {\n 'step.slot': 'Scegli un orario', 'step.details': 'I tuoi dati', 'step.verify': 'Inserisci il codice', 'step.pay': 'Conferma', 'step.done': 'Prenotato', 'step.expired': 'Tempo scaduto',\n 'label.date': 'Data', 'label.time': 'Ora', 'label.duration': 'Durata', 'label.name': 'Nome', 'label.phone': 'Cellulare', 'label.email': 'E-mail', 'label.contact': 'Dove inviare il codice', 'label.code': 'Codice', 'label.notes': 'Note per lo studio',\n 'label.price': 'Prezzo', 'label.deposit': 'Caparra', 'label.total': 'Totale', 'label.perHour': \"all'ora\",\n 'action.continue': 'Continua', 'action.back': 'Indietro', 'action.sendCode': 'Inviami un codice', 'action.verify': 'Verifica', 'action.resend': 'Invia di nuovo', 'action.confirm': 'Conferma la prenotazione', 'action.payCard': 'Paga con carta', 'action.payOnSite': 'Paga in studio', 'action.startOver': 'Ricomincia', 'action.manage': 'Vedi o annulla la prenotazione', 'action.cancel': 'Annulla',\n 'hint.codeSent': 'Abbiamo inviato un codice a {contact}.', 'hint.resendsLeft': '{n} invii rimasti', 'hint.holdExpiresIn': 'Il tuo orario è bloccato per {time}', 'hint.payOnSite': 'Niente da pagare ora; si paga in studio.', 'hint.payCard': 'Viene addebitata ora una caparra di {amount}.', 'hint.cancelNotice': 'Cancellazione gratuita fino a {hours} h prima.', 'hint.sandbox': 'Modalità test: non viene inviato né addebitato nulla, e questa prenotazione sarà eliminata.', 'hint.noSlots': 'Nessun orario libero quel giorno.', 'hint.pickDate': 'Scegli un giorno per vedere gli orari liberi.',\n 'done.title': 'Prenotazione confermata', 'done.reference': 'Riferimento {ref}', 'done.manage': 'Conserva questo link per vedere o annullare la prenotazione.',\n 'channel.phone': 'SMS', 'channel.email': 'E-mail',\n 'pay.card': 'Carta', 'pay.on_site': 'In studio',\n 'error.VALIDATION_ERROR': 'Controlla quello che hai scritto.', 'error.RESOURCE_NOT_FOUND': 'Non trovato.', 'error.SITE_NOT_LIVE': 'Questo studio non accetta ancora prenotazioni online.', 'error.ROOM_NOT_BOOKABLE': 'Questa sala non è prenotabile online al momento.', 'error.STUDIO_NOT_VERIFIED': 'Questo studio non accetta ancora prenotazioni online.',\n 'error.OUTSIDE_HOURS': 'Lo studio è chiuso a quell’ora.', 'error.OUTSIDE_BOOKING_WINDOW': 'Quella data non è ancora prenotabile — provane una più vicina.', 'error.SLOT_TAKEN': 'Quell’orario è appena stato preso. Scegline un altro.', 'error.HOLD_EXPIRED': 'Tempo scaduto. Scegli di nuovo un orario.', 'error.HOLD_NOT_VERIFIED': 'Inserisci prima il codice.', 'error.HOLD_ALREADY_CONFIRMED': 'Questa prenotazione è già confermata.',\n 'error.CODE_INVALID': 'Il codice non è corretto.', 'error.TOO_MANY_ATTEMPTS': 'Troppi tentativi. Ricomincia.', 'error.RATE_LIMIT_EXCEEDED': 'Troppe richieste. Aspetta un minuto e riprova.', 'error.CAPTCHA_FAILED': 'Completa la verifica di sicurezza.', 'error.SMS_UNAVAILABLE': 'Non possiamo inviare SMS al momento — usa l’e-mail.', 'error.PAYMENTS_UNAVAILABLE': 'Il pagamento con carta non è disponibile — paga in studio.', 'error.PAYMENT_MODE_DENIED': 'Questo metodo di pagamento non è accettato per questa sala.',\n 'error.CANCEL_TOO_LATE': 'È troppo tardi per annullare online — chiama lo studio.', 'error.INVALID_STATE': 'Questa azione non è possibile adesso.', 'error.INTERNAL_ERROR': 'Qualcosa è andato storto. Riprova.', 'error.NETWORK_ERROR': 'Nessuna connessione. Controlla la rete e riprova.', 'error.default': 'Qualcosa è andato storto. Riprova.',\n};\n\nconst de: Dict = {\n 'step.slot': 'Zeit wählen', 'step.details': 'Deine Angaben', 'step.verify': 'Code eingeben', 'step.pay': 'Bestätigen', 'step.done': 'Gebucht', 'step.expired': 'Zeit abgelaufen',\n 'label.date': 'Datum', 'label.time': 'Uhrzeit', 'label.duration': 'Dauer', 'label.name': 'Name', 'label.phone': 'Handy', 'label.email': 'E-Mail', 'label.contact': 'Wohin wir den Code schicken', 'label.code': 'Code', 'label.notes': 'Hinweise für das Studio',\n 'label.price': 'Preis', 'label.deposit': 'Anzahlung', 'label.total': 'Gesamt', 'label.perHour': 'pro Stunde',\n 'action.continue': 'Weiter', 'action.back': 'Zurück', 'action.sendCode': 'Code schicken', 'action.verify': 'Prüfen', 'action.resend': 'Erneut senden', 'action.confirm': 'Buchung bestätigen', 'action.payCard': 'Mit Karte zahlen', 'action.payOnSite': 'Im Studio zahlen', 'action.startOver': 'Von vorn beginnen', 'action.manage': 'Buchung ansehen oder stornieren', 'action.cancel': 'Abbrechen',\n 'hint.codeSent': 'Wir haben einen Code an {contact} geschickt.', 'hint.resendsLeft': 'Noch {n} Versuche', 'hint.holdExpiresIn': 'Dein Termin ist {time} lang reserviert', 'hint.payOnSite': 'Jetzt nichts zu zahlen; du zahlst im Studio.', 'hint.payCard': 'Eine Anzahlung von {amount} wird jetzt abgebucht.', 'hint.cancelNotice': 'Kostenlose Stornierung bis {hours} h vorher.', 'hint.sandbox': 'Testmodus: nichts wird gesendet oder abgebucht, und diese Buchung wird gelöscht.', 'hint.noSlots': 'An diesem Tag ist nichts frei.', 'hint.pickDate': 'Wähle einen Tag, um freie Zeiten zu sehen.',\n 'done.title': 'Buchung bestätigt', 'done.reference': 'Referenz {ref}', 'done.manage': 'Bewahre diesen Link auf, um die Buchung anzusehen oder zu stornieren.',\n 'channel.phone': 'SMS', 'channel.email': 'E-Mail',\n 'pay.card': 'Karte', 'pay.on_site': 'Im Studio',\n 'error.VALIDATION_ERROR': 'Bitte prüfe deine Eingaben.', 'error.RESOURCE_NOT_FOUND': 'Nicht gefunden.', 'error.SITE_NOT_LIVE': 'Dieses Studio nimmt noch keine Online-Buchungen an.', 'error.ROOM_NOT_BOOKABLE': 'Dieser Raum kann gerade nicht online gebucht werden.', 'error.STUDIO_NOT_VERIFIED': 'Dieses Studio nimmt noch keine Online-Buchungen an.',\n 'error.OUTSIDE_HOURS': 'Das Studio ist zu dieser Zeit geschlossen.', 'error.OUTSIDE_BOOKING_WINDOW': 'Dieses Datum kann noch nicht gebucht werden — versuche ein näheres.', 'error.SLOT_TAKEN': 'Diese Zeit wurde gerade vergeben. Wähle eine andere.', 'error.HOLD_EXPIRED': 'Zeit abgelaufen. Wähle die Zeit erneut.', 'error.HOLD_NOT_VERIFIED': 'Gib zuerst den Code ein.', 'error.HOLD_ALREADY_CONFIRMED': 'Diese Buchung ist bereits bestätigt.',\n 'error.CODE_INVALID': 'Der Code ist falsch.', 'error.TOO_MANY_ATTEMPTS': 'Zu viele Versuche. Beginne von vorn.', 'error.RATE_LIMIT_EXCEEDED': 'Zu viele Anfragen. Warte eine Minute und versuche es erneut.', 'error.CAPTCHA_FAILED': 'Bitte schließe die Sicherheitsprüfung ab.', 'error.SMS_UNAVAILABLE': 'SMS sind gerade nicht möglich — nutze E-Mail.', 'error.PAYMENTS_UNAVAILABLE': 'Kartenzahlung ist gerade nicht verfügbar — zahle im Studio.', 'error.PAYMENT_MODE_DENIED': 'Diese Zahlungsart wird für diesen Raum nicht akzeptiert.',\n 'error.CANCEL_TOO_LATE': 'Für eine Online-Stornierung ist es zu spät — ruf das Studio an.', 'error.INVALID_STATE': 'Diese Aktion ist gerade nicht möglich.', 'error.INTERNAL_ERROR': 'Etwas ist schiefgelaufen. Versuche es erneut.', 'error.NETWORK_ERROR': 'Keine Verbindung. Prüfe dein Netzwerk und versuche es erneut.', 'error.default': 'Etwas ist schiefgelaufen. Versuche es erneut.',\n};\n\nexport const MESSAGES: Record<Locale, Dict> = { en, es, ca, fr, pt, it, de };\n\n/** Translate a key; `{name}` placeholders are filled from `params`. Unknown keys return the key. */\nexport function t(locale: LocaleInput, key: MessageKey | string, params?: Record<string, string | number>): string {\n const dict = MESSAGES[normalizeLocale(locale)];\n let s = dict[key] ?? en[key] ?? key;\n if (params) for (const [k, v] of Object.entries(params)) s = s.split(`{${k}}`).join(String(v));\n return s;\n}\n\n/** A guest-facing sentence for an error, in the given language. Falls back to the API's English message. */\nexport function messageFor(error: MrCharlesError | { code?: ErrorCode | string; message?: string } | unknown, locale: LocaleInput): string {\n const e = (error ?? {}) as { code?: string; message?: string };\n const dict = MESSAGES[normalizeLocale(locale)];\n if (e.code && dict[`error.${e.code}`]) return dict[`error.${e.code}`];\n if (e.code && en[`error.${e.code}`]) return en[`error.${e.code}`];\n return dict['error.default'];\n}\n\n/** A translator bound to one language: `const tr = translator('fr'); tr('action.confirm')`. */\nexport function translator(locale: LocaleInput) {\n const l = normalizeLocale(locale);\n const fn = (key: MessageKey | string, params?: Record<string, string | number>) => t(l, key, params);\n fn.locale = l;\n fn.error = (error: unknown) => messageFor(error, l);\n return fn;\n}\n",
|
|
9
|
+
"import type { Endpoints } from './env';\nimport { toHostedLocale, type LocaleInput } from './i18n';\n\nexport interface RoomLinkOptions {\n slug: string;\n roomId: string;\n /** YYYY-MM-DD in the studio's zone */\n date?: string;\n /** HH:MM */\n start?: string;\n durationMinutes?: number;\n /** Language of the hosted screen (es, ca, en). Defaults to the client's locale, mapped to the nearest hosted one. */\n lang?: LocaleInput;\n /** Hide the hosted site's header and footer (for iframes) */\n embed?: boolean;\n}\n\nexport function createLinks(endpoints: Endpoints, getLocale: () => LocaleInput | undefined = () => undefined) {\n const siteOrigin = (slug: string) => `https://${slug}.${endpoints.sitesBase}`;\n\n return {\n /** The studio's hosted site */\n site(slug: string): string {\n return `${siteOrigin(slug)}/`;\n },\n\n /** Hosted booking screen for a room, optionally pre-filled */\n bookRoom(o: RoomLinkOptions): string {\n const q = new URLSearchParams();\n if (o.date) q.set('date', o.date);\n if (o.start) q.set('start', o.start);\n if (o.durationMinutes) q.set('duration', String(o.durationMinutes));\n const lang = o.lang ?? getLocale();\n if (lang) q.set('lang', toHostedLocale(lang));\n if (o.embed) q.set('embed', '1');\n const s = q.toString();\n return `${siteOrigin(o.slug)}/reservar/${o.roomId}${s ? `?${s}` : ''}`;\n },\n\n /** A guest's booking page (cancel, details) from the manage token */\n manage(slug: string, manageToken: string): string {\n return `${siteOrigin(slug)}/r/${manageToken}`;\n },\n\n /**\n * Book a lesson in the Mr Charles app. Students need an account there;\n * this is the hand-off. `instructorId` is the teacher's **user** id.\n */\n bookLesson(o: { offerId?: string; instructorId: string }): string {\n const q = new URLSearchParams({ instructorId: o.instructorId });\n if (o.offerId) q.set('offerId', o.offerId);\n return `${endpoints.appBase}/bookings/book?${q.toString()}`;\n },\n\n /** The teacher's public profile in the app */\n teacherProfile(instructorUserId: string): string {\n return `${endpoints.appBase}/instructors/${instructorUserId}`;\n },\n };\n}\n\nexport type Links = ReturnType<typeof createLinks>;\n",
|
|
10
|
+
"import type { Endpoints } from './env';\nimport { createLinks, type RoomLinkOptions } from './links';\nimport type { EmbedBookedEvent, EmbedEvent } from './types';\n\nexport interface EmbedOptions extends Omit<RoomLinkOptions, 'embed'> {\n /** Called once when the guest completes a booking inside the frame */\n onBooked?: (e: EmbedBookedEvent) => void;\n /** Called on every height change; default behaviour sets the iframe height */\n onResize?: (height: number) => void;\n /** Initial height before the first resize message (px). Default 760. */\n height?: number;\n /** Set to false to keep a fixed height instead of following the content */\n autoResize?: boolean;\n title?: string;\n className?: string;\n}\n\nexport interface EmbedHandle {\n iframe: HTMLIFrameElement;\n /** Remove the iframe and the message listener */\n destroy(): void;\n /** Switch the language of the hosted screen (reloads the frame). */\n setLang(lang: string): void;\n}\n\n/** True when a postMessage came from the hosted sites domain of this environment. */\nexport function isTrustedOrigin(origin: string, sitesBase: string): boolean {\n try {\n const host = new URL(origin).host;\n return host === sitesBase || host.endsWith(`.${sitesBase}`);\n } catch {\n return false;\n }\n}\n\nexport function parseEmbedEvent(data: unknown): EmbedEvent | null {\n if (!data || typeof data !== 'object') return null;\n const d = data as Record<string, unknown>;\n if (d.type === 'mrcharles:resize' && typeof d.height === 'number') return { type: 'mrcharles:resize', height: d.height };\n if (d.type === 'mrcharles:booked' && typeof d.reference === 'string') {\n return {\n type: 'mrcharles:booked',\n reference: d.reference,\n bookingId: String(d.bookingId ?? ''),\n manageUrl: String(d.manageUrl ?? ''),\n status: String(d.status ?? ''),\n };\n }\n return null;\n}\n\nexport function createEmbed(endpoints: Endpoints, getLocale: () => string | undefined = () => undefined) {\n const links = createLinks(endpoints, getLocale);\n\n /**\n * Drop the hosted booking screen for a room into `target`. Resizes itself\n * to the content and reports the booking when it happens. Nothing else to\n * wire: codes, payments and the manage link are handled inside the frame.\n */\n function mountRoomBooking(target: HTMLElement | string, opts: EmbedOptions): EmbedHandle {\n const el = typeof target === 'string' ? document.querySelector<HTMLElement>(target) : target;\n if (!el) throw new Error(`@mrcharles/sdk: embed target not found: ${String(target)}`);\n\n const iframe = document.createElement('iframe');\n iframe.src = links.bookRoom({ ...opts, embed: true });\n iframe.title = opts.title ?? 'Mr Charles booking';\n iframe.loading = 'lazy';\n iframe.referrerPolicy = 'strict-origin-when-cross-origin';\n iframe.setAttribute('allow', 'payment');\n iframe.style.width = '100%';\n iframe.style.border = '0';\n iframe.style.display = 'block';\n iframe.style.height = `${opts.height ?? 760}px`;\n if (opts.className) iframe.className = opts.className;\n\n const expectedOrigin = new URL(iframe.src).origin;\n const onMessage = (e: MessageEvent) => {\n if (e.source !== iframe.contentWindow) return;\n if (e.origin !== expectedOrigin && !isTrustedOrigin(e.origin, endpoints.sitesBase)) return;\n const ev = parseEmbedEvent(e.data);\n if (!ev) return;\n if (ev.type === 'mrcharles:resize') {\n if (opts.autoResize !== false) iframe.style.height = `${ev.height}px`;\n opts.onResize?.(ev.height);\n } else {\n opts.onBooked?.(ev);\n }\n };\n window.addEventListener('message', onMessage);\n el.appendChild(iframe);\n\n return {\n iframe,\n /** Switch the language of the hosted screen (reloads the frame). */\n setLang(lang: string) {\n iframe.src = links.bookRoom({ ...opts, lang, embed: true });\n },\n destroy() {\n window.removeEventListener('message', onMessage);\n iframe.remove();\n },\n };\n }\n\n return { mountRoomBooking };\n}\n",
|
|
10
11
|
"/** RFC 4122 v4, with a fallback for runtimes without crypto.randomUUID. */\nexport function uuid(): string {\n const c = (globalThis as { crypto?: Crypto }).crypto;\n if (c?.randomUUID) return c.randomUUID();\n const b = new Uint8Array(16);\n if (c?.getRandomValues) c.getRandomValues(b);\n else for (let i = 0; i < 16; i++) b[i] = Math.floor(Math.random() * 256);\n b[6] = (b[6] & 0x0f) | 0x40;\n b[8] = (b[8] & 0x3f) | 0x80;\n const h = [...b].map((x) => x.toString(16).padStart(2, '0')).join('');\n return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;\n}\n",
|
|
11
12
|
"import type { FreeSpan } from './types';\n\n/** \"17:30\" → 1050 */\nexport function toMinutes(hhmm: string): number {\n const [h, m] = hhmm.split(':').map(Number);\n return (h || 0) * 60 + (m || 0);\n}\n\n/** 1050 → \"17:30\" */\nexport function toHHMM(minutes: number): string {\n const h = Math.floor(minutes / 60);\n const m = minutes % 60;\n return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;\n}\n\nexport function addMinutes(hhmm: string, minutes: number): string {\n return toHHMM(toMinutes(hhmm) + minutes);\n}\n\n/**\n * Every start time at which a booking of `durationMinutes` fits inside one\n * of the free spans, on the `stepMinutes` grid. Sorted, de-duplicated.\n */\nexport function startTimes(free: FreeSpan[], durationMinutes: number, stepMinutes: number): string[] {\n const step = Math.max(1, stepMinutes);\n const out = new Set<string>();\n for (const span of free) {\n const s = toMinutes(span.start);\n const e = toMinutes(span.end);\n for (let t = Math.ceil(s / step) * step; t + durationMinutes <= e; t += step) out.add(toHHMM(t));\n }\n return [...out].sort((a, b) => toMinutes(a) - toMinutes(b));\n}\n\n/** Durations between min and max, on the step grid, that still fit after `start`. */\nexport function durationOptions(free: FreeSpan[], start: string, minMinutes: number, maxMinutes: number, stepMinutes: number): number[] {\n const s = toMinutes(start);\n const span = free.find((f) => toMinutes(f.start) <= s && s < toMinutes(f.end));\n if (!span) return [];\n const room = toMinutes(span.end) - s;\n const out: number[] = [];\n for (let d = minMinutes; d <= maxMinutes && d <= room; d += Math.max(1, stepMinutes)) out.push(d);\n return out;\n}\n\n/** 2500, \"EUR\" → \"25,00 €\" (locale-aware; minor units in, string out). */\nexport function formatPrice(cents: number, currency: string, locale = 'es-ES'): string {\n try {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(cents / 100);\n } catch {\n return `${(cents / 100).toFixed(2)} ${currency}`;\n }\n}\n\n/** \"2026-10-12\" for a Date, in the given IANA zone (today in the studio's zone). */\nexport function dateKey(date: Date, timeZone: string): string {\n const parts = new Intl.DateTimeFormat('en-CA', { timeZone, year: 'numeric', month: '2-digit', day: '2-digit' }).formatToParts(date);\n const get = (t: string) => parts.find((p) => p.type === t)?.value ?? '';\n return `${get('year')}-${get('month')}-${get('day')}`;\n}\n\n/** YYYY-MM-DD plus n days, calendar arithmetic only (no zone involved). */\nexport function addDays(key: string, days: number): string {\n const [y, m, d] = key.split('-').map(Number);\n const t = Date.UTC(y, m - 1, d + days);\n return new Date(t).toISOString().slice(0, 10);\n}\n",
|
|
12
|
-
"import type { Http } from './http';\nimport { MrCharlesError, isMrCharlesError } from './errors';\nimport { uuid } from './uuid';\nimport { addDays, dateKey, durationOptions, startTimes } from './slots';\nimport type { Links } from './links';\nimport type { Channel, ConfirmRequest, Confirmation, Hold, HoldRequest, Locale, PublicRoom, PublicSite, RoomAvailability } from './types';\n\nexport type RoomStep = 'slot' | 'details' | 'verify' | 'pay' | 'done' | 'expired';\n\nexport interface RoomBookingState {\n step: RoomStep;\n site: PublicSite | null;\n room: PublicRoom | null;\n availability: RoomAvailability | null;\n hold: Hold | null;\n confirmation: Confirmation | null;\n /** Last error from any action; cleared on the next successful one */\n error: MrCharlesError | null;\n busy: boolean;\n}\n\nexport interface GuestDetails {\n date: string;\n startTime: string;\n durationMinutes: number;\n guestName: string;\n channel: Channel;\n contact: string;\n locale?: Locale;\n captchaToken?: string;\n}\n\nexport interface RoomBookingOptions {\n slug: string;\n roomId: string;\n /** Called on every state change */\n onChange?: (state: RoomBookingState) => void;\n}\n\nexport interface RoomBooking {\n readonly state: RoomBookingState;\n subscribe(fn: (state: RoomBookingState) => void): () => void;\n\n /** Site payload (cached 60 s server-side). Resolves the room too. */\n loadSite(): Promise<PublicSite>;\n /** Free spans for a window; defaults to the next 14 days from today in the studio's zone. */\n loadAvailability(window?: { from?: string; to?: string; days?: number }): Promise<RoomAvailability>;\n /** Start times for a date and duration, from the loaded availability. */\n startTimesFor(date: string, durationMinutes: number): string[];\n /** Durations that fit after a start time, from the loaded availability. */\n durationsFor(date: string, startTime: string): number[];\n\n /** Reserve the slot and send the code. One idempotency key per attempt is handled for you. */\n hold(details: GuestDetails): Promise<Hold>;\n verify(code: string): Promise<Hold>;\n resend(): Promise<Hold>;\n confirm(req: ConfirmRequest): Promise<Confirmation>;\n\n /** Milliseconds until the hold expires; 0 when there is no live hold. */\n remainingMs(): number;\n /** Forget the hold and start over (new idempotency key). Keeps site and availability. */\n reset(): void;\n destroy(): void;\n}\n\n/**\n * The whole guest flow for one room as a small state machine: availability →\n * hold → code → confirm, with the expiry timer, idempotency key and error\n * classification handled. Render it with any UI.\n */\nexport function createRoomBooking(http: Http, links: Links, opts: RoomBookingOptions): RoomBooking {\n let state: RoomBookingState = { step: 'slot', site: null, room: null, availability: null, hold: null, confirmation: null, error: null, busy: false };\n const listeners = new Set<(s: RoomBookingState) => void>();\n if (opts.onChange) listeners.add(opts.onChange);\n let idempotencyKey = uuid();\n let expiryTimer: ReturnType<typeof setTimeout> | undefined;\n\n const set = (patch: Partial<RoomBookingState>) => {\n state = { ...state, ...patch };\n for (const l of listeners) l(state);\n };\n\n const clearTimer = () => {\n if (expiryTimer) clearTimeout(expiryTimer);\n expiryTimer = undefined;\n };\n\n const armTimer = (hold: Hold) => {\n clearTimer();\n const ms = new Date(hold.expiresAt).getTime() - Date.now();\n if (ms <= 0) return;\n expiryTimer = setTimeout(() => {\n if (state.step === 'verify' || state.step === 'pay') {\n idempotencyKey = uuid();\n set({ step: 'expired', error: new MrCharlesError('HOLD_EXPIRED', 'The hold expired. Pick a time again.', 410) });\n }\n }, ms);\n };\n\n async function run<T>(fn: () => Promise<T>): Promise<T> {\n set({ busy: true });\n try {\n const out = await fn();\n set({ busy: false, error: null });\n return out;\n } catch (e) {\n const err = isMrCharlesError(e) ? e : new MrCharlesError('INTERNAL_ERROR', (e as Error)?.message ?? 'Unexpected error');\n if (err.holdIsDead) {\n clearTimer();\n idempotencyKey = uuid();\n set({ busy: false, error: err, step: 'expired', hold: null });\n } else {\n set({ busy: false, error: err });\n }\n throw err;\n }\n }\n\n const api: RoomBooking = {\n get state() {\n return state;\n },\n subscribe(fn) {\n listeners.add(fn);\n fn(state);\n return () => {\n listeners.delete(fn);\n };\n },\n\n loadSite: () =>\n run(async () => {\n const site = await http.get<PublicSite>(`/public/sites/${encodeURIComponent(opts.slug)}`);\n const room = site.rooms.find((r) => r.id === opts.roomId) ?? null;\n if (!room) throw new MrCharlesError('RESOURCE_NOT_FOUND', `Room ${opts.roomId} is not on site ${opts.slug}`, 404);\n if (!room.bookable) throw new MrCharlesError('ROOM_NOT_BOOKABLE', `${room.name} does not take online bookings right now`, 409);\n set({ site, room });\n return site;\n }),\n\n loadAvailability: (window = {}) =>\n run(async () => {\n const tz = state.site?.studio.timezone ?? 'UTC';\n const from = window.from ?? dateKey(new Date(), tz);\n const to = window.to ?? addDays(from, Math.min(31, Math.max(1, window.days ?? 14)) - 1);\n const availability = await http.get<RoomAvailability>(\n `/public/sites/${encodeURIComponent(opts.slug)}/rooms/${encodeURIComponent(opts.roomId)}/availability`,\n { from, to },\n );\n set({ availability });\n return availability;\n }),\n\n startTimesFor(date, durationMinutes) {\n const a = state.availability;\n if (!a) return [];\n const day = a.days.find((d) => d.date === date);\n return day ? startTimes(day.free, durationMinutes, a.stepMinutes) : [];\n },\n\n durationsFor(date, startTime) {\n const a = state.availability;\n if (!a) return [];\n const day = a.days.find((d) => d.date === date);\n return day ? durationOptions(day.free, startTime, a.minMinutes, a.maxMinutes, a.stepMinutes) : [];\n },\n\n hold: (details) =>\n run(async () => {\n if (state.step === 'expired') set({ step: 'slot', error: null });\n const body: HoldRequest = {\n roomId: opts.roomId,\n date: details.date,\n startTime: details.startTime,\n durationMinutes: details.durationMinutes,\n guestName: details.guestName,\n channel: details.channel,\n contact: details.contact,\n locale: details.locale ?? state.site?.site.defaultLocale ?? 'es',\n idempotencyKey,\n ...(details.captchaToken ? { captchaToken: details.captchaToken } : {}),\n };\n const hold = await http.post<Hold>(`/public/sites/${encodeURIComponent(opts.slug)}/holds`, body);\n armTimer(hold);\n set({ hold, step: 'verify', confirmation: null });\n return hold;\n }),\n\n verify: (code) =>\n run(async () => {\n const id = requireHold(state).holdId;\n const hold = await http.post<Hold>(`/public/holds/${id}/verify`, { code: code.replace(/\\D/g, '') });\n set({ hold, step: 'pay' });\n return hold;\n }),\n\n resend: () =>\n run(async () => {\n const id = requireHold(state).holdId;\n const hold = await http.post<Hold>(`/public/holds/${id}/resend`);\n set({ hold });\n return hold;\n }),\n\n confirm: (req) =>\n run(async () => {\n const h = requireHold(state);\n if (!h.paymentModes.includes(req.paymentMode)) {\n throw new MrCharlesError('PAYMENT_MODE_DENIED', `This room does not accept ${req.paymentMode}`, 409);\n }\n const confirmation = await http.post<Confirmation>(`/public/holds/${h.holdId}/confirm`, {\n paymentMode: req.paymentMode,\n notes: req.notes ?? '',\n email: req.email ?? '',\n });\n clearTimer();\n if (!confirmation.manageUrl && confirmation.manageToken) confirmation.manageUrl = links.manage(opts.slug, confirmation.manageToken);\n set({ confirmation, step: 'done' });\n return confirmation;\n }),\n\n remainingMs() {\n const h = state.hold;\n if (!h || state.step === 'done' || state.step === 'expired') return 0;\n return Math.max(0, new Date(h.expiresAt).getTime() - Date.now());\n },\n\n reset() {\n clearTimer();\n idempotencyKey = uuid();\n set({ step: 'slot', hold: null, confirmation: null, error: null, busy: false });\n },\n\n destroy() {\n clearTimer();\n listeners.clear();\n },\n };\n\n return api;\n}\n\nfunction requireHold(s: RoomBookingState): Hold {\n if (!s.hold) throw new MrCharlesError('INVALID_STATE', 'No hold yet — call hold() first', 409);\n return s.hold;\n}\n",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
13
|
+
"import type { Http } from './http';\nimport { MrCharlesError, isMrCharlesError } from './errors';\nimport { uuid } from './uuid';\nimport { addDays, dateKey, durationOptions, startTimes } from './slots';\nimport type { Links } from './links';\nimport { messageFor, normalizeLocale, t, toHostedLocale, type Locale, type LocaleInput } from './i18n';\nimport type { Channel, ConfirmRequest, Confirmation, Hold, HoldRequest, PublicRoom, PublicSite, RoomAvailability } from './types';\n\nexport type RoomStep = 'slot' | 'details' | 'verify' | 'pay' | 'done' | 'expired';\n\nexport interface RoomBookingState {\n step: RoomStep;\n site: PublicSite | null;\n room: PublicRoom | null;\n availability: RoomAvailability | null;\n hold: Hold | null;\n confirmation: Confirmation | null;\n /** Last error from any action; cleared on the next successful one */\n error: MrCharlesError | null;\n /** `error` as a sentence in the flow's language — show this one. */\n errorMessage: string | null;\n busy: boolean;\n /** Language of the flow's strings and of the guest's messages. */\n locale: Locale;\n}\n\nexport interface GuestDetails {\n date: string;\n startTime: string;\n durationMinutes: number;\n guestName: string;\n channel: Channel;\n contact: string;\n /** Language of the guest's code and confirmation; defaults to the flow's locale. */\n locale?: LocaleInput;\n captchaToken?: string;\n}\n\nexport interface RoomBookingOptions {\n slug: string;\n roomId: string;\n /** Called on every state change */\n onChange?: (state: RoomBookingState) => void;\n /** Language for strings, errors and the guest's messages. Defaults to the client's locale, then the site's default. */\n locale?: LocaleInput;\n}\n\nexport interface RoomBooking {\n readonly state: RoomBookingState;\n subscribe(fn: (state: RoomBookingState) => void): () => void;\n\n /** Site payload (cached 60 s server-side). Resolves the room too. */\n loadSite(): Promise<PublicSite>;\n /** Free spans for a window; defaults to the next 14 days from today in the studio's zone. */\n loadAvailability(window?: { from?: string; to?: string; days?: number }): Promise<RoomAvailability>;\n /** Start times for a date and duration, from the loaded availability. */\n startTimesFor(date: string, durationMinutes: number): string[];\n /** Durations that fit after a start time, from the loaded availability. */\n durationsFor(date: string, startTime: string): number[];\n\n /** Reserve the slot and send the code. One idempotency key per attempt is handled for you. */\n hold(details: GuestDetails): Promise<Hold>;\n verify(code: string): Promise<Hold>;\n resend(): Promise<Hold>;\n confirm(req: ConfirmRequest): Promise<Confirmation>;\n\n /** Milliseconds until the hold expires; 0 when there is no live hold. */\n remainingMs(): number;\n /** Forget the hold and start over (new idempotency key). Keeps site and availability. */\n reset(): void;\n destroy(): void;\n\n /** Translate a UI string in the flow's language: `flow.t('action.confirm')`. */\n t(key: string, params?: Record<string, string | number>): string;\n /** Switch language mid-flow (a language switcher on the page). */\n setLocale(locale: LocaleInput): void;\n}\n\n/**\n * The whole guest flow for one room as a small state machine: availability →\n * hold → code → confirm, with the expiry timer, idempotency key and error\n * classification handled. Render it with any UI.\n */\nexport function createRoomBooking(http: Http, links: Links, opts: RoomBookingOptions, clientLocale?: () => LocaleInput | undefined): RoomBooking {\n const explicit = opts.locale ?? clientLocale?.();\n let state: RoomBookingState = {\n step: 'slot', site: null, room: null, availability: null, hold: null, confirmation: null, error: null, errorMessage: null, busy: false,\n locale: normalizeLocale(explicit, 'es'),\n };\n const listeners = new Set<(s: RoomBookingState) => void>();\n if (opts.onChange) listeners.add(opts.onChange);\n let idempotencyKey = uuid();\n let expiryTimer: ReturnType<typeof setTimeout> | undefined;\n\n const set = (patch: Partial<RoomBookingState>) => {\n state = { ...state, ...patch };\n if ('error' in patch || 'locale' in patch) state.errorMessage = state.error ? messageFor(state.error, state.locale) : null;\n for (const l of listeners) l(state);\n };\n\n const clearTimer = () => {\n if (expiryTimer) clearTimeout(expiryTimer);\n expiryTimer = undefined;\n };\n\n const armTimer = (hold: Hold) => {\n clearTimer();\n const ms = new Date(hold.expiresAt).getTime() - Date.now();\n if (ms <= 0) return;\n expiryTimer = setTimeout(() => {\n if (state.step === 'verify' || state.step === 'pay') {\n idempotencyKey = uuid();\n set({ step: 'expired', error: new MrCharlesError('HOLD_EXPIRED', t(state.locale, 'error.HOLD_EXPIRED'), 410) });\n }\n }, ms);\n };\n\n async function run<T>(fn: () => Promise<T>): Promise<T> {\n set({ busy: true });\n try {\n const out = await fn();\n set({ busy: false, error: null });\n return out;\n } catch (e) {\n const err = isMrCharlesError(e) ? e : new MrCharlesError('INTERNAL_ERROR', (e as Error)?.message ?? 'Unexpected error');\n if (err.holdIsDead) {\n clearTimer();\n idempotencyKey = uuid();\n set({ busy: false, error: err, step: 'expired', hold: null });\n } else {\n set({ busy: false, error: err });\n }\n throw err;\n }\n }\n\n const api: RoomBooking = {\n get state() {\n return state;\n },\n subscribe(fn) {\n listeners.add(fn);\n fn(state);\n return () => {\n listeners.delete(fn);\n };\n },\n\n loadSite: () =>\n run(async () => {\n const site = await http.get<PublicSite>(`/public/sites/${encodeURIComponent(opts.slug)}`);\n const room = site.rooms.find((r) => r.id === opts.roomId) ?? null;\n if (!room) throw new MrCharlesError('RESOURCE_NOT_FOUND', `Room ${opts.roomId} is not on site ${opts.slug}`, 404);\n if (!room.bookable) throw new MrCharlesError('ROOM_NOT_BOOKABLE', `${room.name} does not take online bookings right now`, 409);\n // No language asked for → the site's default, so the guest's messages match the studio.\n const locale = explicit ? state.locale : normalizeLocale(site.site?.defaultLocale, state.locale);\n set({ site, room, locale });\n return site;\n }),\n\n loadAvailability: (window = {}) =>\n run(async () => {\n const tz = state.site?.studio.timezone ?? 'UTC';\n const from = window.from ?? dateKey(new Date(), tz);\n const to = window.to ?? addDays(from, Math.min(31, Math.max(1, window.days ?? 14)) - 1);\n const availability = await http.get<RoomAvailability>(\n `/public/sites/${encodeURIComponent(opts.slug)}/rooms/${encodeURIComponent(opts.roomId)}/availability`,\n { from, to },\n );\n set({ availability });\n return availability;\n }),\n\n startTimesFor(date, durationMinutes) {\n const a = state.availability;\n if (!a) return [];\n const day = a.days.find((d) => d.date === date);\n return day ? startTimes(day.free, durationMinutes, a.stepMinutes) : [];\n },\n\n durationsFor(date, startTime) {\n const a = state.availability;\n if (!a) return [];\n const day = a.days.find((d) => d.date === date);\n return day ? durationOptions(day.free, startTime, a.minMinutes, a.maxMinutes, a.stepMinutes) : [];\n },\n\n hold: (details) =>\n run(async () => {\n if (state.step === 'expired') set({ step: 'slot', error: null });\n const body: HoldRequest = {\n roomId: opts.roomId,\n date: details.date,\n startTime: details.startTime,\n durationMinutes: details.durationMinutes,\n guestName: details.guestName,\n channel: details.channel,\n contact: details.contact,\n locale: toHostedLocale(details.locale ?? state.locale),\n idempotencyKey,\n ...(details.captchaToken ? { captchaToken: details.captchaToken } : {}),\n };\n const hold = await http.post<Hold>(`/public/sites/${encodeURIComponent(opts.slug)}/holds`, body);\n armTimer(hold);\n set({ hold, step: 'verify', confirmation: null });\n return hold;\n }),\n\n verify: (code) =>\n run(async () => {\n const id = requireHold(state).holdId;\n const hold = await http.post<Hold>(`/public/holds/${id}/verify`, { code: code.replace(/\\D/g, '') });\n set({ hold, step: 'pay' });\n return hold;\n }),\n\n resend: () =>\n run(async () => {\n const id = requireHold(state).holdId;\n const hold = await http.post<Hold>(`/public/holds/${id}/resend`);\n set({ hold });\n return hold;\n }),\n\n confirm: (req) =>\n run(async () => {\n const h = requireHold(state);\n if (!h.paymentModes.includes(req.paymentMode)) {\n throw new MrCharlesError('PAYMENT_MODE_DENIED', `This room does not accept ${req.paymentMode}`, 409);\n }\n const confirmation = await http.post<Confirmation>(`/public/holds/${h.holdId}/confirm`, {\n paymentMode: req.paymentMode,\n notes: req.notes ?? '',\n email: req.email ?? '',\n });\n clearTimer();\n if (!confirmation.manageUrl && confirmation.manageToken) confirmation.manageUrl = links.manage(opts.slug, confirmation.manageToken);\n set({ confirmation, step: 'done' });\n return confirmation;\n }),\n\n remainingMs() {\n const h = state.hold;\n if (!h || state.step === 'done' || state.step === 'expired') return 0;\n return Math.max(0, new Date(h.expiresAt).getTime() - Date.now());\n },\n\n reset() {\n clearTimer();\n idempotencyKey = uuid();\n set({ step: 'slot', hold: null, confirmation: null, error: null, busy: false });\n },\n\n t: (key, params) => t(state.locale, key, params),\n setLocale(locale) {\n set({ locale: normalizeLocale(locale, state.locale) });\n },\n\n destroy() {\n clearTimer();\n listeners.clear();\n },\n };\n\n return api;\n}\n\nfunction requireHold(s: RoomBookingState): Hold {\n if (!s.hold) throw new MrCharlesError('INVALID_STATE', 'No hold yet — call hold() first', 409);\n return s.hold;\n}\n",
|
|
14
|
+
"/**\n * Locale-aware formatting for what a booking UI shows: money, dates, times,\n * durations and the hold countdown. Intl does the work; this only picks the\n * right tag and the conventions guests expect (24 h in Europe, \"1 h 30 min\").\n */\nimport { intlTag, normalizeLocale, type LocaleInput } from './i18n';\n\nexport interface Formatter {\n readonly locale: string;\n /** 2500, \"EUR\" → \"25,00 €\" (es) / \"€25.00\" (en) */\n price(cents: number, currency: string): string;\n /** \"2026-10-20\" → \"lunes, 20 de octubre\" (es) / \"Monday 20 October\" (en); pass a style for short forms. */\n date(dateKey: string, style?: 'long' | 'medium' | 'short'): string;\n /** \"17:00\" → \"17:00\" (es, en-GB…) or \"5:00 pm\" (en-US) */\n time(hhmm: string): string;\n /** \"17:00\", 120 → \"17:00 – 19:00\" */\n timeRange(startHHMM: string, minutes: number): string;\n /** 90 → \"1 h 30 min\"; 60 → \"1 h\"; 45 → \"45 min\" */\n duration(minutes: number): string;\n /** 0..6 (Sunday first, like the API) → \"lun.\" / \"Mon\" */\n weekday(dayOfWeek: number, style?: 'long' | 'short' | 'narrow'): string;\n /** Milliseconds → \"11:58\" for the hold timer */\n countdown(ms: number): string;\n}\n\nexport function createFormatter(locale: LocaleInput): Formatter {\n const tag = intlTag(locale);\n const lang = normalizeLocale(locale);\n const hourAbbr: Record<string, [string, string]> = { es: ['h', 'min'], ca: ['h', 'min'], en: ['h', 'min'], fr: ['h', 'min'], pt: ['h', 'min'], it: ['h', 'min'], de: ['Std.', 'Min.'] };\n const [hU, mU] = hourAbbr[lang] ?? ['h', 'min'];\n\n const safe = <T>(fn: () => T, fallback: T): T => {\n try { return fn(); } catch { return fallback; }\n };\n\n return {\n locale: tag,\n price: (cents, currency) =>\n safe(() => new Intl.NumberFormat(tag, { style: 'currency', currency }).format(cents / 100), `${(cents / 100).toFixed(2)} ${currency}`),\n date: (key, style = 'long') => {\n const [y, m, d] = key.split('-').map(Number);\n const dt = new Date(Date.UTC(y, m - 1, d, 12));\n const opts: Intl.DateTimeFormatOptions =\n style === 'long' ? { weekday: 'long', day: 'numeric', month: 'long', timeZone: 'UTC' }\n : style === 'medium' ? { weekday: 'short', day: 'numeric', month: 'short', timeZone: 'UTC' }\n : { day: '2-digit', month: '2-digit', timeZone: 'UTC' };\n return safe(() => new Intl.DateTimeFormat(tag, opts).format(dt), key);\n },\n time: (hhmm) => {\n const [h, mi] = hhmm.split(':').map(Number);\n const dt = new Date(Date.UTC(2000, 0, 1, h, mi));\n return safe(() => new Intl.DateTimeFormat(tag, { hour: 'numeric', minute: '2-digit', timeZone: 'UTC' }).format(dt), hhmm);\n },\n timeRange(start, minutes) {\n const [h, mi] = start.split(':').map(Number);\n const total = h * 60 + mi + minutes;\n const end = `${String(Math.floor(total / 60) % 24).padStart(2, '0')}:${String(total % 60).padStart(2, '0')}`;\n return `${this.time(start)} – ${this.time(end)}`;\n },\n duration: (minutes) => {\n const h = Math.floor(minutes / 60);\n const m = minutes % 60;\n if (h && m) return `${h} ${hU} ${m} ${mU}`;\n if (h) return `${h} ${hU}`;\n return `${m} ${mU}`;\n },\n weekday: (dow, style = 'short') => {\n const dt = new Date(Date.UTC(2023, 0, 1 + ((dow % 7) + 7) % 7, 12)); // 2023-01-01 was a Sunday\n return safe(() => new Intl.DateTimeFormat(tag, { weekday: style, timeZone: 'UTC' }).format(dt), String(dow));\n },\n countdown: (ms) => {\n const s = Math.max(0, Math.floor(ms / 1000));\n return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, '0')}`;\n },\n };\n}\n",
|
|
15
|
+
"import { type ClientConfig, type Endpoints, resolveEndpoints } from './env';\nimport { createHttp } from './http';\nimport { createLinks } from './links';\nimport { createEmbed } from './embed';\nimport { createRoomBooking, type RoomBookingOptions } from './rooms';\nimport { messageFor, normalizeLocale, pick, t, toHostedLocale, type Locale, type LocaleInput } from './i18n';\nimport { createFormatter, type Formatter } from './format';\nimport type {\n Booking, ConfirmRequest, Confirmation, Hold, HoldRequest, LessonOffer, LessonPolicy, LessonSlots,\n PublicSite, RoomAvailability, TeacherProfile, TeacherWindows,\n} from './types';\n\nexport function createClient(config: ClientConfig = {}) {\n const endpoints: Endpoints = resolveEndpoints(config);\n // One language for everything; `undefined` means \"the site's default\".\n let locale: Locale | undefined = config.locale ? normalizeLocale(config.locale) : undefined;\n let formatter: Formatter | undefined;\n const getLocale = () => locale;\n const http = createHttp(endpoints.apiBase, config, getLocale);\n const links = createLinks(endpoints, getLocale);\n const embed = createEmbed(endpoints, getLocale);\n const enc = encodeURIComponent;\n\n const sites = {\n /** Everything needed to render a studio: rooms, prices, hours, payment and captcha keys. */\n get: (slug: string) => http.get<PublicSite>(`/public/sites/${enc(slug)}`),\n /** The site behind a custom domain. */\n resolve: (host: string) => http.get<PublicSite>('/public/sites/resolve', { host }),\n /** Free spans for a room between two dates (≤ 31 days), in the studio's zone. Never cache. */\n availability: (slug: string, roomId: string, range: { from: string; to: string }) =>\n http.get<RoomAvailability>(`/public/sites/${enc(slug)}/rooms/${enc(roomId)}/availability`, range),\n };\n\n const holds = {\n create: (slug: string, req: HoldRequest) => http.post<Hold>(`/public/sites/${enc(slug)}/holds`, req),\n verify: (holdId: string, code: string) => http.post<Hold>(`/public/holds/${enc(holdId)}/verify`, { code }),\n resend: (holdId: string) => http.post<Hold>(`/public/holds/${enc(holdId)}/resend`),\n confirm: (holdId: string, req: ConfirmRequest) =>\n http.post<Confirmation>(`/public/holds/${enc(holdId)}/confirm`, { paymentMode: req.paymentMode, notes: req.notes ?? '', email: req.email ?? '' }),\n };\n\n const bookings = {\n /** A guest's booking from its manage token. Poll this after a card payment. */\n get: (manageToken: string) => http.get<Booking>(`/public/bookings/manage/${enc(manageToken)}`),\n cancel: (manageToken: string, reason = '') => http.post<Booking>(`/public/bookings/manage/${enc(manageToken)}/cancel`, { reason }),\n };\n\n const teachers = {\n /** Public teacher profile. `instructorUserId` is the teacher's user id; the response's `user.id` is the one to keep. */\n profile: (instructorUserId: string) => http.get<TeacherProfile>(`/instructors/${enc(instructorUserId)}/teacher-profile`),\n /** Published lesson offers. */\n offers: (instructorUserId: string) => http.get<LessonOffer[]>(`/instructors/${enc(instructorUserId)}/offers`),\n offer: (offerId: string) => http.get<LessonOffer>(`/offers/${enc(offerId)}`),\n /** Free windows in the teacher's zone; use `slots` for something bookable. */\n windows: (instructorUserId: string, range: { from: string; to: string }) =>\n http.get<TeacherWindows>(`/availability/${enc(instructorUserId)}/windows`, range),\n policy: (instructorUserId: string) => http.get<LessonPolicy>(`/availability/${enc(instructorUserId)}/policy`),\n /** Concrete bookable start times for an offer — duration, policy and existing lessons applied. */\n slots: (q: { instructorUserId: string; offerId: string; date: string; days?: number }) =>\n http.get<LessonSlots>('/bookings/slots', { instructorId: q.instructorUserId, offerId: q.offerId, date: q.date, days: q.days ?? 7 }),\n };\n\n return {\n endpoints,\n sites,\n holds,\n bookings,\n teachers,\n links,\n /** Drop our hosted booking screen into your page. */\n mountRoomBooking: embed.mountRoomBooking,\n /** The headless flow for one room: availability → hold → code → confirm. */\n roomBooking: (opts: RoomBookingOptions) => createRoomBooking(http, links, opts, getLocale),\n\n // ── Languages ─────────────────────────────────────────────────────\n /** The client's language (undefined = each site's default). */\n get locale(): Locale | undefined {\n return locale;\n },\n /** The language the hosted screen and the guest's messages will use. */\n get hostedLocale() {\n return locale ? toHostedLocale(locale) : 'es';\n },\n /** Switch language at runtime: links, embeds, new flows, `t()` and `format` follow. */\n setLocale(next: LocaleInput | undefined) {\n locale = next ? normalizeLocale(next) : undefined;\n formatter = undefined;\n },\n /** A UI string in the client's language: `mc.t('action.confirm')`. */\n t: (key: string, params?: Record<string, string | number>) => t(locale ?? 'en', key, params),\n /** A guest-facing sentence for any error, in the client's language. */\n errorMessage: (error: unknown) => messageFor(error, locale ?? 'en'),\n /** Money, dates, times, durations and the hold countdown in the client's language. */\n get format(): Formatter {\n return (formatter ??= createFormatter(locale ?? 'en'));\n },\n /** Read one language out of a `{ es, ca, en }` object from the payload. */\n pick: (localized: Parameters<typeof pick>[0], defaultLocale?: LocaleInput) => pick(localized, locale ?? defaultLocale ?? 'es', defaultLocale),\n };\n}\n\nexport type MrCharlesClient = ReturnType<typeof createClient>;\n",
|
|
16
|
+
"export { createClient, type MrCharlesClient } from './client';\nexport { MrCharlesError, isMrCharlesError, type ErrorCode } from './errors';\nexport { ENVIRONMENTS, resolveEndpoints, type ClientConfig, type Endpoints, type Environment } from './env';\nexport { createRoomBooking, type RoomBooking, type RoomBookingOptions, type RoomBookingState, type RoomStep, type GuestDetails } from './rooms';\nexport { createLinks, type Links, type RoomLinkOptions } from './links';\nexport { createEmbed, isTrustedOrigin, parseEmbedEvent, type EmbedHandle, type EmbedOptions } from './embed';\nexport { startTimes, durationOptions, toMinutes, toHHMM, addMinutes, formatPrice, dateKey, addDays } from './slots';\nexport { uuid } from './uuid';\nexport {\n LOCALES, HOSTED_LOCALES, MESSAGES, normalizeLocale, toHostedLocale, intlTag, pick, t, messageFor, translator,\n type Locale, type HostedLocale, type LocaleInput, type MessageKey,\n} from './i18n';\nexport { createFormatter, type Formatter } from './format';\nexport type * from './types';\n\nexport const VERSION = '0.2.0';\n"
|
|
15
17
|
],
|
|
16
|
-
"mappings": "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",
|
|
17
|
-
"debugId": "
|
|
18
|
+
"mappings": "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",
|
|
19
|
+
"debugId": "1DCD9FB716D0EA3864756E2164756E21",
|
|
18
20
|
"names": []
|
|
19
21
|
}
|
package/dist/mrcharles.min.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(()=>{var W=Object.defineProperty;var q=(t)=>t;function z(t,o){this[t]=q.bind(null,o)}var j=(t,o)=>{for(var e in o)W(t,e,{get:o[e],enumerable:!0,configurable:!0,set:z.bind(o,e)})};var A={};j(A,{ENVIRONMENTS:()=>B,MrCharlesError:()=>f,VERSION:()=>G,addDays:()=>v,addMinutes:()=>U,createClient:()=>V,createEmbed:()=>I,createLinks:()=>R,createRoomBooking:()=>w,dateKey:()=>M,durationOptions:()=>x,formatPrice:()=>F,isMrCharlesError:()=>k,isTrustedOrigin:()=>N,parseEmbedEvent:()=>D,resolveEndpoints:()=>O,startTimes:()=>C,toHHMM:()=>S,toMinutes:()=>b,uuid:()=>E});var B={production:{apiBase:"https://api.mrcharles.app/api/v1",appBase:"https://app.mrcharles.app",sitesBase:"sites.mrcharles.app"}};function O(t={}){let o=B[t.env??"production"];return{apiBase:P(t.apiBase??o.apiBase),appBase:P(t.appBase??o.appBase),sitesBase:(t.sitesBase??o.sitesBase).replace(/^https?:\/\//,"").replace(/\/+$/,"")}}function P(t){return t.replace(/\/+$/,"")}class f extends Error{code;status;requestId;constructor(t,o,e=0,n){super(o);this.name="MrCharlesError",this.code=t,this.status=e,this.requestId=n}get holdIsDead(){return this.code==="HOLD_EXPIRED"||this.code==="TOO_MANY_ATTEMPTS"}get slotIsGone(){return this.code==="SLOT_TAKEN"||this.code==="OUTSIDE_HOURS"||this.code==="OUTSIDE_BOOKING_WINDOW"}get isTransient(){return this.code==="NETWORK_ERROR"||this.status>=500}}function k(t){return t instanceof f||typeof t==="object"&&t!==null&&t.name==="MrCharlesError"}function H(t,o){let e=o.fetch??(typeof fetch==="function"?fetch.bind(globalThis):void 0);if(!e)throw Error("@mrcharles/sdk: no fetch available — pass { fetch } in the client config");let n=e;async function d(s,l,m,u){let g=t+l;if(u){let h=new URLSearchParams;for(let[K,L]of Object.entries(u))if(L!==void 0&&L!=="")h.set(K,String(L));let T=h.toString();if(T)g+=(g.includes("?")?"&":"?")+T}let r={Accept:"application/json",...o.headers??{}};if(o.locale)r["Accept-Language"]=o.locale;if(m!==void 0)r["Content-Type"]="application/json";let p;try{p=await n(g,{method:s,headers:r,body:m!==void 0?JSON.stringify(m):void 0,cache:"no-store"})}catch(h){throw new f("NETWORK_ERROR",h?.message||"Network error",0)}let i=p.headers?.get?.("x-request-id")??void 0,c=await p.text(),a=null;try{a=c?JSON.parse(c):null}catch{a=null}let y=a&&typeof a==="object"?a:{};if(!p.ok||y.success===!1){let h=y.error?.code??(p.status===429?"RATE_LIMIT_EXCEEDED":p.status===404?"RESOURCE_NOT_FOUND":"INTERNAL_ERROR"),T=y.error?.message??p.statusText??"Request failed";throw new f(h,T,p.status,i)}return"data"in y?y.data:a}return{get:(s,l)=>d("GET",s,void 0,l),post:(s,l)=>d("POST",s,l??{})}}function R(t){let o=(e)=>`https://${e}.${t.sitesBase}`;return{site(e){return`${o(e)}/`},bookRoom(e){let n=new URLSearchParams;if(e.date)n.set("date",e.date);if(e.start)n.set("start",e.start);if(e.durationMinutes)n.set("duration",String(e.durationMinutes));if(e.lang)n.set("lang",e.lang);if(e.embed)n.set("embed","1");let d=n.toString();return`${o(e.slug)}/reservar/${e.roomId}${d?`?${d}`:""}`},manage(e,n){return`${o(e)}/r/${n}`},bookLesson(e){let n=new URLSearchParams({instructorId:e.instructorId});if(e.offerId)n.set("offerId",e.offerId);return`${t.appBase}/bookings/book?${n.toString()}`},teacherProfile(e){return`${t.appBase}/instructors/${e}`}}}function N(t,o){try{let e=new URL(t).host;return e===o||e.endsWith(`.${o}`)}catch{return!1}}function D(t){if(!t||typeof t!=="object")return null;let o=t;if(o.type==="mrcharles:resize"&&typeof o.height==="number")return{type:"mrcharles:resize",height:o.height};if(o.type==="mrcharles:booked"&&typeof o.reference==="string")return{type:"mrcharles:booked",reference:o.reference,bookingId:String(o.bookingId??""),manageUrl:String(o.manageUrl??""),status:String(o.status??"")};return null}function I(t){let o=R(t);function e(n,d){let s=typeof n==="string"?document.querySelector(n):n;if(!s)throw Error(`@mrcharles/sdk: embed target not found: ${String(n)}`);let l=document.createElement("iframe");if(l.src=o.bookRoom({...d,embed:!0}),l.title=d.title??"Mr Charles booking",l.loading="lazy",l.referrerPolicy="strict-origin-when-cross-origin",l.setAttribute("allow","payment"),l.style.width="100%",l.style.border="0",l.style.display="block",l.style.height=`${d.height??760}px`,d.className)l.className=d.className;let m=new URL(l.src).origin,u=(g)=>{if(g.source!==l.contentWindow)return;if(g.origin!==m&&!N(g.origin,t.sitesBase))return;let r=D(g.data);if(!r)return;if(r.type==="mrcharles:resize"){if(d.autoResize!==!1)l.style.height=`${r.height}px`;d.onResize?.(r.height)}else d.onBooked?.(r)};return window.addEventListener("message",u),s.appendChild(l),{iframe:l,destroy(){window.removeEventListener("message",u),l.remove()}}}return{mountRoomBooking:e}}function E(){let t=globalThis.crypto;if(t?.randomUUID)return t.randomUUID();let o=new Uint8Array(16);if(t?.getRandomValues)t.getRandomValues(o);else for(let n=0;n<16;n++)o[n]=Math.floor(Math.random()*256);o[6]=o[6]&15|64,o[8]=o[8]&63|128;let e=[...o].map((n)=>n.toString(16).padStart(2,"0")).join("");return`${e.slice(0,8)}-${e.slice(8,12)}-${e.slice(12,16)}-${e.slice(16,20)}-${e.slice(20)}`}function b(t){let[o,e]=t.split(":").map(Number);return(o||0)*60+(e||0)}function S(t){let o=Math.floor(t/60),e=t%60;return`${String(o).padStart(2,"0")}:${String(e).padStart(2,"0")}`}function U(t,o){return S(b(t)+o)}function C(t,o,e){let n=Math.max(1,e),d=new Set;for(let s of t){let l=b(s.start),m=b(s.end);for(let u=Math.ceil(l/n)*n;u+o<=m;u+=n)d.add(S(u))}return[...d].sort((s,l)=>b(s)-b(l))}function x(t,o,e,n,d){let s=b(o),l=t.find((g)=>b(g.start)<=s&&s<b(g.end));if(!l)return[];let m=b(l.end)-s,u=[];for(let g=e;g<=n&&g<=m;g+=Math.max(1,d))u.push(g);return u}function F(t,o,e="es-ES"){try{return new Intl.NumberFormat(e,{style:"currency",currency:o}).format(t/100)}catch{return`${(t/100).toFixed(2)} ${o}`}}function M(t,o){let e=new Intl.DateTimeFormat("en-CA",{timeZone:o,year:"numeric",month:"2-digit",day:"2-digit"}).formatToParts(t),n=(d)=>e.find((s)=>s.type===d)?.value??"";return`${n("year")}-${n("month")}-${n("day")}`}function v(t,o){let[e,n,d]=t.split("-").map(Number),s=Date.UTC(e,n-1,d+o);return new Date(s).toISOString().slice(0,10)}function w(t,o,e){let n={step:"slot",site:null,room:null,availability:null,hold:null,confirmation:null,error:null,busy:!1},d=new Set;if(e.onChange)d.add(e.onChange);let s=E(),l,m=(i)=>{n={...n,...i};for(let c of d)c(n)},u=()=>{if(l)clearTimeout(l);l=void 0},g=(i)=>{u();let c=new Date(i.expiresAt).getTime()-Date.now();if(c<=0)return;l=setTimeout(()=>{if(n.step==="verify"||n.step==="pay")s=E(),m({step:"expired",error:new f("HOLD_EXPIRED","The hold expired. Pick a time again.",410)})},c)};async function r(i){m({busy:!0});try{let c=await i();return m({busy:!1,error:null}),c}catch(c){let a=k(c)?c:new f("INTERNAL_ERROR",c?.message??"Unexpected error");if(a.holdIsDead)u(),s=E(),m({busy:!1,error:a,step:"expired",hold:null});else m({busy:!1,error:a});throw a}}return{get state(){return n},subscribe(i){return d.add(i),i(n),()=>{d.delete(i)}},loadSite:()=>r(async()=>{let i=await t.get(`/public/sites/${encodeURIComponent(e.slug)}`),c=i.rooms.find((a)=>a.id===e.roomId)??null;if(!c)throw new f("RESOURCE_NOT_FOUND",`Room ${e.roomId} is not on site ${e.slug}`,404);if(!c.bookable)throw new f("ROOM_NOT_BOOKABLE",`${c.name} does not take online bookings right now`,409);return m({site:i,room:c}),i}),loadAvailability:(i={})=>r(async()=>{let c=n.site?.studio.timezone??"UTC",a=i.from??M(new Date,c),y=i.to??v(a,Math.min(31,Math.max(1,i.days??14))-1),h=await t.get(`/public/sites/${encodeURIComponent(e.slug)}/rooms/${encodeURIComponent(e.roomId)}/availability`,{from:a,to:y});return m({availability:h}),h}),startTimesFor(i,c){let a=n.availability;if(!a)return[];let y=a.days.find((h)=>h.date===i);return y?C(y.free,c,a.stepMinutes):[]},durationsFor(i,c){let a=n.availability;if(!a)return[];let y=a.days.find((h)=>h.date===i);return y?x(y.free,c,a.minMinutes,a.maxMinutes,a.stepMinutes):[]},hold:(i)=>r(async()=>{if(n.step==="expired")m({step:"slot",error:null});let c={roomId:e.roomId,date:i.date,startTime:i.startTime,durationMinutes:i.durationMinutes,guestName:i.guestName,channel:i.channel,contact:i.contact,locale:i.locale??n.site?.site.defaultLocale??"es",idempotencyKey:s,...i.captchaToken?{captchaToken:i.captchaToken}:{}},a=await t.post(`/public/sites/${encodeURIComponent(e.slug)}/holds`,c);return g(a),m({hold:a,step:"verify",confirmation:null}),a}),verify:(i)=>r(async()=>{let c=_(n).holdId,a=await t.post(`/public/holds/${c}/verify`,{code:i.replace(/\D/g,"")});return m({hold:a,step:"pay"}),a}),resend:()=>r(async()=>{let i=_(n).holdId,c=await t.post(`/public/holds/${i}/resend`);return m({hold:c}),c}),confirm:(i)=>r(async()=>{let c=_(n);if(!c.paymentModes.includes(i.paymentMode))throw new f("PAYMENT_MODE_DENIED",`This room does not accept ${i.paymentMode}`,409);let a=await t.post(`/public/holds/${c.holdId}/confirm`,{paymentMode:i.paymentMode,notes:i.notes??"",email:i.email??""});if(u(),!a.manageUrl&&a.manageToken)a.manageUrl=o.manage(e.slug,a.manageToken);return m({confirmation:a,step:"done"}),a}),remainingMs(){let i=n.hold;if(!i||n.step==="done"||n.step==="expired")return 0;return Math.max(0,new Date(i.expiresAt).getTime()-Date.now())},reset(){u(),s=E(),m({step:"slot",hold:null,confirmation:null,error:null,busy:!1})},destroy(){u(),d.clear()}}}function _(t){if(!t.hold)throw new f("INVALID_STATE","No hold yet — call hold() first",409);return t.hold}function V(t={}){let o=O(t),e=H(o.apiBase,t),n=R(o),d=I(o),s=encodeURIComponent;return{endpoints:o,sites:{get:(r)=>e.get(`/public/sites/${s(r)}`),resolve:(r)=>e.get("/public/sites/resolve",{host:r}),availability:(r,p,i)=>e.get(`/public/sites/${s(r)}/rooms/${s(p)}/availability`,i)},holds:{create:(r,p)=>e.post(`/public/sites/${s(r)}/holds`,p),verify:(r,p)=>e.post(`/public/holds/${s(r)}/verify`,{code:p}),resend:(r)=>e.post(`/public/holds/${s(r)}/resend`),confirm:(r,p)=>e.post(`/public/holds/${s(r)}/confirm`,{paymentMode:p.paymentMode,notes:p.notes??"",email:p.email??""})},bookings:{get:(r)=>e.get(`/public/bookings/manage/${s(r)}`),cancel:(r,p="")=>e.post(`/public/bookings/manage/${s(r)}/cancel`,{reason:p})},teachers:{profile:(r)=>e.get(`/instructors/${s(r)}/teacher-profile`),offers:(r)=>e.get(`/instructors/${s(r)}/offers`),offer:(r)=>e.get(`/offers/${s(r)}`),windows:(r,p)=>e.get(`/availability/${s(r)}/windows`,p),policy:(r)=>e.get(`/availability/${s(r)}/policy`),slots:(r)=>e.get("/bookings/slots",{instructorId:r.instructorUserId,offerId:r.offerId,date:r.date,days:r.days??7})},links:n,mountRoomBooking:d.mountRoomBooking,roomBooking:(r)=>w(e,n,r)}}var G="0.1.0";window.MrCharles=A;})();
|
|
1
|
+
(()=>{var ne=Object.defineProperty;var ae=(e)=>e;function ie(e,r){this[e]=ae.bind(null,r)}var se=(e,r)=>{for(var t in r)ne(e,t,{get:r[t],enumerable:!0,configurable:!0,set:ie.bind(r,t)})};var X={};se(X,{ENVIRONMENTS:()=>K,HOSTED_LOCALES:()=>q,LOCALES:()=>W,MESSAGES:()=>k,MrCharlesError:()=>T,VERSION:()=>ge,addDays:()=>U,addMinutes:()=>ee,createClient:()=>te,createEmbed:()=>x,createFormatter:()=>F,createLinks:()=>S,createRoomBooking:()=>V,dateKey:()=>H,durationOptions:()=>B,formatPrice:()=>re,intlTag:()=>C,isMrCharlesError:()=>N,isTrustedOrigin:()=>Y,messageFor:()=>_,normalizeLocale:()=>E,parseEmbedEvent:()=>G,pick:()=>M,resolveEndpoints:()=>L,startTimes:()=>P,t:()=>R,toHHMM:()=>w,toHostedLocale:()=>I,toMinutes:()=>y,translator:()=>J,uuid:()=>D});var K={production:{apiBase:"https://api.mrcharles.app/api/v1",appBase:"https://app.mrcharles.app",sitesBase:"sites.mrcharles.app"}};function L(e={}){let r=K[e.env??"production"];return{apiBase:Z(e.apiBase??r.apiBase),appBase:Z(e.appBase??r.appBase),sitesBase:(e.sitesBase??r.sitesBase).replace(/^https?:\/\//,"").replace(/\/+$/,"")}}function Z(e){return e.replace(/\/+$/,"")}class T extends Error{code;status;requestId;constructor(e,r,t=0,a){super(r);this.name="MrCharlesError",this.code=e,this.status=t,this.requestId=a}get holdIsDead(){return this.code==="HOLD_EXPIRED"||this.code==="TOO_MANY_ATTEMPTS"}get slotIsGone(){return this.code==="SLOT_TAKEN"||this.code==="OUTSIDE_HOURS"||this.code==="OUTSIDE_BOOKING_WINDOW"}get isTransient(){return this.code==="NETWORK_ERROR"||this.status>=500}}function N(e){return e instanceof T||typeof e==="object"&&e!==null&&e.name==="MrCharlesError"}function Q(e,r,t=()=>r.locale){let a=r.fetch??(typeof fetch==="function"?fetch.bind(globalThis):void 0);if(!a)throw Error("@mrcharles/sdk: no fetch available — pass { fetch } in the client config");let c=a;async function o(u,i,l,d){let g=e+i;if(d){let b=new URLSearchParams;for(let[oe,z]of Object.entries(d))if(z!==void 0&&z!=="")b.set(oe,String(z));let A=b.toString();if(A)g+=(g.includes("?")?"&":"?")+A}let h={Accept:"application/json",...r.headers??{}},O=t();if(O)h["Accept-Language"]=O;if(l!==void 0)h["Content-Type"]="application/json";let s;try{s=await c(g,{method:u,headers:h,body:l!==void 0?JSON.stringify(l):void 0,cache:"no-store"})}catch(b){throw new T("NETWORK_ERROR",b?.message||"Network error",0)}let n=s.headers?.get?.("x-request-id")??void 0,m=await s.text(),p=null;try{p=m?JSON.parse(m):null}catch{p=null}let f=p&&typeof p==="object"?p:{};if(!s.ok||f.success===!1){let b=f.error?.code??(s.status===429?"RATE_LIMIT_EXCEEDED":s.status===404?"RESOURCE_NOT_FOUND":"INTERNAL_ERROR"),A=f.error?.message??s.statusText??"Request failed";throw new T(b,A,s.status,n)}return"data"in f?f.data:p}return{get:(u,i)=>o("GET",u,void 0,i),post:(u,i)=>o("POST",u,i??{})}}var W=["es","ca","en","fr","pt","it","de"],q=["es","ca","en"];function E(e,r="en"){if(!e)return r;let t=String(e).trim().toLowerCase().split(/[-_]/)[0];return W.includes(t)?t:r}function I(e,r="en"){let t=E(e,r);return q.includes(t)?t:r}function C(e){let r=e?String(e).trim().replace("_","-"):"";if(/^[a-z]{2,3}-[A-Za-z]{2,4}/.test(r))return r;let t=E(r);return{es:"es-ES",ca:"ca-ES",en:"en-GB",fr:"fr-FR",pt:"pt-PT",it:"it-IT",de:"de-DE"}[t]}function M(e,r,t){if(!e)return"";let a=I(r),c=t?I(t):void 0;for(let u of[a,c,"es","ca","en"])if(u&&e[u])return e[u];return Object.values(e).find((u)=>!!u)??""}var v={"step.slot":"Pick a time","step.details":"Your details","step.verify":"Enter the code","step.pay":"Confirm","step.done":"Booked","step.expired":"Time ran out","label.date":"Date","label.time":"Time","label.duration":"Duration","label.name":"Name","label.phone":"Mobile","label.email":"Email","label.contact":"Where to send the code","label.code":"Code","label.notes":"Notes for the studio","label.price":"Price","label.deposit":"Deposit","label.total":"Total","label.perHour":"per hour","action.continue":"Continue","action.back":"Back","action.sendCode":"Send me a code","action.verify":"Verify","action.resend":"Send it again","action.confirm":"Confirm booking","action.payCard":"Pay by card","action.payOnSite":"Pay at the studio","action.startOver":"Start again","action.manage":"See or cancel the booking","action.cancel":"Cancel","hint.codeSent":"We sent a code to {contact}.","hint.resendsLeft":"{n} resends left","hint.holdExpiresIn":"Your slot is held for {time}","hint.payOnSite":"Nothing to pay now; settle at the studio.","hint.payCard":"A deposit of {amount} is charged now.","hint.cancelNotice":"Free cancellation up to {hours} h before.","hint.sandbox":"Test mode: nothing is sent or charged, and this booking will be deleted.","hint.noSlots":"No free times that day.","hint.pickDate":"Choose a day to see free times.","done.title":"Booking confirmed","done.reference":"Reference {ref}","done.manage":"Keep this link to see or cancel the booking.","channel.phone":"SMS","channel.email":"Email","pay.card":"Card","pay.on_site":"At the studio","error.VALIDATION_ERROR":"Please check what you typed.","error.RESOURCE_NOT_FOUND":"That was not found.","error.SITE_NOT_LIVE":"This studio is not taking online bookings yet.","error.ROOM_NOT_BOOKABLE":"This room cannot be booked online right now.","error.STUDIO_NOT_VERIFIED":"This studio is not taking online bookings yet.","error.OUTSIDE_HOURS":"The studio is closed at that time.","error.OUTSIDE_BOOKING_WINDOW":"That date cannot be booked yet — try one closer.","error.SLOT_TAKEN":"That time was just taken. Pick another one.","error.HOLD_EXPIRED":"Time ran out. Pick a time again.","error.HOLD_NOT_VERIFIED":"Enter the code first.","error.HOLD_ALREADY_CONFIRMED":"This booking is already confirmed.","error.CODE_INVALID":"That code is not right.","error.TOO_MANY_ATTEMPTS":"Too many tries. Start again.","error.RATE_LIMIT_EXCEEDED":"Too many requests. Wait a minute and try again.","error.CAPTCHA_FAILED":"Please complete the verification challenge.","error.SMS_UNAVAILABLE":"We cannot send SMS right now — use email.","error.PAYMENTS_UNAVAILABLE":"Card payments are unavailable right now — pay at the studio.","error.PAYMENT_MODE_DENIED":"That payment method is not accepted for this room.","error.CANCEL_TOO_LATE":"It is too late to cancel online — call the studio.","error.INVALID_STATE":"That action is not possible right now.","error.INTERNAL_ERROR":"Something went wrong. Try again.","error.NETWORK_ERROR":"No connection. Check your network and try again.","error.default":"Something went wrong. Try again."},le={"step.slot":"Elige una hora","step.details":"Tus datos","step.verify":"Introduce el código","step.pay":"Confirmar","step.done":"Reservado","step.expired":"Se agotó el tiempo","label.date":"Fecha","label.time":"Hora","label.duration":"Duración","label.name":"Nombre","label.phone":"Móvil","label.email":"Email","label.contact":"Dónde enviamos el código","label.code":"Código","label.notes":"Notas para el estudio","label.price":"Precio","label.deposit":"Señal","label.total":"Total","label.perHour":"por hora","action.continue":"Continuar","action.back":"Atrás","action.sendCode":"Enviarme un código","action.verify":"Verificar","action.resend":"Reenviar","action.confirm":"Confirmar reserva","action.payCard":"Pagar con tarjeta","action.payOnSite":"Pagar en el estudio","action.startOver":"Empezar de nuevo","action.manage":"Ver o cancelar la reserva","action.cancel":"Cancelar","hint.codeSent":"Hemos enviado un código a {contact}.","hint.resendsLeft":"Quedan {n} reenvíos","hint.holdExpiresIn":"Tu hora está reservada durante {time}","hint.payOnSite":"No pagas nada ahora; se paga en el estudio.","hint.payCard":"Se cobra ahora una señal de {amount}.","hint.cancelNotice":"Cancelación gratuita hasta {hours} h antes.","hint.sandbox":"Modo pruebas: no se envía ni se cobra nada, y esta reserva se borrará.","hint.noSlots":"No hay horas libres ese día.","hint.pickDate":"Elige un día para ver las horas libres.","done.title":"Reserva confirmada","done.reference":"Referencia {ref}","done.manage":"Guarda este enlace para ver o cancelar la reserva.","channel.phone":"SMS","channel.email":"Email","pay.card":"Tarjeta","pay.on_site":"En el estudio","error.VALIDATION_ERROR":"Revisa lo que has escrito.","error.RESOURCE_NOT_FOUND":"No lo encontramos.","error.SITE_NOT_LIVE":"Este estudio aún no acepta reservas online.","error.ROOM_NOT_BOOKABLE":"Esta sala no se puede reservar online ahora mismo.","error.STUDIO_NOT_VERIFIED":"Este estudio aún no acepta reservas online.","error.OUTSIDE_HOURS":"El estudio está cerrado a esa hora.","error.OUTSIDE_BOOKING_WINDOW":"Esa fecha aún no se puede reservar: prueba una más cercana.","error.SLOT_TAKEN":"Esa hora acaba de ocuparse. Elige otra.","error.HOLD_EXPIRED":"Se agotó el tiempo. Vuelve a elegir una hora.","error.HOLD_NOT_VERIFIED":"Introduce primero el código.","error.HOLD_ALREADY_CONFIRMED":"Esta reserva ya está confirmada.","error.CODE_INVALID":"El código no es correcto.","error.TOO_MANY_ATTEMPTS":"Demasiados intentos. Empieza de nuevo.","error.RATE_LIMIT_EXCEEDED":"Demasiadas peticiones. Espera un minuto y vuelve a intentarlo.","error.CAPTCHA_FAILED":"Completa la verificación de seguridad.","error.SMS_UNAVAILABLE":"Ahora no podemos enviar SMS: usa el email.","error.PAYMENTS_UNAVAILABLE":"El pago con tarjeta no está disponible: paga en el estudio.","error.PAYMENT_MODE_DENIED":"Esta sala no acepta ese método de pago.","error.CANCEL_TOO_LATE":"Ya es tarde para cancelar online: llama al estudio.","error.INVALID_STATE":"Esa acción no es posible ahora.","error.INTERNAL_ERROR":"Algo ha fallado. Inténtalo de nuevo.","error.NETWORK_ERROR":"Sin conexión. Revisa tu red e inténtalo de nuevo.","error.default":"Algo ha fallado. Inténtalo de nuevo."},ce={"step.slot":"Tria una hora","step.details":"Les teves dades","step.verify":"Introdueix el codi","step.pay":"Confirmar","step.done":"Reservat","step.expired":"S'ha esgotat el temps","label.date":"Data","label.time":"Hora","label.duration":"Durada","label.name":"Nom","label.phone":"Mòbil","label.email":"Correu","label.contact":"On enviem el codi","label.code":"Codi","label.notes":"Notes per a l'estudi","label.price":"Preu","label.deposit":"Paga i senyal","label.total":"Total","label.perHour":"per hora","action.continue":"Continuar","action.back":"Enrere","action.sendCode":"Envia’m un codi","action.verify":"Verificar","action.resend":"Torna a enviar","action.confirm":"Confirmar la reserva","action.payCard":"Pagar amb targeta","action.payOnSite":"Pagar a l'estudi","action.startOver":"Tornar a començar","action.manage":"Veure o cancel·lar la reserva","action.cancel":"Cancel·lar","hint.codeSent":"Hem enviat un codi a {contact}.","hint.resendsLeft":"Queden {n} reenviaments","hint.holdExpiresIn":"La teva hora està reservada durant {time}","hint.payOnSite":"No pagues res ara; es paga a l'estudi.","hint.payCard":"Ara es cobra una paga i senyal de {amount}.","hint.cancelNotice":"Cancel·lació gratuïta fins a {hours} h abans.","hint.sandbox":"Mode de proves: no s'envia ni es cobra res, i aquesta reserva s'esborrarà.","hint.noSlots":"No hi ha hores lliures aquell dia.","hint.pickDate":"Tria un dia per veure les hores lliures.","done.title":"Reserva confirmada","done.reference":"Referència {ref}","done.manage":"Guarda aquest enllaç per veure o cancel·lar la reserva.","channel.phone":"SMS","channel.email":"Correu","pay.card":"Targeta","pay.on_site":"A l'estudi","error.VALIDATION_ERROR":"Revisa el que has escrit.","error.RESOURCE_NOT_FOUND":"No ho hem trobat.","error.SITE_NOT_LIVE":"Aquest estudi encara no accepta reserves en línia.","error.ROOM_NOT_BOOKABLE":"Aquesta sala no es pot reservar en línia ara mateix.","error.STUDIO_NOT_VERIFIED":"Aquest estudi encara no accepta reserves en línia.","error.OUTSIDE_HOURS":"L'estudi està tancat a aquella hora.","error.OUTSIDE_BOOKING_WINDOW":"Aquesta data encara no es pot reservar: prova’n una de més propera.","error.SLOT_TAKEN":"Aquesta hora s'acaba d'ocupar. Tria’n una altra.","error.HOLD_EXPIRED":"S'ha esgotat el temps. Torna a triar una hora.","error.HOLD_NOT_VERIFIED":"Introdueix primer el codi.","error.HOLD_ALREADY_CONFIRMED":"Aquesta reserva ja està confirmada.","error.CODE_INVALID":"El codi no és correcte.","error.TOO_MANY_ATTEMPTS":"Massa intents. Torna a començar.","error.RATE_LIMIT_EXCEEDED":"Massa peticions. Espera un minut i torna-ho a provar.","error.CAPTCHA_FAILED":"Completa la verificació de seguretat.","error.SMS_UNAVAILABLE":"Ara no podem enviar SMS: fes servir el correu.","error.PAYMENTS_UNAVAILABLE":"El pagament amb targeta no està disponible: paga a l'estudi.","error.PAYMENT_MODE_DENIED":"Aquesta sala no accepta aquest mètode de pagament.","error.CANCEL_TOO_LATE":"Ja és tard per cancel·lar en línia: truca a l'estudi.","error.INVALID_STATE":"Aquesta acció no és possible ara.","error.INTERNAL_ERROR":"Alguna cosa ha fallat. Torna-ho a provar.","error.NETWORK_ERROR":"Sense connexió. Revisa la xarxa i torna-ho a provar.","error.default":"Alguna cosa ha fallat. Torna-ho a provar."},de={"step.slot":"Choisissez un horaire","step.details":"Vos coordonnées","step.verify":"Saisissez le code","step.pay":"Confirmer","step.done":"Réservé","step.expired":"Temps écoulé","label.date":"Date","label.time":"Heure","label.duration":"Durée","label.name":"Nom","label.phone":"Mobile","label.email":"E-mail","label.contact":"Où envoyer le code","label.code":"Code","label.notes":"Notes pour le studio","label.price":"Prix","label.deposit":"Acompte","label.total":"Total","label.perHour":"par heure","action.continue":"Continuer","action.back":"Retour","action.sendCode":"Recevoir un code","action.verify":"Vérifier","action.resend":"Renvoyer","action.confirm":"Confirmer la réservation","action.payCard":"Payer par carte","action.payOnSite":"Payer au studio","action.startOver":"Recommencer","action.manage":"Voir ou annuler la réservation","action.cancel":"Annuler","hint.codeSent":"Nous avons envoyé un code à {contact}.","hint.resendsLeft":"{n} renvois restants","hint.holdExpiresIn":"Votre créneau est bloqué pendant {time}","hint.payOnSite":"Rien à payer maintenant ; réglez au studio.","hint.payCard":"Un acompte de {amount} est débité maintenant.","hint.cancelNotice":"Annulation gratuite jusqu'à {hours} h avant.","hint.sandbox":"Mode test : rien n'est envoyé ni débité, et cette réservation sera supprimée.","hint.noSlots":"Aucun horaire libre ce jour-là.","hint.pickDate":"Choisissez un jour pour voir les horaires libres.","done.title":"Réservation confirmée","done.reference":"Référence {ref}","done.manage":"Conservez ce lien pour voir ou annuler la réservation.","channel.phone":"SMS","channel.email":"E-mail","pay.card":"Carte","pay.on_site":"Au studio","error.VALIDATION_ERROR":"Vérifiez ce que vous avez saisi.","error.RESOURCE_NOT_FOUND":"Introuvable.","error.SITE_NOT_LIVE":"Ce studio n'accepte pas encore les réservations en ligne.","error.ROOM_NOT_BOOKABLE":"Cette salle ne peut pas être réservée en ligne pour le moment.","error.STUDIO_NOT_VERIFIED":"Ce studio n'accepte pas encore les réservations en ligne.","error.OUTSIDE_HOURS":"Le studio est fermé à cette heure.","error.OUTSIDE_BOOKING_WINDOW":"Cette date ne peut pas encore être réservée — essayez une date plus proche.","error.SLOT_TAKEN":"Ce créneau vient d'être pris. Choisissez-en un autre.","error.HOLD_EXPIRED":"Temps écoulé. Choisissez à nouveau un horaire.","error.HOLD_NOT_VERIFIED":"Saisissez d'abord le code.","error.HOLD_ALREADY_CONFIRMED":"Cette réservation est déjà confirmée.","error.CODE_INVALID":"Ce code est incorrect.","error.TOO_MANY_ATTEMPTS":"Trop de tentatives. Recommencez.","error.RATE_LIMIT_EXCEEDED":"Trop de requêtes. Patientez une minute et réessayez.","error.CAPTCHA_FAILED":"Veuillez compléter la vérification de sécurité.","error.SMS_UNAVAILABLE":"Impossible d'envoyer des SMS pour le moment — utilisez l'e-mail.","error.PAYMENTS_UNAVAILABLE":"Le paiement par carte est indisponible — payez au studio.","error.PAYMENT_MODE_DENIED":"Ce moyen de paiement n'est pas accepté pour cette salle.","error.CANCEL_TOO_LATE":"Trop tard pour annuler en ligne — appelez le studio.","error.INVALID_STATE":"Cette action n'est pas possible pour le moment.","error.INTERNAL_ERROR":"Une erreur s'est produite. Réessayez.","error.NETWORK_ERROR":"Pas de connexion. Vérifiez votre réseau et réessayez.","error.default":"Une erreur s'est produite. Réessayez."},ue={"step.slot":"Escolha uma hora","step.details":"Os seus dados","step.verify":"Introduza o código","step.pay":"Confirmar","step.done":"Reservado","step.expired":"O tempo esgotou-se","label.date":"Data","label.time":"Hora","label.duration":"Duração","label.name":"Nome","label.phone":"Telemóvel","label.email":"E-mail","label.contact":"Para onde enviamos o código","label.code":"Código","label.notes":"Notas para o estúdio","label.price":"Preço","label.deposit":"Sinal","label.total":"Total","label.perHour":"por hora","action.continue":"Continuar","action.back":"Voltar","action.sendCode":"Enviar-me um código","action.verify":"Verificar","action.resend":"Reenviar","action.confirm":"Confirmar reserva","action.payCard":"Pagar com cartão","action.payOnSite":"Pagar no estúdio","action.startOver":"Recomeçar","action.manage":"Ver ou cancelar a reserva","action.cancel":"Cancelar","hint.codeSent":"Enviámos um código para {contact}.","hint.resendsLeft":"Restam {n} reenvios","hint.holdExpiresIn":"A sua hora está reservada durante {time}","hint.payOnSite":"Não paga nada agora; paga no estúdio.","hint.payCard":"É cobrado agora um sinal de {amount}.","hint.cancelNotice":"Cancelamento gratuito até {hours} h antes.","hint.sandbox":"Modo de testes: nada é enviado nem cobrado, e esta reserva será apagada.","hint.noSlots":"Não há horas livres nesse dia.","hint.pickDate":"Escolha um dia para ver as horas livres.","done.title":"Reserva confirmada","done.reference":"Referência {ref}","done.manage":"Guarde esta ligação para ver ou cancelar a reserva.","channel.phone":"SMS","channel.email":"E-mail","pay.card":"Cartão","pay.on_site":"No estúdio","error.VALIDATION_ERROR":"Verifique o que escreveu.","error.RESOURCE_NOT_FOUND":"Não encontrado.","error.SITE_NOT_LIVE":"Este estúdio ainda não aceita reservas online.","error.ROOM_NOT_BOOKABLE":"Esta sala não pode ser reservada online neste momento.","error.STUDIO_NOT_VERIFIED":"Este estúdio ainda não aceita reservas online.","error.OUTSIDE_HOURS":"O estúdio está fechado a essa hora.","error.OUTSIDE_BOOKING_WINDOW":"Essa data ainda não pode ser reservada — tente uma mais próxima.","error.SLOT_TAKEN":"Essa hora acabou de ser ocupada. Escolha outra.","error.HOLD_EXPIRED":"O tempo esgotou-se. Volte a escolher uma hora.","error.HOLD_NOT_VERIFIED":"Introduza primeiro o código.","error.HOLD_ALREADY_CONFIRMED":"Esta reserva já está confirmada.","error.CODE_INVALID":"Esse código não está correto.","error.TOO_MANY_ATTEMPTS":"Demasiadas tentativas. Recomece.","error.RATE_LIMIT_EXCEEDED":"Demasiados pedidos. Aguarde um minuto e tente novamente.","error.CAPTCHA_FAILED":"Complete a verificação de segurança.","error.SMS_UNAVAILABLE":"Não é possível enviar SMS agora — use o e-mail.","error.PAYMENTS_UNAVAILABLE":"O pagamento com cartão está indisponível — pague no estúdio.","error.PAYMENT_MODE_DENIED":"Esse método de pagamento não é aceite nesta sala.","error.CANCEL_TOO_LATE":"É tarde para cancelar online — ligue ao estúdio.","error.INVALID_STATE":"Essa ação não é possível agora.","error.INTERNAL_ERROR":"Algo correu mal. Tente novamente.","error.NETWORK_ERROR":"Sem ligação. Verifique a rede e tente novamente.","error.default":"Algo correu mal. Tente novamente."},pe={"step.slot":"Scegli un orario","step.details":"I tuoi dati","step.verify":"Inserisci il codice","step.pay":"Conferma","step.done":"Prenotato","step.expired":"Tempo scaduto","label.date":"Data","label.time":"Ora","label.duration":"Durata","label.name":"Nome","label.phone":"Cellulare","label.email":"E-mail","label.contact":"Dove inviare il codice","label.code":"Codice","label.notes":"Note per lo studio","label.price":"Prezzo","label.deposit":"Caparra","label.total":"Totale","label.perHour":"all'ora","action.continue":"Continua","action.back":"Indietro","action.sendCode":"Inviami un codice","action.verify":"Verifica","action.resend":"Invia di nuovo","action.confirm":"Conferma la prenotazione","action.payCard":"Paga con carta","action.payOnSite":"Paga in studio","action.startOver":"Ricomincia","action.manage":"Vedi o annulla la prenotazione","action.cancel":"Annulla","hint.codeSent":"Abbiamo inviato un codice a {contact}.","hint.resendsLeft":"{n} invii rimasti","hint.holdExpiresIn":"Il tuo orario è bloccato per {time}","hint.payOnSite":"Niente da pagare ora; si paga in studio.","hint.payCard":"Viene addebitata ora una caparra di {amount}.","hint.cancelNotice":"Cancellazione gratuita fino a {hours} h prima.","hint.sandbox":"Modalità test: non viene inviato né addebitato nulla, e questa prenotazione sarà eliminata.","hint.noSlots":"Nessun orario libero quel giorno.","hint.pickDate":"Scegli un giorno per vedere gli orari liberi.","done.title":"Prenotazione confermata","done.reference":"Riferimento {ref}","done.manage":"Conserva questo link per vedere o annullare la prenotazione.","channel.phone":"SMS","channel.email":"E-mail","pay.card":"Carta","pay.on_site":"In studio","error.VALIDATION_ERROR":"Controlla quello che hai scritto.","error.RESOURCE_NOT_FOUND":"Non trovato.","error.SITE_NOT_LIVE":"Questo studio non accetta ancora prenotazioni online.","error.ROOM_NOT_BOOKABLE":"Questa sala non è prenotabile online al momento.","error.STUDIO_NOT_VERIFIED":"Questo studio non accetta ancora prenotazioni online.","error.OUTSIDE_HOURS":"Lo studio è chiuso a quell’ora.","error.OUTSIDE_BOOKING_WINDOW":"Quella data non è ancora prenotabile — provane una più vicina.","error.SLOT_TAKEN":"Quell’orario è appena stato preso. Scegline un altro.","error.HOLD_EXPIRED":"Tempo scaduto. Scegli di nuovo un orario.","error.HOLD_NOT_VERIFIED":"Inserisci prima il codice.","error.HOLD_ALREADY_CONFIRMED":"Questa prenotazione è già confermata.","error.CODE_INVALID":"Il codice non è corretto.","error.TOO_MANY_ATTEMPTS":"Troppi tentativi. Ricomincia.","error.RATE_LIMIT_EXCEEDED":"Troppe richieste. Aspetta un minuto e riprova.","error.CAPTCHA_FAILED":"Completa la verifica di sicurezza.","error.SMS_UNAVAILABLE":"Non possiamo inviare SMS al momento — usa l’e-mail.","error.PAYMENTS_UNAVAILABLE":"Il pagamento con carta non è disponibile — paga in studio.","error.PAYMENT_MODE_DENIED":"Questo metodo di pagamento non è accettato per questa sala.","error.CANCEL_TOO_LATE":"È troppo tardi per annullare online — chiama lo studio.","error.INVALID_STATE":"Questa azione non è possibile adesso.","error.INTERNAL_ERROR":"Qualcosa è andato storto. Riprova.","error.NETWORK_ERROR":"Nessuna connessione. Controlla la rete e riprova.","error.default":"Qualcosa è andato storto. Riprova."},me={"step.slot":"Zeit wählen","step.details":"Deine Angaben","step.verify":"Code eingeben","step.pay":"Bestätigen","step.done":"Gebucht","step.expired":"Zeit abgelaufen","label.date":"Datum","label.time":"Uhrzeit","label.duration":"Dauer","label.name":"Name","label.phone":"Handy","label.email":"E-Mail","label.contact":"Wohin wir den Code schicken","label.code":"Code","label.notes":"Hinweise für das Studio","label.price":"Preis","label.deposit":"Anzahlung","label.total":"Gesamt","label.perHour":"pro Stunde","action.continue":"Weiter","action.back":"Zurück","action.sendCode":"Code schicken","action.verify":"Prüfen","action.resend":"Erneut senden","action.confirm":"Buchung bestätigen","action.payCard":"Mit Karte zahlen","action.payOnSite":"Im Studio zahlen","action.startOver":"Von vorn beginnen","action.manage":"Buchung ansehen oder stornieren","action.cancel":"Abbrechen","hint.codeSent":"Wir haben einen Code an {contact} geschickt.","hint.resendsLeft":"Noch {n} Versuche","hint.holdExpiresIn":"Dein Termin ist {time} lang reserviert","hint.payOnSite":"Jetzt nichts zu zahlen; du zahlst im Studio.","hint.payCard":"Eine Anzahlung von {amount} wird jetzt abgebucht.","hint.cancelNotice":"Kostenlose Stornierung bis {hours} h vorher.","hint.sandbox":"Testmodus: nichts wird gesendet oder abgebucht, und diese Buchung wird gelöscht.","hint.noSlots":"An diesem Tag ist nichts frei.","hint.pickDate":"Wähle einen Tag, um freie Zeiten zu sehen.","done.title":"Buchung bestätigt","done.reference":"Referenz {ref}","done.manage":"Bewahre diesen Link auf, um die Buchung anzusehen oder zu stornieren.","channel.phone":"SMS","channel.email":"E-Mail","pay.card":"Karte","pay.on_site":"Im Studio","error.VALIDATION_ERROR":"Bitte prüfe deine Eingaben.","error.RESOURCE_NOT_FOUND":"Nicht gefunden.","error.SITE_NOT_LIVE":"Dieses Studio nimmt noch keine Online-Buchungen an.","error.ROOM_NOT_BOOKABLE":"Dieser Raum kann gerade nicht online gebucht werden.","error.STUDIO_NOT_VERIFIED":"Dieses Studio nimmt noch keine Online-Buchungen an.","error.OUTSIDE_HOURS":"Das Studio ist zu dieser Zeit geschlossen.","error.OUTSIDE_BOOKING_WINDOW":"Dieses Datum kann noch nicht gebucht werden — versuche ein näheres.","error.SLOT_TAKEN":"Diese Zeit wurde gerade vergeben. Wähle eine andere.","error.HOLD_EXPIRED":"Zeit abgelaufen. Wähle die Zeit erneut.","error.HOLD_NOT_VERIFIED":"Gib zuerst den Code ein.","error.HOLD_ALREADY_CONFIRMED":"Diese Buchung ist bereits bestätigt.","error.CODE_INVALID":"Der Code ist falsch.","error.TOO_MANY_ATTEMPTS":"Zu viele Versuche. Beginne von vorn.","error.RATE_LIMIT_EXCEEDED":"Zu viele Anfragen. Warte eine Minute und versuche es erneut.","error.CAPTCHA_FAILED":"Bitte schließe die Sicherheitsprüfung ab.","error.SMS_UNAVAILABLE":"SMS sind gerade nicht möglich — nutze E-Mail.","error.PAYMENTS_UNAVAILABLE":"Kartenzahlung ist gerade nicht verfügbar — zahle im Studio.","error.PAYMENT_MODE_DENIED":"Diese Zahlungsart wird für diesen Raum nicht akzeptiert.","error.CANCEL_TOO_LATE":"Für eine Online-Stornierung ist es zu spät — ruf das Studio an.","error.INVALID_STATE":"Diese Aktion ist gerade nicht möglich.","error.INTERNAL_ERROR":"Etwas ist schiefgelaufen. Versuche es erneut.","error.NETWORK_ERROR":"Keine Verbindung. Prüfe dein Netzwerk und versuche es erneut.","error.default":"Etwas ist schiefgelaufen. Versuche es erneut."},k={en:v,es:le,ca:ce,fr:de,pt:ue,it:pe,de:me};function R(e,r,t){let c=k[E(e)][r]??v[r]??r;if(t)for(let[o,u]of Object.entries(t))c=c.split(`{${o}}`).join(String(u));return c}function _(e,r){let t=e??{},a=k[E(r)];if(t.code&&a[`error.${t.code}`])return a[`error.${t.code}`];if(t.code&&v[`error.${t.code}`])return v[`error.${t.code}`];return a["error.default"]}function J(e){let r=E(e),t=(a,c)=>R(r,a,c);return t.locale=r,t.error=(a)=>_(a,r),t}function S(e,r=()=>{return}){let t=(a)=>`https://${a}.${e.sitesBase}`;return{site(a){return`${t(a)}/`},bookRoom(a){let c=new URLSearchParams;if(a.date)c.set("date",a.date);if(a.start)c.set("start",a.start);if(a.durationMinutes)c.set("duration",String(a.durationMinutes));let o=a.lang??r();if(o)c.set("lang",I(o));if(a.embed)c.set("embed","1");let u=c.toString();return`${t(a.slug)}/reservar/${a.roomId}${u?`?${u}`:""}`},manage(a,c){return`${t(a)}/r/${c}`},bookLesson(a){let c=new URLSearchParams({instructorId:a.instructorId});if(a.offerId)c.set("offerId",a.offerId);return`${e.appBase}/bookings/book?${c.toString()}`},teacherProfile(a){return`${e.appBase}/instructors/${a}`}}}function Y(e,r){try{let t=new URL(e).host;return t===r||t.endsWith(`.${r}`)}catch{return!1}}function G(e){if(!e||typeof e!=="object")return null;let r=e;if(r.type==="mrcharles:resize"&&typeof r.height==="number")return{type:"mrcharles:resize",height:r.height};if(r.type==="mrcharles:booked"&&typeof r.reference==="string")return{type:"mrcharles:booked",reference:r.reference,bookingId:String(r.bookingId??""),manageUrl:String(r.manageUrl??""),status:String(r.status??"")};return null}function x(e,r=()=>{return}){let t=S(e,r);function a(c,o){let u=typeof c==="string"?document.querySelector(c):c;if(!u)throw Error(`@mrcharles/sdk: embed target not found: ${String(c)}`);let i=document.createElement("iframe");if(i.src=t.bookRoom({...o,embed:!0}),i.title=o.title??"Mr Charles booking",i.loading="lazy",i.referrerPolicy="strict-origin-when-cross-origin",i.setAttribute("allow","payment"),i.style.width="100%",i.style.border="0",i.style.display="block",i.style.height=`${o.height??760}px`,o.className)i.className=o.className;let l=new URL(i.src).origin,d=(g)=>{if(g.source!==i.contentWindow)return;if(g.origin!==l&&!Y(g.origin,e.sitesBase))return;let h=G(g.data);if(!h)return;if(h.type==="mrcharles:resize"){if(o.autoResize!==!1)i.style.height=`${h.height}px`;o.onResize?.(h.height)}else o.onBooked?.(h)};return window.addEventListener("message",d),u.appendChild(i),{iframe:i,setLang(g){i.src=t.bookRoom({...o,lang:g,embed:!0})},destroy(){window.removeEventListener("message",d),i.remove()}}}return{mountRoomBooking:a}}function D(){let e=globalThis.crypto;if(e?.randomUUID)return e.randomUUID();let r=new Uint8Array(16);if(e?.getRandomValues)e.getRandomValues(r);else for(let a=0;a<16;a++)r[a]=Math.floor(Math.random()*256);r[6]=r[6]&15|64,r[8]=r[8]&63|128;let t=[...r].map((a)=>a.toString(16).padStart(2,"0")).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}function y(e){let[r,t]=e.split(":").map(Number);return(r||0)*60+(t||0)}function w(e){let r=Math.floor(e/60),t=e%60;return`${String(r).padStart(2,"0")}:${String(t).padStart(2,"0")}`}function ee(e,r){return w(y(e)+r)}function P(e,r,t){let a=Math.max(1,t),c=new Set;for(let o of e){let u=y(o.start),i=y(o.end);for(let l=Math.ceil(u/a)*a;l+r<=i;l+=a)c.add(w(l))}return[...c].sort((o,u)=>y(o)-y(u))}function B(e,r,t,a,c){let o=y(r),u=e.find((d)=>y(d.start)<=o&&o<y(d.end));if(!u)return[];let i=y(u.end)-o,l=[];for(let d=t;d<=a&&d<=i;d+=Math.max(1,c))l.push(d);return l}function re(e,r,t="es-ES"){try{return new Intl.NumberFormat(t,{style:"currency",currency:r}).format(e/100)}catch{return`${(e/100).toFixed(2)} ${r}`}}function H(e,r){let t=new Intl.DateTimeFormat("en-CA",{timeZone:r,year:"numeric",month:"2-digit",day:"2-digit"}).formatToParts(e),a=(c)=>t.find((o)=>o.type===c)?.value??"";return`${a("year")}-${a("month")}-${a("day")}`}function U(e,r){let[t,a,c]=e.split("-").map(Number),o=Date.UTC(t,a-1,c+r);return new Date(o).toISOString().slice(0,10)}function V(e,r,t,a){let c=t.locale??a?.(),o={step:"slot",site:null,room:null,availability:null,hold:null,confirmation:null,error:null,errorMessage:null,busy:!1,locale:E(c,"es")},u=new Set;if(t.onChange)u.add(t.onChange);let i=D(),l,d=(n)=>{if(o={...o,...n},"error"in n||"locale"in n)o.errorMessage=o.error?_(o.error,o.locale):null;for(let m of u)m(o)},g=()=>{if(l)clearTimeout(l);l=void 0},h=(n)=>{g();let m=new Date(n.expiresAt).getTime()-Date.now();if(m<=0)return;l=setTimeout(()=>{if(o.step==="verify"||o.step==="pay")i=D(),d({step:"expired",error:new T("HOLD_EXPIRED",R(o.locale,"error.HOLD_EXPIRED"),410)})},m)};async function O(n){d({busy:!0});try{let m=await n();return d({busy:!1,error:null}),m}catch(m){let p=N(m)?m:new T("INTERNAL_ERROR",m?.message??"Unexpected error");if(p.holdIsDead)g(),i=D(),d({busy:!1,error:p,step:"expired",hold:null});else d({busy:!1,error:p});throw p}}return{get state(){return o},subscribe(n){return u.add(n),n(o),()=>{u.delete(n)}},loadSite:()=>O(async()=>{let n=await e.get(`/public/sites/${encodeURIComponent(t.slug)}`),m=n.rooms.find((f)=>f.id===t.roomId)??null;if(!m)throw new T("RESOURCE_NOT_FOUND",`Room ${t.roomId} is not on site ${t.slug}`,404);if(!m.bookable)throw new T("ROOM_NOT_BOOKABLE",`${m.name} does not take online bookings right now`,409);let p=c?o.locale:E(n.site?.defaultLocale,o.locale);return d({site:n,room:m,locale:p}),n}),loadAvailability:(n={})=>O(async()=>{let m=o.site?.studio.timezone??"UTC",p=n.from??H(new Date,m),f=n.to??U(p,Math.min(31,Math.max(1,n.days??14))-1),b=await e.get(`/public/sites/${encodeURIComponent(t.slug)}/rooms/${encodeURIComponent(t.roomId)}/availability`,{from:p,to:f});return d({availability:b}),b}),startTimesFor(n,m){let p=o.availability;if(!p)return[];let f=p.days.find((b)=>b.date===n);return f?P(f.free,m,p.stepMinutes):[]},durationsFor(n,m){let p=o.availability;if(!p)return[];let f=p.days.find((b)=>b.date===n);return f?B(f.free,m,p.minMinutes,p.maxMinutes,p.stepMinutes):[]},hold:(n)=>O(async()=>{if(o.step==="expired")d({step:"slot",error:null});let m={roomId:t.roomId,date:n.date,startTime:n.startTime,durationMinutes:n.durationMinutes,guestName:n.guestName,channel:n.channel,contact:n.contact,locale:I(n.locale??o.locale),idempotencyKey:i,...n.captchaToken?{captchaToken:n.captchaToken}:{}},p=await e.post(`/public/sites/${encodeURIComponent(t.slug)}/holds`,m);return h(p),d({hold:p,step:"verify",confirmation:null}),p}),verify:(n)=>O(async()=>{let m=j(o).holdId,p=await e.post(`/public/holds/${m}/verify`,{code:n.replace(/\D/g,"")});return d({hold:p,step:"pay"}),p}),resend:()=>O(async()=>{let n=j(o).holdId,m=await e.post(`/public/holds/${n}/resend`);return d({hold:m}),m}),confirm:(n)=>O(async()=>{let m=j(o);if(!m.paymentModes.includes(n.paymentMode))throw new T("PAYMENT_MODE_DENIED",`This room does not accept ${n.paymentMode}`,409);let p=await e.post(`/public/holds/${m.holdId}/confirm`,{paymentMode:n.paymentMode,notes:n.notes??"",email:n.email??""});if(g(),!p.manageUrl&&p.manageToken)p.manageUrl=r.manage(t.slug,p.manageToken);return d({confirmation:p,step:"done"}),p}),remainingMs(){let n=o.hold;if(!n||o.step==="done"||o.step==="expired")return 0;return Math.max(0,new Date(n.expiresAt).getTime()-Date.now())},reset(){g(),i=D(),d({step:"slot",hold:null,confirmation:null,error:null,busy:!1})},t:(n,m)=>R(o.locale,n,m),setLocale(n){d({locale:E(n,o.locale)})},destroy(){g(),u.clear()}}}function j(e){if(!e.hold)throw new T("INVALID_STATE","No hold yet — call hold() first",409);return e.hold}function F(e){let r=C(e),t=E(e),a={es:["h","min"],ca:["h","min"],en:["h","min"],fr:["h","min"],pt:["h","min"],it:["h","min"],de:["Std.","Min."]},[c,o]=a[t]??["h","min"],u=(i,l)=>{try{return i()}catch{return l}};return{locale:r,price:(i,l)=>u(()=>new Intl.NumberFormat(r,{style:"currency",currency:l}).format(i/100),`${(i/100).toFixed(2)} ${l}`),date:(i,l="long")=>{let[d,g,h]=i.split("-").map(Number),O=new Date(Date.UTC(d,g-1,h,12)),s=l==="long"?{weekday:"long",day:"numeric",month:"long",timeZone:"UTC"}:l==="medium"?{weekday:"short",day:"numeric",month:"short",timeZone:"UTC"}:{day:"2-digit",month:"2-digit",timeZone:"UTC"};return u(()=>new Intl.DateTimeFormat(r,s).format(O),i)},time:(i)=>{let[l,d]=i.split(":").map(Number),g=new Date(Date.UTC(2000,0,1,l,d));return u(()=>new Intl.DateTimeFormat(r,{hour:"numeric",minute:"2-digit",timeZone:"UTC"}).format(g),i)},timeRange(i,l){let[d,g]=i.split(":").map(Number),h=d*60+g+l,O=`${String(Math.floor(h/60)%24).padStart(2,"0")}:${String(h%60).padStart(2,"0")}`;return`${this.time(i)} – ${this.time(O)}`},duration:(i)=>{let l=Math.floor(i/60),d=i%60;if(l&&d)return`${l} ${c} ${d} ${o}`;if(l)return`${l} ${c}`;return`${d} ${o}`},weekday:(i,l="short")=>{let d=new Date(Date.UTC(2023,0,1+(i%7+7)%7,12));return u(()=>new Intl.DateTimeFormat(r,{weekday:l,timeZone:"UTC"}).format(d),String(i))},countdown:(i)=>{let l=Math.max(0,Math.floor(i/1000));return`${Math.floor(l/60)}:${String(l%60).padStart(2,"0")}`}}}function te(e={}){let r=L(e),t=e.locale?E(e.locale):void 0,a,c=()=>t,o=Q(r.apiBase,e,c),u=S(r,c),i=x(r,c),l=encodeURIComponent;return{endpoints:r,sites:{get:(s)=>o.get(`/public/sites/${l(s)}`),resolve:(s)=>o.get("/public/sites/resolve",{host:s}),availability:(s,n,m)=>o.get(`/public/sites/${l(s)}/rooms/${l(n)}/availability`,m)},holds:{create:(s,n)=>o.post(`/public/sites/${l(s)}/holds`,n),verify:(s,n)=>o.post(`/public/holds/${l(s)}/verify`,{code:n}),resend:(s)=>o.post(`/public/holds/${l(s)}/resend`),confirm:(s,n)=>o.post(`/public/holds/${l(s)}/confirm`,{paymentMode:n.paymentMode,notes:n.notes??"",email:n.email??""})},bookings:{get:(s)=>o.get(`/public/bookings/manage/${l(s)}`),cancel:(s,n="")=>o.post(`/public/bookings/manage/${l(s)}/cancel`,{reason:n})},teachers:{profile:(s)=>o.get(`/instructors/${l(s)}/teacher-profile`),offers:(s)=>o.get(`/instructors/${l(s)}/offers`),offer:(s)=>o.get(`/offers/${l(s)}`),windows:(s,n)=>o.get(`/availability/${l(s)}/windows`,n),policy:(s)=>o.get(`/availability/${l(s)}/policy`),slots:(s)=>o.get("/bookings/slots",{instructorId:s.instructorUserId,offerId:s.offerId,date:s.date,days:s.days??7})},links:u,mountRoomBooking:i.mountRoomBooking,roomBooking:(s)=>V(o,u,s,c),get locale(){return t},get hostedLocale(){return t?I(t):"es"},setLocale(s){t=s?E(s):void 0,a=void 0},t:(s,n)=>R(t??"en",s,n),errorMessage:(s)=>_(s,t??"en"),get format(){return a??=F(t??"en")},pick:(s,n)=>M(s,t??n??"es",n)}}var ge="0.2.0";window.MrCharles=X;})();
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=AFEC5D89B9E42FFC64756E2164756E21
|
|
4
4
|
//# sourceMappingURL=mrcharles.min.js.map
|