@bookr-cl/widget 0.1.1 → 0.3.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/dist/index.cjs CHANGED
@@ -25,6 +25,7 @@ __export(index_exports, {
25
25
  DEFAULT_PROVIDER_COLORS: () => DEFAULT_PROVIDER_COLORS,
26
26
  cancelMyBooking: () => cancelMyBooking,
27
27
  clearClientToken: () => clearClientToken,
28
+ confirmWaitlistOffer: () => confirmWaitlistOffer,
28
29
  createBooking: () => createBooking,
29
30
  createClient: () => createClient,
30
31
  dateStr: () => dateStr,
@@ -219,6 +220,7 @@ async function joinWaitlist(apiBase, token, params) {
219
220
  location_id: params.locationId,
220
221
  provider_id: params.providerId,
221
222
  date: params.date,
223
+ date_until: params.dateUntil,
222
224
  class_session_id: params.classSessionId
223
225
  })
224
226
  });
@@ -237,6 +239,15 @@ async function leaveWaitlist(apiBase, token, entryId) {
237
239
  headers: authHeaders(token)
238
240
  });
239
241
  }
242
+ async function confirmWaitlistOffer(cfg, token) {
243
+ const res = await fetch(`${cfg.apiBase}/v1/waitlist/confirm/${token}`, {
244
+ method: "POST",
245
+ headers: headers(cfg)
246
+ });
247
+ const data = await res.json();
248
+ if (!res.ok) throw new Error(data.detail || "No se pudo confirmar el cupo.");
249
+ return data;
250
+ }
240
251
 
241
252
  // src/clientAuth.ts
242
253
  var TOKEN_KEY = "client_token";
