@bookr-cl/widget 0.2.0 → 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,
@@ -238,6 +239,15 @@ async function leaveWaitlist(apiBase, token, entryId) {
238
239
  headers: authHeaders(token)
239
240
  });
240
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
+ }
241
251
 
242
252
  // src/clientAuth.ts
243
253
  var TOKEN_KEY = "client_token";
@@ -807,6 +817,7 @@ function useClientAccount(opts) {
807
817
  DEFAULT_PROVIDER_COLORS,
808
818
  cancelMyBooking,
809
819
  clearClientToken,
820
+ confirmWaitlistOffer,
810
821
  createBooking,
811
822
  createClient,
812
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: {\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","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
@@ -46,6 +46,9 @@ interface WaitlistEntry {
46
46
  status: "waiting" | "offered" | "confirmed" | "expired";
47
47
  notified_at: string | null;
48
48
  offer_expires_at: string | null;
49
+ offered_start_time: string | null;
50
+ offered_end_time: string | null;
51
+ booking_id: string | null;
49
52
  created_at: string;
50
53
  }
51
54
  interface ClientProfile {
@@ -180,6 +183,7 @@ declare function joinWaitlist(apiBase: string, token: string, params: {
180
183
  }): Promise<WaitlistEntry>;
181
184
  declare function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]>;
182
185
  declare function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void>;
186
+ declare function confirmWaitlistOffer(cfg: ApiConfig, token: string): Promise<WaitlistEntry>;
183
187
 
184
188
  declare function getClientToken(): string | null;
185
189
  declare function setClientToken(token: string): void;
@@ -358,4 +362,4 @@ declare function useClientAccount(opts: UseClientAccountOptions): {
358
362
  actionLoading: boolean;
359
363
  };
360
364
 
361
- 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
@@ -46,6 +46,9 @@ interface WaitlistEntry {
46
46
  status: "waiting" | "offered" | "confirmed" | "expired";
47
47
  notified_at: string | null;
48
48
  offer_expires_at: string | null;
49
+ offered_start_time: string | null;
50
+ offered_end_time: string | null;
51
+ booking_id: string | null;
49
52
  created_at: string;
50
53
  }
51
54
  interface ClientProfile {
@@ -180,6 +183,7 @@ declare function joinWaitlist(apiBase: string, token: string, params: {
180
183
  }): Promise<WaitlistEntry>;
181
184
  declare function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]>;
182
185
  declare function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void>;
186
+ declare function confirmWaitlistOffer(cfg: ApiConfig, token: string): Promise<WaitlistEntry>;
183
187
 
184
188
  declare function getClientToken(): string | null;
185
189
  declare function setClientToken(token: string): void;
@@ -358,4 +362,4 @@ declare function useClientAccount(opts: UseClientAccountOptions): {
358
362
  actionLoading: boolean;
359
363
  };
360
364
 
361
- 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
@@ -180,6 +180,15 @@ async function leaveWaitlist(apiBase, token, entryId) {
180
180
  headers: authHeaders(token)
181
181
  });
182
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
+ }
183
192
 
184
193
  // src/clientAuth.ts
185
194
  var TOKEN_KEY = "client_token";
@@ -748,6 +757,7 @@ export {
748
757
  DEFAULT_PROVIDER_COLORS,
749
758
  cancelMyBooking,
750
759
  clearClientToken,
760
+ confirmWaitlistOffer,
751
761
  createBooking,
752
762
  createClient,
753
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: {\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","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.2.0",
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",