@@ -806,6 +817,7 @@ function useClientAccount(opts) {
806
817
  DEFAULT_PROVIDER_COLORS,
807
818
  cancelMyBooking,
808
819
  clearClientToken,
820
+ confirmWaitlistOffer,
809
821
  createBooking,
810
822
  createClient,
811
823
  dateStr,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/api.ts","../src/clientAuth.ts","../src/dateUtils.ts","../src/hooks/useBookingFlow.ts","../src/hooks/useClassSchedule.ts","../src/hooks/useMagicLinkAuth.ts","../src/hooks/useRegisterForm.ts","../src/hooks/useClientAccount.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./api\";\nexport * from \"./clientAuth\";\nexport * from \"./dateUtils\";\nexport * from \"./hooks/useBookingFlow\";\nexport * from \"./hooks/useClassSchedule\";\nexport * from \"./hooks/useMagicLinkAuth\";\nexport * from \"./hooks/useRegisterForm\";\nexport * from \"./hooks/useClientAccount\";\n","import type {\n ApiConfig,\n BookingCreateInput,\n BookingRecord,\n BookingResult,\n ClientFormValues,\n ClientProfile,\n Location,\n PackageRecord,\n Provider,\n Service,\n Slot,\n WaitlistEntry,\n} from \"./types\";\n\nfunction headers(cfg: ApiConfig, withJson = false): Record<string, string> {\n const h: Record<string, string> = { \"X-API-Key\": cfg.apiKey };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nfunction authHeaders(token: string, withJson = false): Record<string, string> {\n const h: Record<string, string> = { Authorization: `Bearer ${token}` };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nexport async function listLocations(cfg: ApiConfig): Promise<Location[]> {\n const res = await fetch(`${cfg.apiBase}/v1/locations`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listServices(cfg: ApiConfig, perPage = 100): Promise<Service[]> {\n const res = await fetch(`${cfg.apiBase}/v1/services?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listProviders(cfg: ApiConfig, perPage = 100): Promise<Provider[]> {\n const res = await fetch(`${cfg.apiBase}/v1/providers?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getAvailableSlots(\n cfg: ApiConfig,\n params: { locationId: string; startDate: string; serviceId?: string; providerId?: string }\n): Promise<Slot[]> {\n const q = new URLSearchParams({ location_id: params.locationId, start_date: params.startDate });\n if (params.serviceId) q.set(\"service_id\", params.serviceId);\n if (params.providerId) q.set(\"provider_id\", params.providerId);\n const res = await fetch(`${cfg.apiBase}/v1/available-slots?${q.toString()}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data?.slots || [];\n}\n\nexport async function createClient(cfg: ApiConfig, form: ClientFormValues): Promise<{ id: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/clients`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone,\n rut: form.rut || undefined,\n }),\n });\n if (!res.ok) throw new Error(\"Error registrando datos\");\n return res.json();\n}\n\nexport async function createBooking(\n cfg: ApiConfig,\n input: BookingCreateInput,\n clientToken?: string\n): Promise<BookingResult> {\n // A logged-in client's token takes priority so the server attributes the\n // booking to their account rather than treating it as anonymous — see\n // create_booking in routes/bookings.py, which ignores any client_id sent\n // by an unauthenticated caller.\n const reqHeaders = headers(cfg, true);\n if (clientToken) reqHeaders.Authorization = `Bearer ${clientToken}`;\n const res = await fetch(`${cfg.apiBase}/v1/bookings`, {\n method: \"POST\",\n headers: reqHeaders,\n body: JSON.stringify(input),\n });\n if (res.status === 409) {\n const data = await res.json().catch(() => ({}));\n return { ok: false, conflict: true, message: data.detail || \"Ese horario ya no está disponible.\" };\n }\n if (!res.ok) {\n return { ok: false, conflict: false, message: \"Error creando la reserva. Por favor intenta nuevamente.\" };\n }\n return { ok: true, booking: await res.json() };\n}\n\nexport async function sendMagicLink(\n cfg: ApiConfig,\n email: string,\n frontendUrl: string,\n profile?: { firstName?: string; lastName?: string; phone?: string; rut?: string }\n): Promise<void> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n email: email.trim().toLowerCase(),\n frontend_url: frontendUrl,\n first_name: profile?.firstName,\n last_name: profile?.lastName,\n phone: profile?.phone,\n rut: profile?.rut,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error enviando el link.\");\n}\n\nexport async function verifyMagicLink(cfg: ApiConfig, token: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link/verify`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ token }),\n });\n const data = await res.json();\n if (!data.access_token) throw new Error(data.detail || \"Link inválido.\");\n return data;\n}\n\nexport async function loginWithGoogle(cfg: ApiConfig, credential: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/google`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ credential }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error con Google.\");\n return data;\n}\n\nexport async function register(\n cfg: ApiConfig,\n form: { firstName: string; lastName: string; email: string; phone?: string; password: string }\n): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/register`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone || undefined,\n password: form.password,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error al registrarse.\");\n return data;\n}\n\nexport async function getMe(apiBase: string, token: string): Promise<ClientProfile> {\n const res = await fetch(`${apiBase}/v1/me`, { headers: authHeaders(token) });\n return res.json();\n}\n\nexport async function getMyBookings(\n apiBase: string,\n token: string,\n params?: { upcoming?: boolean; perPage?: number }\n): Promise<BookingRecord[]> {\n const q = new URLSearchParams();\n if (params?.upcoming) q.set(\"upcoming\", \"true\");\n q.set(\"per_page\", String(params?.perPage ?? 20));\n const res = await fetch(`${apiBase}/v1/me/bookings?${q.toString()}`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getMyPackages(apiBase: string, token: string): Promise<PackageRecord[]> {\n const res = await fetch(`${apiBase}/v1/me/packages`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\n/** Result of a client cancelling/rescheduling their own booking — callers\n * branch on `.ok` to show the server's specific reason (cutoff window,\n * overlap, etc.) instead of a generic error. */\nexport type MyBookingActionResult =\n | { ok: true; booking: BookingRecord }\n | { ok: false; message: string };\n\nexport async function cancelMyBooking(\n apiBase: string, token: string, bookingId: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/cancel`, {\n method: \"POST\",\n headers: authHeaders(token),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo cancelar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function rescheduleMyBooking(\n apiBase: string, token: string, bookingId: string, startTime: string, endTime: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/reschedule`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({ start_time: startTime, end_time: endTime }),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo reprogramar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function joinWaitlist(\n apiBase: string,\n token: string,\n params: { serviceId: string; locationId: string; providerId?: string; date?: string; classSessionId?: string }\n): Promise<WaitlistEntry> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({\n service_id: params.serviceId,\n location_id: params.locationId,\n provider_id: params.providerId,\n date: params.date,\n class_session_id: params.classSessionId,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"No se pudo unir a la lista de espera.\");\n return data;\n}\n\nexport async function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void> {\n await fetch(`${apiBase}/v1/me/waitlist/${entryId}`, {\n method: \"DELETE\",\n headers: authHeaders(token),\n });\n}\n","import { getMe } from \"./api\";\nimport type { ClientProfile } from \"./types\";\n\nconst TOKEN_KEY = \"client_token\";\n\nexport function getClientToken(): string | null {\n if (typeof window === \"undefined\") return null;\n return localStorage.getItem(TOKEN_KEY);\n}\n\nexport function setClientToken(token: string): void {\n if (typeof window === \"undefined\") return;\n localStorage.setItem(TOKEN_KEY, token);\n}\n\nexport function clearClientToken(): void {\n if (typeof window === \"undefined\") return;\n localStorage.removeItem(TOKEN_KEY);\n}\n\nexport async function fetchMe(apiBase: string, token: string): Promise<ClientProfile | null> {\n try {\n return await getMe(apiBase, token);\n } catch {\n return null;\n }\n}\n","export function getMondayOf(date: Date): Date {\n const d = new Date(date);\n const day = (d.getDay() + 6) % 7;\n d.setDate(d.getDate() - day);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\nexport function dateStr(d: Date): string {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`;\n}\n\nexport function formatMonthRange(monday: Date): string {\n const sunday = new Date(monday);\n sunday.setDate(monday.getDate() + 6);\n const opts: Intl.DateTimeFormatOptions = { day: \"numeric\", month: \"long\" };\n const start = monday.toLocaleDateString(\"es-CL\", opts);\n const end = sunday.toLocaleDateString(\"es-CL\", opts);\n return `${start} – ${end}`;\n}\n\nexport const DAY_NAMES = [\"Lun\", \"Mar\", \"Mié\", \"Jue\", \"Vie\", \"Sáb\", \"Dom\"];\nexport const DAY_NAMES_FULL = [\"Lunes\", \"Martes\", \"Miércoles\", \"Jueves\", \"Viernes\", \"Sábado\", \"Domingo\"];\n\nexport interface ProviderColor {\n bg: string;\n border: string;\n text: string;\n}\n\nexport const DEFAULT_PROVIDER_COLORS: ProviderColor[] = [\n { bg: \"#e8f5f0\", border: \"#2bbf8e\", text: \"#1a7a5a\" },\n { bg: \"#eef0fb\", border: \"#6b7de8\", text: \"#3d4fa8\" },\n { bg: \"#fdf3e8\", border: \"#e8a24b\", text: \"#a0600a\" },\n { bg: \"#fdeef4\", border: \"#e86b9a\", text: \"#a03060\" },\n];\n","import { useEffect, useState } from \"react\";\nimport {\n createBooking,\n getAvailableSlots,\n listLocations,\n listProviders,\n listServices,\n} from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport type {\n ApiConfig,\n BookingRecord,\n ClientFormValues,\n ClientProfile,\n Location,\n Provider,\n Service,\n Slot,\n} from \"../types\";\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClientForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n if (!form.rut.trim()) return \"Por favor ingresa tu RUT.\";\n return null;\n}\n\ninterface BuildBookingPayloadArgs {\n form: ClientFormValues;\n client: ClientProfile | null;\n selectedDate: string;\n selectedSlot: Slot;\n selectedSvc: string;\n selectedLoc: string;\n svcPrice?: string;\n defaultNotes?: string;\n overrides?: SubmitBookingOverrides;\n}\n\nfunction buildBookingPayload(args: BuildBookingPayloadArgs) {\n const { form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc } = args;\n const price = args.overrides?.price ?? args.svcPrice ?? \"0\";\n const notes = args.overrides?.notes ?? args.defaultNotes;\n return {\n start_time: `${selectedDate}T${selectedSlot.start_time}:00-04:00`,\n end_time: `${selectedDate}T${selectedSlot.end_time}:00-04:00`,\n service_id: selectedSvc,\n service_provider_id: selectedSlot.provider_id,\n location_id: selectedLoc,\n price,\n notes,\n // Ignored server-side unless a client/staff auth token proves the caller's\n // identity; for a logged-in client it's redundant but harmless to include.\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nexport interface UseBookingFlowOptions extends ApiConfig {\n onBookingComplete: (booking: BookingRecord) => void;\n /** Default notes attached to every booking (e.g. \"Reserva realizada desde sitio web X\"). */\n defaultNotes?: string;\n}\n\nexport interface SubmitBookingOverrides {\n /** Override the service's list price (e.g. magnolia's price-variant step). */\n price?: string;\n /** Override defaultNotes for this specific submission. */\n notes?: string;\n}\n\n/**\n * Shared booking-flow logic: catalog fetching (locations/services/providers/\n * slots), logged-in-client prefill, form validation, and submit-with-409-\n * handling. Does NOT own step navigation or app-specific filtering (e.g.\n * magnolia's category/price-variant logic) — those stay in the consuming\n * component, layered on top of the `services`/`providers` this hook returns.\n */\nexport function useBookingFlow(opts: UseBookingFlowOptions) {\n const [locations, setLocations] = useState<Location[]>([]);\n const [services, setServices] = useState<Service[]>([]);\n const [providers, setProviders] = useState<Provider[]>([]);\n const [slots, setSlots] = useState<Slot[]>([]);\n\n const [selectedLoc, setSelectedLoc] = useState(\"\");\n const [selectedSvc, setSelectedSvc] = useState(\"\");\n const [selectedProv, setSelectedProv] = useState(\"\");\n const [selectedDate, setSelectedDate] = useState(\"\");\n const [selectedSlot, setSelectedSlot] = useState<Slot | null>(null);\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n // Prefill from a logged-in client session, if any.\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n listLocations(opts)\n .then(setLocations)\n .catch(() => setError(\"Error cargando sucursales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!selectedLoc) return;\n listServices(opts)\n .then(setServices)\n .catch(() => setError(\"Error cargando servicios\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc]);\n\n useEffect(() => {\n if (!selectedSvc) return;\n listProviders(opts)\n .then(setProviders)\n .catch(() => setError(\"Error cargando profesionales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedSvc]);\n\n useEffect(() => {\n if (!selectedLoc || !selectedDate) return;\n setLoading(true);\n getAvailableSlots(opts, {\n locationId: selectedLoc,\n startDate: selectedDate,\n serviceId: selectedSvc || undefined,\n providerId: selectedProv || undefined,\n })\n .then(s => { setSlots(s); setLoading(false); })\n .catch(() => { setError(\"Error cargando horarios\"); setLoading(false); });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc, selectedSvc, selectedProv, selectedDate]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (overrides?: SubmitBookingOverrides) => {\n if (!selectedSlot) return;\n const validationError = validateClientForm(form);\n if (validationError) { setError(validationError); return; }\n\n setLoading(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.id === selectedSvc);\n const token = getClientToken();\n const payload = buildBookingPayload({\n form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc, overrides,\n svcPrice: svc?.price, defaultNotes: opts.defaultNotes,\n });\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar la reserva\");\n setLoading(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(result.message);\n if (result.conflict) setSelectedSlot(null);\n setLoading(false);\n return;\n }\n opts.onBookingComplete(result.booking);\n }\n\n return {\n locations, services, providers, slots,\n selectedLoc, setSelectedLoc,\n selectedSvc, setSelectedSvc,\n selectedProv, setSelectedProv,\n selectedDate, setSelectedDate,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n loading, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { createBooking, getAvailableSlots, listLocations, listServices } from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport { dateStr, DEFAULT_PROVIDER_COLORS, getMondayOf, type ProviderColor } from \"../dateUtils\";\nimport type { ApiConfig, ClientFormValues, ClientProfile, Service, Slot } from \"../types\";\n\nexport interface SelectedClassSlot {\n slot: Slot;\n date: string;\n}\n\nexport interface UseClassScheduleOptions extends ApiConfig {\n onBookingComplete: () => void;\n colors?: ProviderColor[];\n}\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClassForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n return null;\n}\n\nfunction buildClassBookingPayload(\n form: ClientFormValues,\n client: ClientProfile | null,\n selectedSlot: SelectedClassSlot,\n svc: Service | undefined,\n locationId: string\n) {\n return {\n start_time: `${selectedSlot.date}T${selectedSlot.slot.start_time}:00-04:00`,\n end_time: `${selectedSlot.date}T${selectedSlot.slot.end_time}:00-04:00`,\n service_id: svc?.id ?? \"\",\n service_provider_id: selectedSlot.slot.provider_id,\n location_id: locationId,\n price: svc?.price || \"0\",\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nfunction resolveConflictMessage(result: { conflict: boolean; message: string }): string {\n return result.conflict\n ? \"Ese cupo ya fue tomado por otra persona. Cierra esta ventana y elige otro horario.\"\n : result.message;\n}\n\n/**\n * Shared weekly group-class schedule logic: week-of-slots fetching, provider\n * color-palette assignment, and submit-with-409-handling. The week-grid table\n * JSX and modal markup stay in the consuming component — this hook only owns\n * data and state transitions.\n */\nexport function useClassSchedule(opts: UseClassScheduleOptions) {\n const colors = opts.colors ?? DEFAULT_PROVIDER_COLORS;\n\n const [monday, setMonday] = useState<Date>(() => getMondayOf(new Date()));\n const [slotsByDay, setSlotsByDay] = useState<Record<string, Slot[]>>({});\n const [services, setServices] = useState<Service[]>([]);\n const [locationId, setLocationId] = useState(\"\");\n const [loading, setLoading] = useState(true);\n const [selectedSlot, setSelectedSlot] = useState<SelectedClassSlot | null>(null);\n const [providerColorMap, setProviderColorMap] = useState<Record<string, ProviderColor>>({});\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n useEffect(() => {\n Promise.all([listLocations(opts), listServices(opts, 50)])\n .then(([locs, svcs]) => {\n if (locs.length) setLocationId(locs[0].id);\n setServices(svcs);\n })\n .catch(() => setError(\"Error cargando datos\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const loadWeek = useCallback(async (mon: Date, locId: string) => {\n if (!locId) return;\n setLoading(true);\n const days = Array.from({ length: 7 }, (_, i) => {\n const d = new Date(mon);\n d.setDate(mon.getDate() + i);\n return d;\n });\n\n const results = await Promise.all(\n days.map(async d => {\n const ds = dateStr(d);\n try {\n const slots = await getAvailableSlots(opts, { locationId: locId, startDate: ds });\n return { date: ds, slots };\n } catch {\n return { date: ds, slots: [] as Slot[] };\n }\n })\n );\n\n const map: Record<string, Slot[]> = {};\n const colorMap: Record<string, ProviderColor> = {};\n let colorIdx = 0;\n results.forEach(({ date, slots }) => {\n map[date] = slots;\n slots.forEach(s => {\n if (!colorMap[s.provider_id]) {\n colorMap[s.provider_id] = colors[colorIdx % colors.length];\n colorIdx++;\n }\n });\n });\n\n setSlotsByDay(map);\n setProviderColorMap(prev => ({ ...prev, ...colorMap }));\n setLoading(false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (locationId) loadWeek(monday, locationId);\n }, [monday, locationId, loadWeek]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!selectedSlot) return;\n const validationError = validateClassForm(form);\n if (validationError) { setError(validationError); return; }\n setSubmitting(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.name === selectedSlot.slot.service_name);\n const token = getClientToken();\n const payload = buildClassBookingPayload(form, client, selectedSlot, svc, locationId);\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar\");\n setSubmitting(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(resolveConflictMessage(result));\n setSubmitting(false);\n return;\n }\n opts.onBookingComplete();\n }\n\n return {\n monday, setMonday,\n slotsByDay, loading, providerColorMap,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n submitting, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useState } from \"react\";\nimport { loginWithGoogle, sendMagicLink } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\ndeclare global {\n interface Window {\n google?: {\n accounts: {\n id: {\n initialize: (config: { client_id: string; callback: (response: { credential: string }) => void }) => void;\n prompt: () => void;\n };\n };\n };\n }\n}\n\nexport interface UseMagicLinkAuthOptions extends ApiConfig {\n googleClientId?: string;\n frontendUrl: string;\n onGoogleLoggedIn: () => void;\n}\n\nexport type MagicLinkStep = \"email\" | \"sent\";\n\nexport function useMagicLinkAuth(opts: UseMagicLinkAuthOptions) {\n const [email, setEmail] = useState(\"\");\n // Optional — only relevant on a signup-style form (e.g. registro pages)\n // that collects a bit more than login does. Login pages can ignore these.\n const [firstName, setFirstName] = useState(\"\");\n const [lastName, setLastName] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [rut, setRut] = useState(\"\");\n const [step, setStep] = useState<MagicLinkStep>(\"email\");\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const handleMagicLink = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!email.trim() || !/\\S+@\\S+\\.\\S+/.test(email)) {\n setError(\"Ingresa un email válido.\");\n return;\n }\n setLoading(true);\n setError(\"\");\n try {\n await sendMagicLink(opts, email, opts.frontendUrl, {\n firstName: firstName || undefined,\n lastName: lastName || undefined,\n phone: phone || undefined,\n rut: rut || undefined,\n });\n setStep(\"sent\");\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error enviando el link.\");\n } finally {\n setLoading(false);\n }\n };\n\n const handleGoogle = () => {\n if (!opts.googleClientId || typeof window === \"undefined\" || !window.google) return;\n window.google.accounts.id.initialize({\n client_id: opts.googleClientId,\n callback: async (response: { credential: string }) => {\n setLoading(true);\n try {\n const data = await loginWithGoogle(opts, response.credential);\n setClientToken(data.access_token);\n opts.onGoogleLoggedIn();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error con Google.\");\n setLoading(false);\n }\n },\n });\n window.google.accounts.id.prompt();\n };\n\n const reset = () => {\n setStep(\"email\");\n setError(\"\");\n };\n\n return {\n email, setEmail,\n firstName, setFirstName,\n lastName, setLastName,\n phone, setPhone,\n rut, setRut,\n step, error, loading, handleMagicLink, handleGoogle, reset,\n };\n}\n","import { useState } from \"react\";\nimport { register } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\nexport interface RegisterFormValues {\n firstName: string;\n lastName: string;\n email: string;\n phone: string;\n password: string;\n confirm: string;\n}\n\nconst EMPTY: RegisterFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", password: \"\", confirm: \"\" };\n\nexport interface UseRegisterFormOptions extends ApiConfig {\n onRegistered: () => void;\n}\n\nexport function useRegisterForm(opts: UseRegisterFormOptions) {\n const [form, setForm] = useState<RegisterFormValues>(EMPTY);\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const updateField = (fields: Partial<RegisterFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const handleSubmit = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!form.firstName.trim()) { setError(\"Ingresa tu nombre.\"); return; }\n if (!form.lastName.trim()) { setError(\"Ingresa tu apellido.\"); return; }\n if (!form.email.trim()) { setError(\"Ingresa tu email.\"); return; }\n if (form.password.length < 6) { setError(\"La contraseña debe tener al menos 6 caracteres.\"); return; }\n if (form.password !== form.confirm) { setError(\"Las contraseñas no coinciden.\"); return; }\n setLoading(true);\n setError(\"\");\n try {\n const data = await register(opts, form);\n setClientToken(data.access_token);\n opts.onRegistered();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al registrarse.\");\n } finally {\n setLoading(false);\n }\n };\n\n return { form, updateField, error, loading, handleSubmit };\n}\n","import { useEffect, useState } from \"react\";\nimport { cancelMyBooking, getMe, getMyBookings, getMyPackages, rescheduleMyBooking } from \"../api\";\nimport { clearClientToken, getClientToken } from \"../clientAuth\";\nimport type { BookingRecord, ClientProfile, PackageRecord } from \"../types\";\n\nexport interface UseClientAccountOptions {\n apiBase: string;\n onUnauthenticated: () => void;\n onLoggedOut: () => void;\n}\n\nexport function useClientAccount(opts: UseClientAccountOptions) {\n const [profile, setProfile] = useState<ClientProfile | null>(null);\n const [upcoming, setUpcoming] = useState<BookingRecord[]>([]);\n const [history, setHistory] = useState<BookingRecord[]>([]);\n const [packages, setPackages] = useState<PackageRecord[]>([]);\n const [loading, setLoading] = useState(true);\n const [actionError, setActionError] = useState(\"\");\n const [actionLoading, setActionLoading] = useState(false);\n\n const loadAll = () => {\n const token = getClientToken();\n if (!token) {\n opts.onUnauthenticated();\n return;\n }\n Promise.all([\n getMe(opts.apiBase, token),\n getMyBookings(opts.apiBase, token, { upcoming: true, perPage: 10 }),\n getMyBookings(opts.apiBase, token, { perPage: 20 }),\n getMyPackages(opts.apiBase, token),\n ])\n .then(([prof, up, hist, pkgs]) => {\n setProfile(prof);\n setUpcoming(up);\n setHistory(hist);\n setPackages(pkgs);\n setLoading(false);\n })\n .catch(() => opts.onUnauthenticated());\n };\n\n useEffect(() => {\n loadAll();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const handleLogout = () => {\n clearClientToken();\n opts.onLoggedOut();\n };\n\n const cancelBooking = async (bookingId: string) => {\n const token = getClientToken();\n if (!token) return;\n setActionLoading(true);\n setActionError(\"\");\n const result = await cancelMyBooking(opts.apiBase, token, bookingId);\n if (!result.ok) {\n setActionError(result.message);\n setActionLoading(false);\n return;\n }\n loadAll();\n setActionLoading(false);\n };\n\n const rescheduleBooking = async (bookingId: string, startTime: string, endTime: string) => {\n const token = getClientToken();\n if (!token) return false;\n setActionLoading(true);\n setActionError(\"\");\n const result = await rescheduleMyBooking(opts.apiBase, token, bookingId, startTime, endTime);\n setActionLoading(false);\n if (!result.ok) {\n setActionError(result.message);\n return false;\n }\n loadAll();\n return true;\n };\n\n const totalCredits = packages.reduce((s, p) => s + p.remaining_credits, 0);\n\n return {\n profile, upcoming, history, packages, loading, totalCredits, handleLogout,\n cancelBooking, rescheduleBooking, actionError, setActionError, actionLoading,\n };\n}\n"],"mappings":"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","names":["import_react","EMPTY_FORM","isValidPhone","import_react","import_react","import_react"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/api.ts","../src/clientAuth.ts","../src/dateUtils.ts","../src/hooks/useBookingFlow.ts","../src/hooks/useClassSchedule.ts","../src/hooks/useMagicLinkAuth.ts","../src/hooks/useRegisterForm.ts","../src/hooks/useClientAccount.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./api\";\nexport * from \"./clientAuth\";\nexport * from \"./dateUtils\";\nexport * from \"./hooks/useBookingFlow\";\nexport * from \"./hooks/useClassSchedule\";\nexport * from \"./hooks/useMagicLinkAuth\";\nexport * from \"./hooks/useRegisterForm\";\nexport * from \"./hooks/useClientAccount\";\n","import type {\n ApiConfig,\n BookingCreateInput,\n BookingRecord,\n BookingResult,\n ClientFormValues,\n ClientProfile,\n Location,\n PackageRecord,\n Provider,\n Service,\n Slot,\n WaitlistEntry,\n} from \"./types\";\n\nfunction headers(cfg: ApiConfig, withJson = false): Record<string, string> {\n const h: Record<string, string> = { \"X-API-Key\": cfg.apiKey };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nfunction authHeaders(token: string, withJson = false): Record<string, string> {\n const h: Record<string, string> = { Authorization: `Bearer ${token}` };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nexport async function listLocations(cfg: ApiConfig): Promise<Location[]> {\n const res = await fetch(`${cfg.apiBase}/v1/locations`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listServices(cfg: ApiConfig, perPage = 100): Promise<Service[]> {\n const res = await fetch(`${cfg.apiBase}/v1/services?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listProviders(cfg: ApiConfig, perPage = 100): Promise<Provider[]> {\n const res = await fetch(`${cfg.apiBase}/v1/providers?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getAvailableSlots(\n cfg: ApiConfig,\n params: { locationId: string; startDate: string; serviceId?: string; providerId?: string }\n): Promise<Slot[]> {\n const q = new URLSearchParams({ location_id: params.locationId, start_date: params.startDate });\n if (params.serviceId) q.set(\"service_id\", params.serviceId);\n if (params.providerId) q.set(\"provider_id\", params.providerId);\n const res = await fetch(`${cfg.apiBase}/v1/available-slots?${q.toString()}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data?.slots || [];\n}\n\nexport async function createClient(cfg: ApiConfig, form: ClientFormValues): Promise<{ id: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/clients`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone,\n rut: form.rut || undefined,\n }),\n });\n if (!res.ok) throw new Error(\"Error registrando datos\");\n return res.json();\n}\n\nexport async function createBooking(\n cfg: ApiConfig,\n input: BookingCreateInput,\n clientToken?: string\n): Promise<BookingResult> {\n // A logged-in client's token takes priority so the server attributes the\n // booking to their account rather than treating it as anonymous — see\n // create_booking in routes/bookings.py, which ignores any client_id sent\n // by an unauthenticated caller.\n const reqHeaders = headers(cfg, true);\n if (clientToken) reqHeaders.Authorization = `Bearer ${clientToken}`;\n const res = await fetch(`${cfg.apiBase}/v1/bookings`, {\n method: \"POST\",\n headers: reqHeaders,\n body: JSON.stringify(input),\n });\n if (res.status === 409) {\n const data = await res.json().catch(() => ({}));\n return { ok: false, conflict: true, message: data.detail || \"Ese horario ya no está disponible.\" };\n }\n if (!res.ok) {\n return { ok: false, conflict: false, message: \"Error creando la reserva. Por favor intenta nuevamente.\" };\n }\n return { ok: true, booking: await res.json() };\n}\n\nexport async function sendMagicLink(\n cfg: ApiConfig,\n email: string,\n frontendUrl: string,\n profile?: { firstName?: string; lastName?: string; phone?: string; rut?: string }\n): Promise<void> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n email: email.trim().toLowerCase(),\n frontend_url: frontendUrl,\n first_name: profile?.firstName,\n last_name: profile?.lastName,\n phone: profile?.phone,\n rut: profile?.rut,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error enviando el link.\");\n}\n\nexport async function verifyMagicLink(cfg: ApiConfig, token: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link/verify`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ token }),\n });\n const data = await res.json();\n if (!data.access_token) throw new Error(data.detail || \"Link inválido.\");\n return data;\n}\n\nexport async function loginWithGoogle(cfg: ApiConfig, credential: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/google`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ credential }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error con Google.\");\n return data;\n}\n\nexport async function register(\n cfg: ApiConfig,\n form: { firstName: string; lastName: string; email: string; phone?: string; password: string }\n): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/register`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone || undefined,\n password: form.password,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error al registrarse.\");\n return data;\n}\n\nexport async function getMe(apiBase: string, token: string): Promise<ClientProfile> {\n const res = await fetch(`${apiBase}/v1/me`, { headers: authHeaders(token) });\n return res.json();\n}\n\nexport async function getMyBookings(\n apiBase: string,\n token: string,\n params?: { upcoming?: boolean; perPage?: number }\n): Promise<BookingRecord[]> {\n const q = new URLSearchParams();\n if (params?.upcoming) q.set(\"upcoming\", \"true\");\n q.set(\"per_page\", String(params?.perPage ?? 20));\n const res = await fetch(`${apiBase}/v1/me/bookings?${q.toString()}`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getMyPackages(apiBase: string, token: string): Promise<PackageRecord[]> {\n const res = await fetch(`${apiBase}/v1/me/packages`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\n/** Result of a client cancelling/rescheduling their own booking — callers\n * branch on `.ok` to show the server's specific reason (cutoff window,\n * overlap, etc.) instead of a generic error. */\nexport type MyBookingActionResult =\n | { ok: true; booking: BookingRecord }\n | { ok: false; message: string };\n\nexport async function cancelMyBooking(\n apiBase: string, token: string, bookingId: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/cancel`, {\n method: \"POST\",\n headers: authHeaders(token),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo cancelar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function rescheduleMyBooking(\n apiBase: string, token: string, bookingId: string, startTime: string, endTime: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/reschedule`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({ start_time: startTime, end_time: endTime }),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo reprogramar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function joinWaitlist(\n apiBase: string,\n token: string,\n params: {\n serviceId: string;\n locationId: string;\n providerId?: string;\n date?: string;\n dateUntil?: string;\n classSessionId?: string;\n }\n): Promise<WaitlistEntry> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({\n service_id: params.serviceId,\n location_id: params.locationId,\n provider_id: params.providerId,\n date: params.date,\n date_until: params.dateUntil,\n class_session_id: params.classSessionId,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"No se pudo unir a la lista de espera.\");\n return data;\n}\n\nexport async function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void> {\n await fetch(`${apiBase}/v1/me/waitlist/${entryId}`, {\n method: \"DELETE\",\n headers: authHeaders(token),\n });\n}\n\nexport async function confirmWaitlistOffer(cfg: ApiConfig, token: string): Promise<WaitlistEntry> {\n const res = await fetch(`${cfg.apiBase}/v1/waitlist/confirm/${token}`, {\n method: \"POST\",\n headers: headers(cfg),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"No se pudo confirmar el cupo.\");\n return data;\n}\n","import { getMe } from \"./api\";\nimport type { ClientProfile } from \"./types\";\n\nconst TOKEN_KEY = \"client_token\";\n\nexport function getClientToken(): string | null {\n if (typeof window === \"undefined\") return null;\n return localStorage.getItem(TOKEN_KEY);\n}\n\nexport function setClientToken(token: string): void {\n if (typeof window === \"undefined\") return;\n localStorage.setItem(TOKEN_KEY, token);\n}\n\nexport function clearClientToken(): void {\n if (typeof window === \"undefined\") return;\n localStorage.removeItem(TOKEN_KEY);\n}\n\nexport async function fetchMe(apiBase: string, token: string): Promise<ClientProfile | null> {\n try {\n return await getMe(apiBase, token);\n } catch {\n return null;\n }\n}\n","export function getMondayOf(date: Date): Date {\n const d = new Date(date);\n const day = (d.getDay() + 6) % 7;\n d.setDate(d.getDate() - day);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\nexport function dateStr(d: Date): string {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`;\n}\n\nexport function formatMonthRange(monday: Date): string {\n const sunday = new Date(monday);\n sunday.setDate(monday.getDate() + 6);\n const opts: Intl.DateTimeFormatOptions = { day: \"numeric\", month: \"long\" };\n const start = monday.toLocaleDateString(\"es-CL\", opts);\n const end = sunday.toLocaleDateString(\"es-CL\", opts);\n return `${start} – ${end}`;\n}\n\nexport const DAY_NAMES = [\"Lun\", \"Mar\", \"Mié\", \"Jue\", \"Vie\", \"Sáb\", \"Dom\"];\nexport const DAY_NAMES_FULL = [\"Lunes\", \"Martes\", \"Miércoles\", \"Jueves\", \"Viernes\", \"Sábado\", \"Domingo\"];\n\nexport interface ProviderColor {\n bg: string;\n border: string;\n text: string;\n}\n\nexport const DEFAULT_PROVIDER_COLORS: ProviderColor[] = [\n { bg: \"#e8f5f0\", border: \"#2bbf8e\", text: \"#1a7a5a\" },\n { bg: \"#eef0fb\", border: \"#6b7de8\", text: \"#3d4fa8\" },\n { bg: \"#fdf3e8\", border: \"#e8a24b\", text: \"#a0600a\" },\n { bg: \"#fdeef4\", border: \"#e86b9a\", text: \"#a03060\" },\n];\n","import { useEffect, useState } from \"react\";\nimport {\n createBooking,\n getAvailableSlots,\n listLocations,\n listProviders,\n listServices,\n} from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport type {\n ApiConfig,\n BookingRecord,\n ClientFormValues,\n ClientProfile,\n Location,\n Provider,\n Service,\n Slot,\n} from \"../types\";\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClientForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n if (!form.rut.trim()) return \"Por favor ingresa tu RUT.\";\n return null;\n}\n\ninterface BuildBookingPayloadArgs {\n form: ClientFormValues;\n client: ClientProfile | null;\n selectedDate: string;\n selectedSlot: Slot;\n selectedSvc: string;\n selectedLoc: string;\n svcPrice?: string;\n defaultNotes?: string;\n overrides?: SubmitBookingOverrides;\n}\n\nfunction buildBookingPayload(args: BuildBookingPayloadArgs) {\n const { form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc } = args;\n const price = args.overrides?.price ?? args.svcPrice ?? \"0\";\n const notes = args.overrides?.notes ?? args.defaultNotes;\n return {\n start_time: `${selectedDate}T${selectedSlot.start_time}:00-04:00`,\n end_time: `${selectedDate}T${selectedSlot.end_time}:00-04:00`,\n service_id: selectedSvc,\n service_provider_id: selectedSlot.provider_id,\n location_id: selectedLoc,\n price,\n notes,\n // Ignored server-side unless a client/staff auth token proves the caller's\n // identity; for a logged-in client it's redundant but harmless to include.\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nexport interface UseBookingFlowOptions extends ApiConfig {\n onBookingComplete: (booking: BookingRecord) => void;\n /** Default notes attached to every booking (e.g. \"Reserva realizada desde sitio web X\"). */\n defaultNotes?: string;\n}\n\nexport interface SubmitBookingOverrides {\n /** Override the service's list price (e.g. magnolia's price-variant step). */\n price?: string;\n /** Override defaultNotes for this specific submission. */\n notes?: string;\n}\n\n/**\n * Shared booking-flow logic: catalog fetching (locations/services/providers/\n * slots), logged-in-client prefill, form validation, and submit-with-409-\n * handling. Does NOT own step navigation or app-specific filtering (e.g.\n * magnolia's category/price-variant logic) — those stay in the consuming\n * component, layered on top of the `services`/`providers` this hook returns.\n */\nexport function useBookingFlow(opts: UseBookingFlowOptions) {\n const [locations, setLocations] = useState<Location[]>([]);\n const [services, setServices] = useState<Service[]>([]);\n const [providers, setProviders] = useState<Provider[]>([]);\n const [slots, setSlots] = useState<Slot[]>([]);\n\n const [selectedLoc, setSelectedLoc] = useState(\"\");\n const [selectedSvc, setSelectedSvc] = useState(\"\");\n const [selectedProv, setSelectedProv] = useState(\"\");\n const [selectedDate, setSelectedDate] = useState(\"\");\n const [selectedSlot, setSelectedSlot] = useState<Slot | null>(null);\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n // Prefill from a logged-in client session, if any.\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n listLocations(opts)\n .then(setLocations)\n .catch(() => setError(\"Error cargando sucursales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!selectedLoc) return;\n listServices(opts)\n .then(setServices)\n .catch(() => setError(\"Error cargando servicios\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc]);\n\n useEffect(() => {\n if (!selectedSvc) return;\n listProviders(opts)\n .then(setProviders)\n .catch(() => setError(\"Error cargando profesionales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedSvc]);\n\n useEffect(() => {\n if (!selectedLoc || !selectedDate) return;\n setLoading(true);\n getAvailableSlots(opts, {\n locationId: selectedLoc,\n startDate: selectedDate,\n serviceId: selectedSvc || undefined,\n providerId: selectedProv || undefined,\n })\n .then(s => { setSlots(s); setLoading(false); })\n .catch(() => { setError(\"Error cargando horarios\"); setLoading(false); });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc, selectedSvc, selectedProv, selectedDate]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (overrides?: SubmitBookingOverrides) => {\n if (!selectedSlot) return;\n const validationError = validateClientForm(form);\n if (validationError) { setError(validationError); return; }\n\n setLoading(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.id === selectedSvc);\n const token = getClientToken();\n const payload = buildBookingPayload({\n form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc, overrides,\n svcPrice: svc?.price, defaultNotes: opts.defaultNotes,\n });\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar la reserva\");\n setLoading(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(result.message);\n if (result.conflict) setSelectedSlot(null);\n setLoading(false);\n return;\n }\n opts.onBookingComplete(result.booking);\n }\n\n return {\n locations, services, providers, slots,\n selectedLoc, setSelectedLoc,\n selectedSvc, setSelectedSvc,\n selectedProv, setSelectedProv,\n selectedDate, setSelectedDate,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n loading, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { createBooking, getAvailableSlots, listLocations, listServices } from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport { dateStr, DEFAULT_PROVIDER_COLORS, getMondayOf, type ProviderColor } from \"../dateUtils\";\nimport type { ApiConfig, ClientFormValues, ClientProfile, Service, Slot } from \"../types\";\n\nexport interface SelectedClassSlot {\n slot: Slot;\n date: string;\n}\n\nexport interface UseClassScheduleOptions extends ApiConfig {\n onBookingComplete: () => void;\n colors?: ProviderColor[];\n}\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClassForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n return null;\n}\n\nfunction buildClassBookingPayload(\n form: ClientFormValues,\n client: ClientProfile | null,\n selectedSlot: SelectedClassSlot,\n svc: Service | undefined,\n locationId: string\n) {\n return {\n start_time: `${selectedSlot.date}T${selectedSlot.slot.start_time}:00-04:00`,\n end_time: `${selectedSlot.date}T${selectedSlot.slot.end_time}:00-04:00`,\n service_id: svc?.id ?? \"\",\n service_provider_id: selectedSlot.slot.provider_id,\n location_id: locationId,\n price: svc?.price || \"0\",\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nfunction resolveConflictMessage(result: { conflict: boolean; message: string }): string {\n return result.conflict\n ? \"Ese cupo ya fue tomado por otra persona. Cierra esta ventana y elige otro horario.\"\n : result.message;\n}\n\n/**\n * Shared weekly group-class schedule logic: week-of-slots fetching, provider\n * color-palette assignment, and submit-with-409-handling. The week-grid table\n * JSX and modal markup stay in the consuming component — this hook only owns\n * data and state transitions.\n */\nexport function useClassSchedule(opts: UseClassScheduleOptions) {\n const colors = opts.colors ?? DEFAULT_PROVIDER_COLORS;\n\n const [monday, setMonday] = useState<Date>(() => getMondayOf(new Date()));\n const [slotsByDay, setSlotsByDay] = useState<Record<string, Slot[]>>({});\n const [services, setServices] = useState<Service[]>([]);\n const [locationId, setLocationId] = useState(\"\");\n const [loading, setLoading] = useState(true);\n const [selectedSlot, setSelectedSlot] = useState<SelectedClassSlot | null>(null);\n const [providerColorMap, setProviderColorMap] = useState<Record<string, ProviderColor>>({});\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n useEffect(() => {\n Promise.all([listLocations(opts), listServices(opts, 50)])\n .then(([locs, svcs]) => {\n if (locs.length) setLocationId(locs[0].id);\n setServices(svcs);\n })\n .catch(() => setError(\"Error cargando datos\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const loadWeek = useCallback(async (mon: Date, locId: string) => {\n if (!locId) return;\n setLoading(true);\n const days = Array.from({ length: 7 }, (_, i) => {\n const d = new Date(mon);\n d.setDate(mon.getDate() + i);\n return d;\n });\n\n const results = await Promise.all(\n days.map(async d => {\n const ds = dateStr(d);\n try {\n const slots = await getAvailableSlots(opts, { locationId: locId, startDate: ds });\n return { date: ds, slots };\n } catch {\n return { date: ds, slots: [] as Slot[] };\n }\n })\n );\n\n const map: Record<string, Slot[]> = {};\n const colorMap: Record<string, ProviderColor> = {};\n let colorIdx = 0;\n results.forEach(({ date, slots }) => {\n map[date] = slots;\n slots.forEach(s => {\n if (!colorMap[s.provider_id]) {\n colorMap[s.provider_id] = colors[colorIdx % colors.length];\n colorIdx++;\n }\n });\n });\n\n setSlotsByDay(map);\n setProviderColorMap(prev => ({ ...prev, ...colorMap }));\n setLoading(false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (locationId) loadWeek(monday, locationId);\n }, [monday, locationId, loadWeek]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!selectedSlot) return;\n const validationError = validateClassForm(form);\n if (validationError) { setError(validationError); return; }\n setSubmitting(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.name === selectedSlot.slot.service_name);\n const token = getClientToken();\n const payload = buildClassBookingPayload(form, client, selectedSlot, svc, locationId);\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar\");\n setSubmitting(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(resolveConflictMessage(result));\n setSubmitting(false);\n return;\n }\n opts.onBookingComplete();\n }\n\n return {\n monday, setMonday,\n slotsByDay, loading, providerColorMap,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n submitting, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useState } from \"react\";\nimport { loginWithGoogle, sendMagicLink } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\ndeclare global {\n interface Window {\n google?: {\n accounts: {\n id: {\n initialize: (config: { client_id: string; callback: (response: { credential: string }) => void }) => void;\n prompt: () => void;\n };\n };\n };\n }\n}\n\nexport interface UseMagicLinkAuthOptions extends ApiConfig {\n googleClientId?: string;\n frontendUrl: string;\n onGoogleLoggedIn: () => void;\n}\n\nexport type MagicLinkStep = \"email\" | \"sent\";\n\nexport function useMagicLinkAuth(opts: UseMagicLinkAuthOptions) {\n const [email, setEmail] = useState(\"\");\n // Optional — only relevant on a signup-style form (e.g. registro pages)\n // that collects a bit more than login does. Login pages can ignore these.\n const [firstName, setFirstName] = useState(\"\");\n const [lastName, setLastName] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [rut, setRut] = useState(\"\");\n const [step, setStep] = useState<MagicLinkStep>(\"email\");\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const handleMagicLink = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!email.trim() || !/\\S+@\\S+\\.\\S+/.test(email)) {\n setError(\"Ingresa un email válido.\");\n return;\n }\n setLoading(true);\n setError(\"\");\n try {\n await sendMagicLink(opts, email, opts.frontendUrl, {\n firstName: firstName || undefined,\n lastName: lastName || undefined,\n phone: phone || undefined,\n rut: rut || undefined,\n });\n setStep(\"sent\");\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error enviando el link.\");\n } finally {\n setLoading(false);\n }\n };\n\n const handleGoogle = () => {\n if (!opts.googleClientId || typeof window === \"undefined\" || !window.google) return;\n window.google.accounts.id.initialize({\n client_id: opts.googleClientId,\n callback: async (response: { credential: string }) => {\n setLoading(true);\n try {\n const data = await loginWithGoogle(opts, response.credential);\n setClientToken(data.access_token);\n opts.onGoogleLoggedIn();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error con Google.\");\n setLoading(false);\n }\n },\n });\n window.google.accounts.id.prompt();\n };\n\n const reset = () => {\n setStep(\"email\");\n setError(\"\");\n };\n\n return {\n email, setEmail,\n firstName, setFirstName,\n lastName, setLastName,\n phone, setPhone,\n rut, setRut,\n step, error, loading, handleMagicLink, handleGoogle, reset,\n };\n}\n","import { useState } from \"react\";\nimport { register } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\nexport interface RegisterFormValues {\n firstName: string;\n lastName: string;\n email: string;\n phone: string;\n password: string;\n confirm: string;\n}\n\nconst EMPTY: RegisterFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", password: \"\", confirm: \"\" };\n\nexport interface UseRegisterFormOptions extends ApiConfig {\n onRegistered: () => void;\n}\n\nexport function useRegisterForm(opts: UseRegisterFormOptions) {\n const [form, setForm] = useState<RegisterFormValues>(EMPTY);\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const updateField = (fields: Partial<RegisterFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const handleSubmit = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!form.firstName.trim()) { setError(\"Ingresa tu nombre.\"); return; }\n if (!form.lastName.trim()) { setError(\"Ingresa tu apellido.\"); return; }\n if (!form.email.trim()) { setError(\"Ingresa tu email.\"); return; }\n if (form.password.length < 6) { setError(\"La contraseña debe tener al menos 6 caracteres.\"); return; }\n if (form.password !== form.confirm) { setError(\"Las contraseñas no coinciden.\"); return; }\n setLoading(true);\n setError(\"\");\n try {\n const data = await register(opts, form);\n setClientToken(data.access_token);\n opts.onRegistered();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al registrarse.\");\n } finally {\n setLoading(false);\n }\n };\n\n return { form, updateField, error, loading, handleSubmit };\n}\n","import { useEffect, useState } from \"react\";\nimport { cancelMyBooking, getMe, getMyBookings, getMyPackages, rescheduleMyBooking } from \"../api\";\nimport { clearClientToken, getClientToken } from \"../clientAuth\";\nimport type { BookingRecord, ClientProfile, PackageRecord } from \"../types\";\n\nexport interface UseClientAccountOptions {\n apiBase: string;\n onUnauthenticated: () => void;\n onLoggedOut: () => void;\n}\n\nexport function useClientAccount(opts: UseClientAccountOptions) {\n const [profile, setProfile] = useState<ClientProfile | null>(null);\n const [upcoming, setUpcoming] = useState<BookingRecord[]>([]);\n const [history, setHistory] = useState<BookingRecord[]>([]);\n const [packages, setPackages] = useState<PackageRecord[]>([]);\n const [loading, setLoading] = useState(true);\n const [actionError, setActionError] = useState(\"\");\n const [actionLoading, setActionLoading] = useState(false);\n\n const loadAll = () => {\n const token = getClientToken();\n if (!token) {\n opts.onUnauthenticated();\n return;\n }\n Promise.all([\n getMe(opts.apiBase, token),\n getMyBookings(opts.apiBase, token, { upcoming: true, perPage: 10 }),\n getMyBookings(opts.apiBase, token, { perPage: 20 }),\n getMyPackages(opts.apiBase, token),\n ])\n .then(([prof, up, hist, pkgs]) => {\n setProfile(prof);\n setUpcoming(up);\n setHistory(hist);\n setPackages(pkgs);\n setLoading(false);\n })\n .catch(() => opts.onUnauthenticated());\n };\n\n useEffect(() => {\n loadAll();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const handleLogout = () => {\n clearClientToken();\n opts.onLoggedOut();\n };\n\n const cancelBooking = async (bookingId: string) => {\n const token = getClientToken();\n if (!token) return;\n setActionLoading(true);\n setActionError(\"\");\n const result = await cancelMyBooking(opts.apiBase, token, bookingId);\n if (!result.ok) {\n setActionError(result.message);\n setActionLoading(false);\n return;\n }\n loadAll();\n setActionLoading(false);\n };\n\n const rescheduleBooking = async (bookingId: string, startTime: string, endTime: string) => {\n const token = getClientToken();\n if (!token) return false;\n setActionLoading(true);\n setActionError(\"\");\n const result = await rescheduleMyBooking(opts.apiBase, token, bookingId, startTime, endTime);\n setActionLoading(false);\n if (!result.ok) {\n setActionError(result.message);\n return false;\n }\n loadAll();\n return true;\n };\n\n const totalCredits = packages.reduce((s, p) => s + p.remaining_credits, 0);\n\n return {\n profile, upcoming, history, packages, loading, totalCredits, handleLogout,\n cancelBooking, rescheduleBooking, actionError, setActionError, actionLoading,\n };\n}\n"],"mappings":"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","names":["import_react","EMPTY_FORM","isValidPhone","import_react","import_react","import_react"]}
package/dist/index.d.cts CHANGED
@@ -42,7 +42,13 @@ interface WaitlistEntry {
42
42
  location_id: string;
43
43
  class_session_id: string | null;
44
44
  date: string | null;
45
+ date_until: string | null;
46
+ status: "waiting" | "offered" | "confirmed" | "expired";
45
47
  notified_at: string | null;
48
+ offer_expires_at: string | null;
49
+ offered_start_time: string | null;
50
+ offered_end_time: string | null;
51
+ booking_id: string | null;
46
52
  created_at: string;
47
53
  }
48
54
  interface ClientProfile {
@@ -172,10 +178,12 @@ declare function joinWaitlist(apiBase: string, token: string, params: {
172
178
  locationId: string;
173
179
  providerId?: string;
174
180
  date?: string;
181
+ dateUntil?: string;
175
182
  classSessionId?: string;
176
183
  }): Promise<WaitlistEntry>;
177
184
  declare function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]>;
178
185
  declare function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void>;
186
+ declare function confirmWaitlistOffer(cfg: ApiConfig, token: string): Promise<WaitlistEntry>;
179
187
 
180
188
  declare function getClientToken(): string | null;
181
189
  declare function setClientToken(token: string): void;
@@ -354,4 +362,4 @@ declare function useClientAccount(opts: UseClientAccountOptions): {
354
362
  actionLoading: boolean;
355
363
  };
356
364
 
357
- export { type ApiConfig, type BookingCreateInput, type BookingRecord, type BookingResult, type ClientFormValues, type ClientProfile, DAY_NAMES, DAY_NAMES_FULL, DEFAULT_PROVIDER_COLORS, type Location, type MagicLinkStep, type MyBookingActionResult, type PackageRecord, type Provider, type ProviderColor, type RegisterFormValues, type SelectedClassSlot, type Service, type Slot, type SubmitBookingOverrides, type UseBookingFlowOptions, type UseClassScheduleOptions, type UseClientAccountOptions, type UseMagicLinkAuthOptions, type UseRegisterFormOptions, type WaitlistEntry, cancelMyBooking, clearClientToken, createBooking, createClient, dateStr, fetchMe, formatMonthRange, getAvailableSlots, getClientToken, getMe, getMondayOf, getMyBookings, getMyPackages, getMyWaitlist, joinWaitlist, leaveWaitlist, listLocations, listProviders, listServices, loginWithGoogle, register, rescheduleMyBooking, sendMagicLink, setClientToken, useBookingFlow, useClassSchedule, useClientAccount, useMagicLinkAuth, useRegisterForm, verifyMagicLink };
365
+ export { type ApiConfig, type BookingCreateInput, type BookingRecord, type BookingResult, type ClientFormValues, type ClientProfile, DAY_NAMES, DAY_NAMES_FULL, DEFAULT_PROVIDER_COLORS, type Location, type MagicLinkStep, type MyBookingActionResult, type PackageRecord, type Provider, type ProviderColor, type RegisterFormValues, type SelectedClassSlot, type Service, type Slot, type SubmitBookingOverrides, type UseBookingFlowOptions, type UseClassScheduleOptions, type UseClientAccountOptions, type UseMagicLinkAuthOptions, type UseRegisterFormOptions, type WaitlistEntry, cancelMyBooking, clearClientToken, confirmWaitlistOffer, createBooking, createClient, dateStr, fetchMe, formatMonthRange, getAvailableSlots, getClientToken, getMe, getMondayOf, getMyBookings, getMyPackages, getMyWaitlist, joinWaitlist, leaveWaitlist, listLocations, listProviders, listServices, loginWithGoogle, register, rescheduleMyBooking, sendMagicLink, setClientToken, useBookingFlow, useClassSchedule, useClientAccount, useMagicLinkAuth, useRegisterForm, verifyMagicLink };
package/dist/index.d.ts CHANGED
@@ -42,7 +42,13 @@ interface WaitlistEntry {
42
42
  location_id: string;
43
43
  class_session_id: string | null;
44
44
  date: string | null;
45
+ date_until: string | null;
46
+ status: "waiting" | "offered" | "confirmed" | "expired";
45
47
  notified_at: string | null;
48
+ offer_expires_at: string | null;
49
+ offered_start_time: string | null;
50
+ offered_end_time: string | null;
51
+ booking_id: string | null;
46
52
  created_at: string;
47
53
  }
48
54
  interface ClientProfile {
@@ -172,10 +178,12 @@ declare function joinWaitlist(apiBase: string, token: string, params: {
172
178
  locationId: string;
173
179
  providerId?: string;
174
180
  date?: string;
181
+ dateUntil?: string;
175
182
  classSessionId?: string;
176
183
  }): Promise<WaitlistEntry>;
177
184
  declare function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]>;
178
185
  declare function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void>;
186
+ declare function confirmWaitlistOffer(cfg: ApiConfig, token: string): Promise<WaitlistEntry>;
179
187
 
180
188
  declare function getClientToken(): string | null;
181
189
  declare function setClientToken(token: string): void;
@@ -354,4 +362,4 @@ declare function useClientAccount(opts: UseClientAccountOptions): {
354
362
  actionLoading: boolean;
355
363
  };
356
364
 
357
- export { type ApiConfig, type BookingCreateInput, type BookingRecord, type BookingResult, type ClientFormValues, type ClientProfile, DAY_NAMES, DAY_NAMES_FULL, DEFAULT_PROVIDER_COLORS, type Location, type MagicLinkStep, type MyBookingActionResult, type PackageRecord, type Provider, type ProviderColor, type RegisterFormValues, type SelectedClassSlot, type Service, type Slot, type SubmitBookingOverrides, type UseBookingFlowOptions, type UseClassScheduleOptions, type UseClientAccountOptions, type UseMagicLinkAuthOptions, type UseRegisterFormOptions, type WaitlistEntry, cancelMyBooking, clearClientToken, createBooking, createClient, dateStr, fetchMe, formatMonthRange, getAvailableSlots, getClientToken, getMe, getMondayOf, getMyBookings, getMyPackages, getMyWaitlist, joinWaitlist, leaveWaitlist, listLocations, listProviders, listServices, loginWithGoogle, register, rescheduleMyBooking, sendMagicLink, setClientToken, useBookingFlow, useClassSchedule, useClientAccount, useMagicLinkAuth, useRegisterForm, verifyMagicLink };
365
+ export { type ApiConfig, type BookingCreateInput, type BookingRecord, type BookingResult, type ClientFormValues, type ClientProfile, DAY_NAMES, DAY_NAMES_FULL, DEFAULT_PROVIDER_COLORS, type Location, type MagicLinkStep, type MyBookingActionResult, type PackageRecord, type Provider, type ProviderColor, type RegisterFormValues, type SelectedClassSlot, type Service, type Slot, type SubmitBookingOverrides, type UseBookingFlowOptions, type UseClassScheduleOptions, type UseClientAccountOptions, type UseMagicLinkAuthOptions, type UseRegisterFormOptions, type WaitlistEntry, cancelMyBooking, clearClientToken, confirmWaitlistOffer, createBooking, createClient, dateStr, fetchMe, formatMonthRange, getAvailableSlots, getClientToken, getMe, getMondayOf, getMyBookings, getMyPackages, getMyWaitlist, joinWaitlist, leaveWaitlist, listLocations, listProviders, listServices, loginWithGoogle, register, rescheduleMyBooking, sendMagicLink, setClientToken, useBookingFlow, useClassSchedule, useClientAccount, useMagicLinkAuth, useRegisterForm, verifyMagicLink };
package/dist/index.js CHANGED
@@ -161,6 +161,7 @@ async function joinWaitlist(apiBase, token, params) {
161
161
  location_id: params.locationId,
162
162
  provider_id: params.providerId,
163
163
  date: params.date,
164
+ date_until: params.dateUntil,
164
165
  class_session_id: params.classSessionId
165
166
  })
166
167
  });
@@ -179,6 +180,15 @@ async function leaveWaitlist(apiBase, token, entryId) {
179
180
  headers: authHeaders(token)
180
181
  });
181
182
  }
183
+ async function confirmWaitlistOffer(cfg, token) {
184
+ const res = await fetch(`${cfg.apiBase}/v1/waitlist/confirm/${token}`, {
185
+ method: "POST",
186
+ headers: headers(cfg)
187
+ });
188
+ const data = await res.json();
189
+ if (!res.ok) throw new Error(data.detail || "No se pudo confirmar el cupo.");
190
+ return data;
191
+ }
182
192
 
183
193
  // src/clientAuth.ts
184
194
  var TOKEN_KEY = "client_token";
@@ -747,6 +757,7 @@ export {
747
757
  DEFAULT_PROVIDER_COLORS,
748
758
  cancelMyBooking,
749
759
  clearClientToken,
760
+ confirmWaitlistOffer,
750
761
  createBooking,
751
762
  createClient,
752
763
  dateStr,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api.ts","../src/clientAuth.ts","../src/dateUtils.ts","../src/hooks/useBookingFlow.ts","../src/hooks/useClassSchedule.ts","../src/hooks/useMagicLinkAuth.ts","../src/hooks/useRegisterForm.ts","../src/hooks/useClientAccount.ts"],"sourcesContent":["import type {\n ApiConfig,\n BookingCreateInput,\n BookingRecord,\n BookingResult,\n ClientFormValues,\n ClientProfile,\n Location,\n PackageRecord,\n Provider,\n Service,\n Slot,\n WaitlistEntry,\n} from \"./types\";\n\nfunction headers(cfg: ApiConfig, withJson = false): Record<string, string> {\n const h: Record<string, string> = { \"X-API-Key\": cfg.apiKey };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nfunction authHeaders(token: string, withJson = false): Record<string, string> {\n const h: Record<string, string> = { Authorization: `Bearer ${token}` };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nexport async function listLocations(cfg: ApiConfig): Promise<Location[]> {\n const res = await fetch(`${cfg.apiBase}/v1/locations`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listServices(cfg: ApiConfig, perPage = 100): Promise<Service[]> {\n const res = await fetch(`${cfg.apiBase}/v1/services?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listProviders(cfg: ApiConfig, perPage = 100): Promise<Provider[]> {\n const res = await fetch(`${cfg.apiBase}/v1/providers?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getAvailableSlots(\n cfg: ApiConfig,\n params: { locationId: string; startDate: string; serviceId?: string; providerId?: string }\n): Promise<Slot[]> {\n const q = new URLSearchParams({ location_id: params.locationId, start_date: params.startDate });\n if (params.serviceId) q.set(\"service_id\", params.serviceId);\n if (params.providerId) q.set(\"provider_id\", params.providerId);\n const res = await fetch(`${cfg.apiBase}/v1/available-slots?${q.toString()}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data?.slots || [];\n}\n\nexport async function createClient(cfg: ApiConfig, form: ClientFormValues): Promise<{ id: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/clients`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone,\n rut: form.rut || undefined,\n }),\n });\n if (!res.ok) throw new Error(\"Error registrando datos\");\n return res.json();\n}\n\nexport async function createBooking(\n cfg: ApiConfig,\n input: BookingCreateInput,\n clientToken?: string\n): Promise<BookingResult> {\n // A logged-in client's token takes priority so the server attributes the\n // booking to their account rather than treating it as anonymous — see\n // create_booking in routes/bookings.py, which ignores any client_id sent\n // by an unauthenticated caller.\n const reqHeaders = headers(cfg, true);\n if (clientToken) reqHeaders.Authorization = `Bearer ${clientToken}`;\n const res = await fetch(`${cfg.apiBase}/v1/bookings`, {\n method: \"POST\",\n headers: reqHeaders,\n body: JSON.stringify(input),\n });\n if (res.status === 409) {\n const data = await res.json().catch(() => ({}));\n return { ok: false, conflict: true, message: data.detail || \"Ese horario ya no está disponible.\" };\n }\n if (!res.ok) {\n return { ok: false, conflict: false, message: \"Error creando la reserva. Por favor intenta nuevamente.\" };\n }\n return { ok: true, booking: await res.json() };\n}\n\nexport async function sendMagicLink(\n cfg: ApiConfig,\n email: string,\n frontendUrl: string,\n profile?: { firstName?: string; lastName?: string; phone?: string; rut?: string }\n): Promise<void> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n email: email.trim().toLowerCase(),\n frontend_url: frontendUrl,\n first_name: profile?.firstName,\n last_name: profile?.lastName,\n phone: profile?.phone,\n rut: profile?.rut,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error enviando el link.\");\n}\n\nexport async function verifyMagicLink(cfg: ApiConfig, token: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link/verify`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ token }),\n });\n const data = await res.json();\n if (!data.access_token) throw new Error(data.detail || \"Link inválido.\");\n return data;\n}\n\nexport async function loginWithGoogle(cfg: ApiConfig, credential: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/google`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ credential }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error con Google.\");\n return data;\n}\n\nexport async function register(\n cfg: ApiConfig,\n form: { firstName: string; lastName: string; email: string; phone?: string; password: string }\n): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/register`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone || undefined,\n password: form.password,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error al registrarse.\");\n return data;\n}\n\nexport async function getMe(apiBase: string, token: string): Promise<ClientProfile> {\n const res = await fetch(`${apiBase}/v1/me`, { headers: authHeaders(token) });\n return res.json();\n}\n\nexport async function getMyBookings(\n apiBase: string,\n token: string,\n params?: { upcoming?: boolean; perPage?: number }\n): Promise<BookingRecord[]> {\n const q = new URLSearchParams();\n if (params?.upcoming) q.set(\"upcoming\", \"true\");\n q.set(\"per_page\", String(params?.perPage ?? 20));\n const res = await fetch(`${apiBase}/v1/me/bookings?${q.toString()}`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getMyPackages(apiBase: string, token: string): Promise<PackageRecord[]> {\n const res = await fetch(`${apiBase}/v1/me/packages`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\n/** Result of a client cancelling/rescheduling their own booking — callers\n * branch on `.ok` to show the server's specific reason (cutoff window,\n * overlap, etc.) instead of a generic error. */\nexport type MyBookingActionResult =\n | { ok: true; booking: BookingRecord }\n | { ok: false; message: string };\n\nexport async function cancelMyBooking(\n apiBase: string, token: string, bookingId: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/cancel`, {\n method: \"POST\",\n headers: authHeaders(token),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo cancelar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function rescheduleMyBooking(\n apiBase: string, token: string, bookingId: string, startTime: string, endTime: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/reschedule`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({ start_time: startTime, end_time: endTime }),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo reprogramar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function joinWaitlist(\n apiBase: string,\n token: string,\n params: { serviceId: string; locationId: string; providerId?: string; date?: string; classSessionId?: string }\n): Promise<WaitlistEntry> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({\n service_id: params.serviceId,\n location_id: params.locationId,\n provider_id: params.providerId,\n date: params.date,\n class_session_id: params.classSessionId,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"No se pudo unir a la lista de espera.\");\n return data;\n}\n\nexport async function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void> {\n await fetch(`${apiBase}/v1/me/waitlist/${entryId}`, {\n method: \"DELETE\",\n headers: authHeaders(token),\n });\n}\n","import { getMe } from \"./api\";\nimport type { ClientProfile } from \"./types\";\n\nconst TOKEN_KEY = \"client_token\";\n\nexport function getClientToken(): string | null {\n if (typeof window === \"undefined\") return null;\n return localStorage.getItem(TOKEN_KEY);\n}\n\nexport function setClientToken(token: string): void {\n if (typeof window === \"undefined\") return;\n localStorage.setItem(TOKEN_KEY, token);\n}\n\nexport function clearClientToken(): void {\n if (typeof window === \"undefined\") return;\n localStorage.removeItem(TOKEN_KEY);\n}\n\nexport async function fetchMe(apiBase: string, token: string): Promise<ClientProfile | null> {\n try {\n return await getMe(apiBase, token);\n } catch {\n return null;\n }\n}\n","export function getMondayOf(date: Date): Date {\n const d = new Date(date);\n const day = (d.getDay() + 6) % 7;\n d.setDate(d.getDate() - day);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\nexport function dateStr(d: Date): string {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`;\n}\n\nexport function formatMonthRange(monday: Date): string {\n const sunday = new Date(monday);\n sunday.setDate(monday.getDate() + 6);\n const opts: Intl.DateTimeFormatOptions = { day: \"numeric\", month: \"long\" };\n const start = monday.toLocaleDateString(\"es-CL\", opts);\n const end = sunday.toLocaleDateString(\"es-CL\", opts);\n return `${start} – ${end}`;\n}\n\nexport const DAY_NAMES = [\"Lun\", \"Mar\", \"Mié\", \"Jue\", \"Vie\", \"Sáb\", \"Dom\"];\nexport const DAY_NAMES_FULL = [\"Lunes\", \"Martes\", \"Miércoles\", \"Jueves\", \"Viernes\", \"Sábado\", \"Domingo\"];\n\nexport interface ProviderColor {\n bg: string;\n border: string;\n text: string;\n}\n\nexport const DEFAULT_PROVIDER_COLORS: ProviderColor[] = [\n { bg: \"#e8f5f0\", border: \"#2bbf8e\", text: \"#1a7a5a\" },\n { bg: \"#eef0fb\", border: \"#6b7de8\", text: \"#3d4fa8\" },\n { bg: \"#fdf3e8\", border: \"#e8a24b\", text: \"#a0600a\" },\n { bg: \"#fdeef4\", border: \"#e86b9a\", text: \"#a03060\" },\n];\n","import { useEffect, useState } from \"react\";\nimport {\n createBooking,\n getAvailableSlots,\n listLocations,\n listProviders,\n listServices,\n} from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport type {\n ApiConfig,\n BookingRecord,\n ClientFormValues,\n ClientProfile,\n Location,\n Provider,\n Service,\n Slot,\n} from \"../types\";\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClientForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n if (!form.rut.trim()) return \"Por favor ingresa tu RUT.\";\n return null;\n}\n\ninterface BuildBookingPayloadArgs {\n form: ClientFormValues;\n client: ClientProfile | null;\n selectedDate: string;\n selectedSlot: Slot;\n selectedSvc: string;\n selectedLoc: string;\n svcPrice?: string;\n defaultNotes?: string;\n overrides?: SubmitBookingOverrides;\n}\n\nfunction buildBookingPayload(args: BuildBookingPayloadArgs) {\n const { form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc } = args;\n const price = args.overrides?.price ?? args.svcPrice ?? \"0\";\n const notes = args.overrides?.notes ?? args.defaultNotes;\n return {\n start_time: `${selectedDate}T${selectedSlot.start_time}:00-04:00`,\n end_time: `${selectedDate}T${selectedSlot.end_time}:00-04:00`,\n service_id: selectedSvc,\n service_provider_id: selectedSlot.provider_id,\n location_id: selectedLoc,\n price,\n notes,\n // Ignored server-side unless a client/staff auth token proves the caller's\n // identity; for a logged-in client it's redundant but harmless to include.\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nexport interface UseBookingFlowOptions extends ApiConfig {\n onBookingComplete: (booking: BookingRecord) => void;\n /** Default notes attached to every booking (e.g. \"Reserva realizada desde sitio web X\"). */\n defaultNotes?: string;\n}\n\nexport interface SubmitBookingOverrides {\n /** Override the service's list price (e.g. magnolia's price-variant step). */\n price?: string;\n /** Override defaultNotes for this specific submission. */\n notes?: string;\n}\n\n/**\n * Shared booking-flow logic: catalog fetching (locations/services/providers/\n * slots), logged-in-client prefill, form validation, and submit-with-409-\n * handling. Does NOT own step navigation or app-specific filtering (e.g.\n * magnolia's category/price-variant logic) — those stay in the consuming\n * component, layered on top of the `services`/`providers` this hook returns.\n */\nexport function useBookingFlow(opts: UseBookingFlowOptions) {\n const [locations, setLocations] = useState<Location[]>([]);\n const [services, setServices] = useState<Service[]>([]);\n const [providers, setProviders] = useState<Provider[]>([]);\n const [slots, setSlots] = useState<Slot[]>([]);\n\n const [selectedLoc, setSelectedLoc] = useState(\"\");\n const [selectedSvc, setSelectedSvc] = useState(\"\");\n const [selectedProv, setSelectedProv] = useState(\"\");\n const [selectedDate, setSelectedDate] = useState(\"\");\n const [selectedSlot, setSelectedSlot] = useState<Slot | null>(null);\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n // Prefill from a logged-in client session, if any.\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n listLocations(opts)\n .then(setLocations)\n .catch(() => setError(\"Error cargando sucursales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!selectedLoc) return;\n listServices(opts)\n .then(setServices)\n .catch(() => setError(\"Error cargando servicios\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc]);\n\n useEffect(() => {\n if (!selectedSvc) return;\n listProviders(opts)\n .then(setProviders)\n .catch(() => setError(\"Error cargando profesionales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedSvc]);\n\n useEffect(() => {\n if (!selectedLoc || !selectedDate) return;\n setLoading(true);\n getAvailableSlots(opts, {\n locationId: selectedLoc,\n startDate: selectedDate,\n serviceId: selectedSvc || undefined,\n providerId: selectedProv || undefined,\n })\n .then(s => { setSlots(s); setLoading(false); })\n .catch(() => { setError(\"Error cargando horarios\"); setLoading(false); });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc, selectedSvc, selectedProv, selectedDate]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (overrides?: SubmitBookingOverrides) => {\n if (!selectedSlot) return;\n const validationError = validateClientForm(form);\n if (validationError) { setError(validationError); return; }\n\n setLoading(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.id === selectedSvc);\n const token = getClientToken();\n const payload = buildBookingPayload({\n form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc, overrides,\n svcPrice: svc?.price, defaultNotes: opts.defaultNotes,\n });\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar la reserva\");\n setLoading(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(result.message);\n if (result.conflict) setSelectedSlot(null);\n setLoading(false);\n return;\n }\n opts.onBookingComplete(result.booking);\n }\n\n return {\n locations, services, providers, slots,\n selectedLoc, setSelectedLoc,\n selectedSvc, setSelectedSvc,\n selectedProv, setSelectedProv,\n selectedDate, setSelectedDate,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n loading, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { createBooking, getAvailableSlots, listLocations, listServices } from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport { dateStr, DEFAULT_PROVIDER_COLORS, getMondayOf, type ProviderColor } from \"../dateUtils\";\nimport type { ApiConfig, ClientFormValues, ClientProfile, Service, Slot } from \"../types\";\n\nexport interface SelectedClassSlot {\n slot: Slot;\n date: string;\n}\n\nexport interface UseClassScheduleOptions extends ApiConfig {\n onBookingComplete: () => void;\n colors?: ProviderColor[];\n}\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClassForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n return null;\n}\n\nfunction buildClassBookingPayload(\n form: ClientFormValues,\n client: ClientProfile | null,\n selectedSlot: SelectedClassSlot,\n svc: Service | undefined,\n locationId: string\n) {\n return {\n start_time: `${selectedSlot.date}T${selectedSlot.slot.start_time}:00-04:00`,\n end_time: `${selectedSlot.date}T${selectedSlot.slot.end_time}:00-04:00`,\n service_id: svc?.id ?? \"\",\n service_provider_id: selectedSlot.slot.provider_id,\n location_id: locationId,\n price: svc?.price || \"0\",\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nfunction resolveConflictMessage(result: { conflict: boolean; message: string }): string {\n return result.conflict\n ? \"Ese cupo ya fue tomado por otra persona. Cierra esta ventana y elige otro horario.\"\n : result.message;\n}\n\n/**\n * Shared weekly group-class schedule logic: week-of-slots fetching, provider\n * color-palette assignment, and submit-with-409-handling. The week-grid table\n * JSX and modal markup stay in the consuming component — this hook only owns\n * data and state transitions.\n */\nexport function useClassSchedule(opts: UseClassScheduleOptions) {\n const colors = opts.colors ?? DEFAULT_PROVIDER_COLORS;\n\n const [monday, setMonday] = useState<Date>(() => getMondayOf(new Date()));\n const [slotsByDay, setSlotsByDay] = useState<Record<string, Slot[]>>({});\n const [services, setServices] = useState<Service[]>([]);\n const [locationId, setLocationId] = useState(\"\");\n const [loading, setLoading] = useState(true);\n const [selectedSlot, setSelectedSlot] = useState<SelectedClassSlot | null>(null);\n const [providerColorMap, setProviderColorMap] = useState<Record<string, ProviderColor>>({});\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n useEffect(() => {\n Promise.all([listLocations(opts), listServices(opts, 50)])\n .then(([locs, svcs]) => {\n if (locs.length) setLocationId(locs[0].id);\n setServices(svcs);\n })\n .catch(() => setError(\"Error cargando datos\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const loadWeek = useCallback(async (mon: Date, locId: string) => {\n if (!locId) return;\n setLoading(true);\n const days = Array.from({ length: 7 }, (_, i) => {\n const d = new Date(mon);\n d.setDate(mon.getDate() + i);\n return d;\n });\n\n const results = await Promise.all(\n days.map(async d => {\n const ds = dateStr(d);\n try {\n const slots = await getAvailableSlots(opts, { locationId: locId, startDate: ds });\n return { date: ds, slots };\n } catch {\n return { date: ds, slots: [] as Slot[] };\n }\n })\n );\n\n const map: Record<string, Slot[]> = {};\n const colorMap: Record<string, ProviderColor> = {};\n let colorIdx = 0;\n results.forEach(({ date, slots }) => {\n map[date] = slots;\n slots.forEach(s => {\n if (!colorMap[s.provider_id]) {\n colorMap[s.provider_id] = colors[colorIdx % colors.length];\n colorIdx++;\n }\n });\n });\n\n setSlotsByDay(map);\n setProviderColorMap(prev => ({ ...prev, ...colorMap }));\n setLoading(false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (locationId) loadWeek(monday, locationId);\n }, [monday, locationId, loadWeek]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!selectedSlot) return;\n const validationError = validateClassForm(form);\n if (validationError) { setError(validationError); return; }\n setSubmitting(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.name === selectedSlot.slot.service_name);\n const token = getClientToken();\n const payload = buildClassBookingPayload(form, client, selectedSlot, svc, locationId);\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar\");\n setSubmitting(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(resolveConflictMessage(result));\n setSubmitting(false);\n return;\n }\n opts.onBookingComplete();\n }\n\n return {\n monday, setMonday,\n slotsByDay, loading, providerColorMap,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n submitting, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useState } from \"react\";\nimport { loginWithGoogle, sendMagicLink } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\ndeclare global {\n interface Window {\n google?: {\n accounts: {\n id: {\n initialize: (config: { client_id: string; callback: (response: { credential: string }) => void }) => void;\n prompt: () => void;\n };\n };\n };\n }\n}\n\nexport interface UseMagicLinkAuthOptions extends ApiConfig {\n googleClientId?: string;\n frontendUrl: string;\n onGoogleLoggedIn: () => void;\n}\n\nexport type MagicLinkStep = \"email\" | \"sent\";\n\nexport function useMagicLinkAuth(opts: UseMagicLinkAuthOptions) {\n const [email, setEmail] = useState(\"\");\n // Optional — only relevant on a signup-style form (e.g. registro pages)\n // that collects a bit more than login does. Login pages can ignore these.\n const [firstName, setFirstName] = useState(\"\");\n const [lastName, setLastName] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [rut, setRut] = useState(\"\");\n const [step, setStep] = useState<MagicLinkStep>(\"email\");\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const handleMagicLink = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!email.trim() || !/\\S+@\\S+\\.\\S+/.test(email)) {\n setError(\"Ingresa un email válido.\");\n return;\n }\n setLoading(true);\n setError(\"\");\n try {\n await sendMagicLink(opts, email, opts.frontendUrl, {\n firstName: firstName || undefined,\n lastName: lastName || undefined,\n phone: phone || undefined,\n rut: rut || undefined,\n });\n setStep(\"sent\");\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error enviando el link.\");\n } finally {\n setLoading(false);\n }\n };\n\n const handleGoogle = () => {\n if (!opts.googleClientId || typeof window === \"undefined\" || !window.google) return;\n window.google.accounts.id.initialize({\n client_id: opts.googleClientId,\n callback: async (response: { credential: string }) => {\n setLoading(true);\n try {\n const data = await loginWithGoogle(opts, response.credential);\n setClientToken(data.access_token);\n opts.onGoogleLoggedIn();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error con Google.\");\n setLoading(false);\n }\n },\n });\n window.google.accounts.id.prompt();\n };\n\n const reset = () => {\n setStep(\"email\");\n setError(\"\");\n };\n\n return {\n email, setEmail,\n firstName, setFirstName,\n lastName, setLastName,\n phone, setPhone,\n rut, setRut,\n step, error, loading, handleMagicLink, handleGoogle, reset,\n };\n}\n","import { useState } from \"react\";\nimport { register } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\nexport interface RegisterFormValues {\n firstName: string;\n lastName: string;\n email: string;\n phone: string;\n password: string;\n confirm: string;\n}\n\nconst EMPTY: RegisterFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", password: \"\", confirm: \"\" };\n\nexport interface UseRegisterFormOptions extends ApiConfig {\n onRegistered: () => void;\n}\n\nexport function useRegisterForm(opts: UseRegisterFormOptions) {\n const [form, setForm] = useState<RegisterFormValues>(EMPTY);\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const updateField = (fields: Partial<RegisterFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const handleSubmit = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!form.firstName.trim()) { setError(\"Ingresa tu nombre.\"); return; }\n if (!form.lastName.trim()) { setError(\"Ingresa tu apellido.\"); return; }\n if (!form.email.trim()) { setError(\"Ingresa tu email.\"); return; }\n if (form.password.length < 6) { setError(\"La contraseña debe tener al menos 6 caracteres.\"); return; }\n if (form.password !== form.confirm) { setError(\"Las contraseñas no coinciden.\"); return; }\n setLoading(true);\n setError(\"\");\n try {\n const data = await register(opts, form);\n setClientToken(data.access_token);\n opts.onRegistered();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al registrarse.\");\n } finally {\n setLoading(false);\n }\n };\n\n return { form, updateField, error, loading, handleSubmit };\n}\n","import { useEffect, useState } from \"react\";\nimport { cancelMyBooking, getMe, getMyBookings, getMyPackages, rescheduleMyBooking } from \"../api\";\nimport { clearClientToken, getClientToken } from \"../clientAuth\";\nimport type { BookingRecord, ClientProfile, PackageRecord } from \"../types\";\n\nexport interface UseClientAccountOptions {\n apiBase: string;\n onUnauthenticated: () => void;\n onLoggedOut: () => void;\n}\n\nexport function useClientAccount(opts: UseClientAccountOptions) {\n const [profile, setProfile] = useState<ClientProfile | null>(null);\n const [upcoming, setUpcoming] = useState<BookingRecord[]>([]);\n const [history, setHistory] = useState<BookingRecord[]>([]);\n const [packages, setPackages] = useState<PackageRecord[]>([]);\n const [loading, setLoading] = useState(true);\n const [actionError, setActionError] = useState(\"\");\n const [actionLoading, setActionLoading] = useState(false);\n\n const loadAll = () => {\n const token = getClientToken();\n if (!token) {\n opts.onUnauthenticated();\n return;\n }\n Promise.all([\n getMe(opts.apiBase, token),\n getMyBookings(opts.apiBase, token, { upcoming: true, perPage: 10 }),\n getMyBookings(opts.apiBase, token, { perPage: 20 }),\n getMyPackages(opts.apiBase, token),\n ])\n .then(([prof, up, hist, pkgs]) => {\n setProfile(prof);\n setUpcoming(up);\n setHistory(hist);\n setPackages(pkgs);\n setLoading(false);\n })\n .catch(() => opts.onUnauthenticated());\n };\n\n useEffect(() => {\n loadAll();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const handleLogout = () => {\n clearClientToken();\n opts.onLoggedOut();\n };\n\n const cancelBooking = async (bookingId: string) => {\n const token = getClientToken();\n if (!token) return;\n setActionLoading(true);\n setActionError(\"\");\n const result = await cancelMyBooking(opts.apiBase, token, bookingId);\n if (!result.ok) {\n setActionError(result.message);\n setActionLoading(false);\n return;\n }\n loadAll();\n setActionLoading(false);\n };\n\n const rescheduleBooking = async (bookingId: string, startTime: string, endTime: string) => {\n const token = getClientToken();\n if (!token) return false;\n setActionLoading(true);\n setActionError(\"\");\n const result = await rescheduleMyBooking(opts.apiBase, token, bookingId, startTime, endTime);\n setActionLoading(false);\n if (!result.ok) {\n setActionError(result.message);\n return false;\n }\n loadAll();\n return true;\n };\n\n const totalCredits = packages.reduce((s, p) => s + p.remaining_credits, 0);\n\n return {\n profile, upcoming, history, packages, loading, totalCredits, handleLogout,\n cancelBooking, rescheduleBooking, actionError, setActionError, actionLoading,\n };\n}\n"],"mappings":"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","names":["useEffect","useState","EMPTY_FORM","isValidPhone","useState","useEffect","useState","useState","useState","useState","useEffect","useState","useState","useEffect"]}
1
+ {"version":3,"sources":["../src/api.ts","../src/clientAuth.ts","../src/dateUtils.ts","../src/hooks/useBookingFlow.ts","../src/hooks/useClassSchedule.ts","../src/hooks/useMagicLinkAuth.ts","../src/hooks/useRegisterForm.ts","../src/hooks/useClientAccount.ts"],"sourcesContent":["import type {\n ApiConfig,\n BookingCreateInput,\n BookingRecord,\n BookingResult,\n ClientFormValues,\n ClientProfile,\n Location,\n PackageRecord,\n Provider,\n Service,\n Slot,\n WaitlistEntry,\n} from \"./types\";\n\nfunction headers(cfg: ApiConfig, withJson = false): Record<string, string> {\n const h: Record<string, string> = { \"X-API-Key\": cfg.apiKey };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nfunction authHeaders(token: string, withJson = false): Record<string, string> {\n const h: Record<string, string> = { Authorization: `Bearer ${token}` };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nexport async function listLocations(cfg: ApiConfig): Promise<Location[]> {\n const res = await fetch(`${cfg.apiBase}/v1/locations`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listServices(cfg: ApiConfig, perPage = 100): Promise<Service[]> {\n const res = await fetch(`${cfg.apiBase}/v1/services?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listProviders(cfg: ApiConfig, perPage = 100): Promise<Provider[]> {\n const res = await fetch(`${cfg.apiBase}/v1/providers?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getAvailableSlots(\n cfg: ApiConfig,\n params: { locationId: string; startDate: string; serviceId?: string; providerId?: string }\n): Promise<Slot[]> {\n const q = new URLSearchParams({ location_id: params.locationId, start_date: params.startDate });\n if (params.serviceId) q.set(\"service_id\", params.serviceId);\n if (params.providerId) q.set(\"provider_id\", params.providerId);\n const res = await fetch(`${cfg.apiBase}/v1/available-slots?${q.toString()}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data?.slots || [];\n}\n\nexport async function createClient(cfg: ApiConfig, form: ClientFormValues): Promise<{ id: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/clients`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone,\n rut: form.rut || undefined,\n }),\n });\n if (!res.ok) throw new Error(\"Error registrando datos\");\n return res.json();\n}\n\nexport async function createBooking(\n cfg: ApiConfig,\n input: BookingCreateInput,\n clientToken?: string\n): Promise<BookingResult> {\n // A logged-in client's token takes priority so the server attributes the\n // booking to their account rather than treating it as anonymous — see\n // create_booking in routes/bookings.py, which ignores any client_id sent\n // by an unauthenticated caller.\n const reqHeaders = headers(cfg, true);\n if (clientToken) reqHeaders.Authorization = `Bearer ${clientToken}`;\n const res = await fetch(`${cfg.apiBase}/v1/bookings`, {\n method: \"POST\",\n headers: reqHeaders,\n body: JSON.stringify(input),\n });\n if (res.status === 409) {\n const data = await res.json().catch(() => ({}));\n return { ok: false, conflict: true, message: data.detail || \"Ese horario ya no está disponible.\" };\n }\n if (!res.ok) {\n return { ok: false, conflict: false, message: \"Error creando la reserva. Por favor intenta nuevamente.\" };\n }\n return { ok: true, booking: await res.json() };\n}\n\nexport async function sendMagicLink(\n cfg: ApiConfig,\n email: string,\n frontendUrl: string,\n profile?: { firstName?: string; lastName?: string; phone?: string; rut?: string }\n): Promise<void> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n email: email.trim().toLowerCase(),\n frontend_url: frontendUrl,\n first_name: profile?.firstName,\n last_name: profile?.lastName,\n phone: profile?.phone,\n rut: profile?.rut,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error enviando el link.\");\n}\n\nexport async function verifyMagicLink(cfg: ApiConfig, token: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link/verify`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ token }),\n });\n const data = await res.json();\n if (!data.access_token) throw new Error(data.detail || \"Link inválido.\");\n return data;\n}\n\nexport async function loginWithGoogle(cfg: ApiConfig, credential: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/google`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ credential }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error con Google.\");\n return data;\n}\n\nexport async function register(\n cfg: ApiConfig,\n form: { firstName: string; lastName: string; email: string; phone?: string; password: string }\n): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/register`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone || undefined,\n password: form.password,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error al registrarse.\");\n return data;\n}\n\nexport async function getMe(apiBase: string, token: string): Promise<ClientProfile> {\n const res = await fetch(`${apiBase}/v1/me`, { headers: authHeaders(token) });\n return res.json();\n}\n\nexport async function getMyBookings(\n apiBase: string,\n token: string,\n params?: { upcoming?: boolean; perPage?: number }\n): Promise<BookingRecord[]> {\n const q = new URLSearchParams();\n if (params?.upcoming) q.set(\"upcoming\", \"true\");\n q.set(\"per_page\", String(params?.perPage ?? 20));\n const res = await fetch(`${apiBase}/v1/me/bookings?${q.toString()}`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getMyPackages(apiBase: string, token: string): Promise<PackageRecord[]> {\n const res = await fetch(`${apiBase}/v1/me/packages`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\n/** Result of a client cancelling/rescheduling their own booking — callers\n * branch on `.ok` to show the server's specific reason (cutoff window,\n * overlap, etc.) instead of a generic error. */\nexport type MyBookingActionResult =\n | { ok: true; booking: BookingRecord }\n | { ok: false; message: string };\n\nexport async function cancelMyBooking(\n apiBase: string, token: string, bookingId: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/cancel`, {\n method: \"POST\",\n headers: authHeaders(token),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo cancelar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function rescheduleMyBooking(\n apiBase: string, token: string, bookingId: string, startTime: string, endTime: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/reschedule`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({ start_time: startTime, end_time: endTime }),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo reprogramar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function joinWaitlist(\n apiBase: string,\n token: string,\n params: {\n serviceId: string;\n locationId: string;\n providerId?: string;\n date?: string;\n dateUntil?: string;\n classSessionId?: string;\n }\n): Promise<WaitlistEntry> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({\n service_id: params.serviceId,\n location_id: params.locationId,\n provider_id: params.providerId,\n date: params.date,\n date_until: params.dateUntil,\n class_session_id: params.classSessionId,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"No se pudo unir a la lista de espera.\");\n return data;\n}\n\nexport async function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void> {\n await fetch(`${apiBase}/v1/me/waitlist/${entryId}`, {\n method: \"DELETE\",\n headers: authHeaders(token),\n });\n}\n\nexport async function confirmWaitlistOffer(cfg: ApiConfig, token: string): Promise<WaitlistEntry> {\n const res = await fetch(`${cfg.apiBase}/v1/waitlist/confirm/${token}`, {\n method: \"POST\",\n headers: headers(cfg),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"No se pudo confirmar el cupo.\");\n return data;\n}\n","import { getMe } from \"./api\";\nimport type { ClientProfile } from \"./types\";\n\nconst TOKEN_KEY = \"client_token\";\n\nexport function getClientToken(): string | null {\n if (typeof window === \"undefined\") return null;\n return localStorage.getItem(TOKEN_KEY);\n}\n\nexport function setClientToken(token: string): void {\n if (typeof window === \"undefined\") return;\n localStorage.setItem(TOKEN_KEY, token);\n}\n\nexport function clearClientToken(): void {\n if (typeof window === \"undefined\") return;\n localStorage.removeItem(TOKEN_KEY);\n}\n\nexport async function fetchMe(apiBase: string, token: string): Promise<ClientProfile | null> {\n try {\n return await getMe(apiBase, token);\n } catch {\n return null;\n }\n}\n","export function getMondayOf(date: Date): Date {\n const d = new Date(date);\n const day = (d.getDay() + 6) % 7;\n d.setDate(d.getDate() - day);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\nexport function dateStr(d: Date): string {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`;\n}\n\nexport function formatMonthRange(monday: Date): string {\n const sunday = new Date(monday);\n sunday.setDate(monday.getDate() + 6);\n const opts: Intl.DateTimeFormatOptions = { day: \"numeric\", month: \"long\" };\n const start = monday.toLocaleDateString(\"es-CL\", opts);\n const end = sunday.toLocaleDateString(\"es-CL\", opts);\n return `${start} – ${end}`;\n}\n\nexport const DAY_NAMES = [\"Lun\", \"Mar\", \"Mié\", \"Jue\", \"Vie\", \"Sáb\", \"Dom\"];\nexport const DAY_NAMES_FULL = [\"Lunes\", \"Martes\", \"Miércoles\", \"Jueves\", \"Viernes\", \"Sábado\", \"Domingo\"];\n\nexport interface ProviderColor {\n bg: string;\n border: string;\n text: string;\n}\n\nexport const DEFAULT_PROVIDER_COLORS: ProviderColor[] = [\n { bg: \"#e8f5f0\", border: \"#2bbf8e\", text: \"#1a7a5a\" },\n { bg: \"#eef0fb\", border: \"#6b7de8\", text: \"#3d4fa8\" },\n { bg: \"#fdf3e8\", border: \"#e8a24b\", text: \"#a0600a\" },\n { bg: \"#fdeef4\", border: \"#e86b9a\", text: \"#a03060\" },\n];\n","import { useEffect, useState } from \"react\";\nimport {\n createBooking,\n getAvailableSlots,\n listLocations,\n listProviders,\n listServices,\n} from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport type {\n ApiConfig,\n BookingRecord,\n ClientFormValues,\n ClientProfile,\n Location,\n Provider,\n Service,\n Slot,\n} from \"../types\";\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClientForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n if (!form.rut.trim()) return \"Por favor ingresa tu RUT.\";\n return null;\n}\n\ninterface BuildBookingPayloadArgs {\n form: ClientFormValues;\n client: ClientProfile | null;\n selectedDate: string;\n selectedSlot: Slot;\n selectedSvc: string;\n selectedLoc: string;\n svcPrice?: string;\n defaultNotes?: string;\n overrides?: SubmitBookingOverrides;\n}\n\nfunction buildBookingPayload(args: BuildBookingPayloadArgs) {\n const { form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc } = args;\n const price = args.overrides?.price ?? args.svcPrice ?? \"0\";\n const notes = args.overrides?.notes ?? args.defaultNotes;\n return {\n start_time: `${selectedDate}T${selectedSlot.start_time}:00-04:00`,\n end_time: `${selectedDate}T${selectedSlot.end_time}:00-04:00`,\n service_id: selectedSvc,\n service_provider_id: selectedSlot.provider_id,\n location_id: selectedLoc,\n price,\n notes,\n // Ignored server-side unless a client/staff auth token proves the caller's\n // identity; for a logged-in client it's redundant but harmless to include.\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nexport interface UseBookingFlowOptions extends ApiConfig {\n onBookingComplete: (booking: BookingRecord) => void;\n /** Default notes attached to every booking (e.g. \"Reserva realizada desde sitio web X\"). */\n defaultNotes?: string;\n}\n\nexport interface SubmitBookingOverrides {\n /** Override the service's list price (e.g. magnolia's price-variant step). */\n price?: string;\n /** Override defaultNotes for this specific submission. */\n notes?: string;\n}\n\n/**\n * Shared booking-flow logic: catalog fetching (locations/services/providers/\n * slots), logged-in-client prefill, form validation, and submit-with-409-\n * handling. Does NOT own step navigation or app-specific filtering (e.g.\n * magnolia's category/price-variant logic) — those stay in the consuming\n * component, layered on top of the `services`/`providers` this hook returns.\n */\nexport function useBookingFlow(opts: UseBookingFlowOptions) {\n const [locations, setLocations] = useState<Location[]>([]);\n const [services, setServices] = useState<Service[]>([]);\n const [providers, setProviders] = useState<Provider[]>([]);\n const [slots, setSlots] = useState<Slot[]>([]);\n\n const [selectedLoc, setSelectedLoc] = useState(\"\");\n const [selectedSvc, setSelectedSvc] = useState(\"\");\n const [selectedProv, setSelectedProv] = useState(\"\");\n const [selectedDate, setSelectedDate] = useState(\"\");\n const [selectedSlot, setSelectedSlot] = useState<Slot | null>(null);\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n // Prefill from a logged-in client session, if any.\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n listLocations(opts)\n .then(setLocations)\n .catch(() => setError(\"Error cargando sucursales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!selectedLoc) return;\n listServices(opts)\n .then(setServices)\n .catch(() => setError(\"Error cargando servicios\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc]);\n\n useEffect(() => {\n if (!selectedSvc) return;\n listProviders(opts)\n .then(setProviders)\n .catch(() => setError(\"Error cargando profesionales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedSvc]);\n\n useEffect(() => {\n if (!selectedLoc || !selectedDate) return;\n setLoading(true);\n getAvailableSlots(opts, {\n locationId: selectedLoc,\n startDate: selectedDate,\n serviceId: selectedSvc || undefined,\n providerId: selectedProv || undefined,\n })\n .then(s => { setSlots(s); setLoading(false); })\n .catch(() => { setError(\"Error cargando horarios\"); setLoading(false); });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc, selectedSvc, selectedProv, selectedDate]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (overrides?: SubmitBookingOverrides) => {\n if (!selectedSlot) return;\n const validationError = validateClientForm(form);\n if (validationError) { setError(validationError); return; }\n\n setLoading(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.id === selectedSvc);\n const token = getClientToken();\n const payload = buildBookingPayload({\n form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc, overrides,\n svcPrice: svc?.price, defaultNotes: opts.defaultNotes,\n });\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar la reserva\");\n setLoading(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(result.message);\n if (result.conflict) setSelectedSlot(null);\n setLoading(false);\n return;\n }\n opts.onBookingComplete(result.booking);\n }\n\n return {\n locations, services, providers, slots,\n selectedLoc, setSelectedLoc,\n selectedSvc, setSelectedSvc,\n selectedProv, setSelectedProv,\n selectedDate, setSelectedDate,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n loading, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { createBooking, getAvailableSlots, listLocations, listServices } from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport { dateStr, DEFAULT_PROVIDER_COLORS, getMondayOf, type ProviderColor } from \"../dateUtils\";\nimport type { ApiConfig, ClientFormValues, ClientProfile, Service, Slot } from \"../types\";\n\nexport interface SelectedClassSlot {\n slot: Slot;\n date: string;\n}\n\nexport interface UseClassScheduleOptions extends ApiConfig {\n onBookingComplete: () => void;\n colors?: ProviderColor[];\n}\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClassForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n return null;\n}\n\nfunction buildClassBookingPayload(\n form: ClientFormValues,\n client: ClientProfile | null,\n selectedSlot: SelectedClassSlot,\n svc: Service | undefined,\n locationId: string\n) {\n return {\n start_time: `${selectedSlot.date}T${selectedSlot.slot.start_time}:00-04:00`,\n end_time: `${selectedSlot.date}T${selectedSlot.slot.end_time}:00-04:00`,\n service_id: svc?.id ?? \"\",\n service_provider_id: selectedSlot.slot.provider_id,\n location_id: locationId,\n price: svc?.price || \"0\",\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nfunction resolveConflictMessage(result: { conflict: boolean; message: string }): string {\n return result.conflict\n ? \"Ese cupo ya fue tomado por otra persona. Cierra esta ventana y elige otro horario.\"\n : result.message;\n}\n\n/**\n * Shared weekly group-class schedule logic: week-of-slots fetching, provider\n * color-palette assignment, and submit-with-409-handling. The week-grid table\n * JSX and modal markup stay in the consuming component — this hook only owns\n * data and state transitions.\n */\nexport function useClassSchedule(opts: UseClassScheduleOptions) {\n const colors = opts.colors ?? DEFAULT_PROVIDER_COLORS;\n\n const [monday, setMonday] = useState<Date>(() => getMondayOf(new Date()));\n const [slotsByDay, setSlotsByDay] = useState<Record<string, Slot[]>>({});\n const [services, setServices] = useState<Service[]>([]);\n const [locationId, setLocationId] = useState(\"\");\n const [loading, setLoading] = useState(true);\n const [selectedSlot, setSelectedSlot] = useState<SelectedClassSlot | null>(null);\n const [providerColorMap, setProviderColorMap] = useState<Record<string, ProviderColor>>({});\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n useEffect(() => {\n Promise.all([listLocations(opts), listServices(opts, 50)])\n .then(([locs, svcs]) => {\n if (locs.length) setLocationId(locs[0].id);\n setServices(svcs);\n })\n .catch(() => setError(\"Error cargando datos\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const loadWeek = useCallback(async (mon: Date, locId: string) => {\n if (!locId) return;\n setLoading(true);\n const days = Array.from({ length: 7 }, (_, i) => {\n const d = new Date(mon);\n d.setDate(mon.getDate() + i);\n return d;\n });\n\n const results = await Promise.all(\n days.map(async d => {\n const ds = dateStr(d);\n try {\n const slots = await getAvailableSlots(opts, { locationId: locId, startDate: ds });\n return { date: ds, slots };\n } catch {\n return { date: ds, slots: [] as Slot[] };\n }\n })\n );\n\n const map: Record<string, Slot[]> = {};\n const colorMap: Record<string, ProviderColor> = {};\n let colorIdx = 0;\n results.forEach(({ date, slots }) => {\n map[date] = slots;\n slots.forEach(s => {\n if (!colorMap[s.provider_id]) {\n colorMap[s.provider_id] = colors[colorIdx % colors.length];\n colorIdx++;\n }\n });\n });\n\n setSlotsByDay(map);\n setProviderColorMap(prev => ({ ...prev, ...colorMap }));\n setLoading(false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (locationId) loadWeek(monday, locationId);\n }, [monday, locationId, loadWeek]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!selectedSlot) return;\n const validationError = validateClassForm(form);\n if (validationError) { setError(validationError); return; }\n setSubmitting(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.name === selectedSlot.slot.service_name);\n const token = getClientToken();\n const payload = buildClassBookingPayload(form, client, selectedSlot, svc, locationId);\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar\");\n setSubmitting(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(resolveConflictMessage(result));\n setSubmitting(false);\n return;\n }\n opts.onBookingComplete();\n }\n\n return {\n monday, setMonday,\n slotsByDay, loading, providerColorMap,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n submitting, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useState } from \"react\";\nimport { loginWithGoogle, sendMagicLink } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\ndeclare global {\n interface Window {\n google?: {\n accounts: {\n id: {\n initialize: (config: { client_id: string; callback: (response: { credential: string }) => void }) => void;\n prompt: () => void;\n };\n };\n };\n }\n}\n\nexport interface UseMagicLinkAuthOptions extends ApiConfig {\n googleClientId?: string;\n frontendUrl: string;\n onGoogleLoggedIn: () => void;\n}\n\nexport type MagicLinkStep = \"email\" | \"sent\";\n\nexport function useMagicLinkAuth(opts: UseMagicLinkAuthOptions) {\n const [email, setEmail] = useState(\"\");\n // Optional — only relevant on a signup-style form (e.g. registro pages)\n // that collects a bit more than login does. Login pages can ignore these.\n const [firstName, setFirstName] = useState(\"\");\n const [lastName, setLastName] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [rut, setRut] = useState(\"\");\n const [step, setStep] = useState<MagicLinkStep>(\"email\");\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const handleMagicLink = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!email.trim() || !/\\S+@\\S+\\.\\S+/.test(email)) {\n setError(\"Ingresa un email válido.\");\n return;\n }\n setLoading(true);\n setError(\"\");\n try {\n await sendMagicLink(opts, email, opts.frontendUrl, {\n firstName: firstName || undefined,\n lastName: lastName || undefined,\n phone: phone || undefined,\n rut: rut || undefined,\n });\n setStep(\"sent\");\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error enviando el link.\");\n } finally {\n setLoading(false);\n }\n };\n\n const handleGoogle = () => {\n if (!opts.googleClientId || typeof window === \"undefined\" || !window.google) return;\n window.google.accounts.id.initialize({\n client_id: opts.googleClientId,\n callback: async (response: { credential: string }) => {\n setLoading(true);\n try {\n const data = await loginWithGoogle(opts, response.credential);\n setClientToken(data.access_token);\n opts.onGoogleLoggedIn();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error con Google.\");\n setLoading(false);\n }\n },\n });\n window.google.accounts.id.prompt();\n };\n\n const reset = () => {\n setStep(\"email\");\n setError(\"\");\n };\n\n return {\n email, setEmail,\n firstName, setFirstName,\n lastName, setLastName,\n phone, setPhone,\n rut, setRut,\n step, error, loading, handleMagicLink, handleGoogle, reset,\n };\n}\n","import { useState } from \"react\";\nimport { register } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\nexport interface RegisterFormValues {\n firstName: string;\n lastName: string;\n email: string;\n phone: string;\n password: string;\n confirm: string;\n}\n\nconst EMPTY: RegisterFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", password: \"\", confirm: \"\" };\n\nexport interface UseRegisterFormOptions extends ApiConfig {\n onRegistered: () => void;\n}\n\nexport function useRegisterForm(opts: UseRegisterFormOptions) {\n const [form, setForm] = useState<RegisterFormValues>(EMPTY);\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const updateField = (fields: Partial<RegisterFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const handleSubmit = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!form.firstName.trim()) { setError(\"Ingresa tu nombre.\"); return; }\n if (!form.lastName.trim()) { setError(\"Ingresa tu apellido.\"); return; }\n if (!form.email.trim()) { setError(\"Ingresa tu email.\"); return; }\n if (form.password.length < 6) { setError(\"La contraseña debe tener al menos 6 caracteres.\"); return; }\n if (form.password !== form.confirm) { setError(\"Las contraseñas no coinciden.\"); return; }\n setLoading(true);\n setError(\"\");\n try {\n const data = await register(opts, form);\n setClientToken(data.access_token);\n opts.onRegistered();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al registrarse.\");\n } finally {\n setLoading(false);\n }\n };\n\n return { form, updateField, error, loading, handleSubmit };\n}\n","import { useEffect, useState } from \"react\";\nimport { cancelMyBooking, getMe, getMyBookings, getMyPackages, rescheduleMyBooking } from \"../api\";\nimport { clearClientToken, getClientToken } from \"../clientAuth\";\nimport type { BookingRecord, ClientProfile, PackageRecord } from \"../types\";\n\nexport interface UseClientAccountOptions {\n apiBase: string;\n onUnauthenticated: () => void;\n onLoggedOut: () => void;\n}\n\nexport function useClientAccount(opts: UseClientAccountOptions) {\n const [profile, setProfile] = useState<ClientProfile | null>(null);\n const [upcoming, setUpcoming] = useState<BookingRecord[]>([]);\n const [history, setHistory] = useState<BookingRecord[]>([]);\n const [packages, setPackages] = useState<PackageRecord[]>([]);\n const [loading, setLoading] = useState(true);\n const [actionError, setActionError] = useState(\"\");\n const [actionLoading, setActionLoading] = useState(false);\n\n const loadAll = () => {\n const token = getClientToken();\n if (!token) {\n opts.onUnauthenticated();\n return;\n }\n Promise.all([\n getMe(opts.apiBase, token),\n getMyBookings(opts.apiBase, token, { upcoming: true, perPage: 10 }),\n getMyBookings(opts.apiBase, token, { perPage: 20 }),\n getMyPackages(opts.apiBase, token),\n ])\n .then(([prof, up, hist, pkgs]) => {\n setProfile(prof);\n setUpcoming(up);\n setHistory(hist);\n setPackages(pkgs);\n setLoading(false);\n })\n .catch(() => opts.onUnauthenticated());\n };\n\n useEffect(() => {\n loadAll();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const handleLogout = () => {\n clearClientToken();\n opts.onLoggedOut();\n };\n\n const cancelBooking = async (bookingId: string) => {\n const token = getClientToken();\n if (!token) return;\n setActionLoading(true);\n setActionError(\"\");\n const result = await cancelMyBooking(opts.apiBase, token, bookingId);\n if (!result.ok) {\n setActionError(result.message);\n setActionLoading(false);\n return;\n }\n loadAll();\n setActionLoading(false);\n };\n\n const rescheduleBooking = async (bookingId: string, startTime: string, endTime: string) => {\n const token = getClientToken();\n if (!token) return false;\n setActionLoading(true);\n setActionError(\"\");\n const result = await rescheduleMyBooking(opts.apiBase, token, bookingId, startTime, endTime);\n setActionLoading(false);\n if (!result.ok) {\n setActionError(result.message);\n return false;\n }\n loadAll();\n return true;\n };\n\n const totalCredits = packages.reduce((s, p) => s + p.remaining_credits, 0);\n\n return {\n profile, upcoming, history, packages, loading, totalCredits, handleLogout,\n cancelBooking, rescheduleBooking, actionError, setActionError, actionLoading,\n };\n}\n"],"mappings":"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","names":["useEffect","useState","EMPTY_FORM","isValidPhone","useState","useEffect","useState","useState","useState","useState","useEffect","useState","useState","useEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bookr-cl/widget",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Shared booking-flow logic (API client, auth, hooks) for Bookr client widgets.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",