@bookr-cl/widget 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/api.ts","../src/clientAuth.ts","../src/dateUtils.ts","../src/hooks/useBookingFlow.ts","../src/hooks/useClassSchedule.ts","../src/hooks/useMagicLinkAuth.ts","../src/hooks/useRegisterForm.ts","../src/hooks/useClientAccount.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./api\";\nexport * from \"./clientAuth\";\nexport * from \"./dateUtils\";\nexport * from \"./hooks/useBookingFlow\";\nexport * from \"./hooks/useClassSchedule\";\nexport * from \"./hooks/useMagicLinkAuth\";\nexport * from \"./hooks/useRegisterForm\";\nexport * from \"./hooks/useClientAccount\";\n","import type {\n ApiConfig,\n BookingCreateInput,\n BookingRecord,\n BookingResult,\n ClientFormValues,\n ClientProfile,\n Location,\n PackageRecord,\n Provider,\n Service,\n Slot,\n WaitlistEntry,\n} from \"./types\";\n\nfunction headers(cfg: ApiConfig, withJson = false): Record<string, string> {\n const h: Record<string, string> = { \"X-API-Key\": cfg.apiKey };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nfunction authHeaders(token: string, withJson = false): Record<string, string> {\n const h: Record<string, string> = { Authorization: `Bearer ${token}` };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nexport async function listLocations(cfg: ApiConfig): Promise<Location[]> {\n const res = await fetch(`${cfg.apiBase}/v1/locations`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listServices(cfg: ApiConfig, perPage = 100): Promise<Service[]> {\n const res = await fetch(`${cfg.apiBase}/v1/services?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listProviders(cfg: ApiConfig, perPage = 100): Promise<Provider[]> {\n const res = await fetch(`${cfg.apiBase}/v1/providers?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getAvailableSlots(\n cfg: ApiConfig,\n params: { locationId: string; startDate: string; serviceId?: string; providerId?: string }\n): Promise<Slot[]> {\n const q = new URLSearchParams({ location_id: params.locationId, start_date: params.startDate });\n if (params.serviceId) q.set(\"service_id\", params.serviceId);\n if (params.providerId) q.set(\"provider_id\", params.providerId);\n const res = await fetch(`${cfg.apiBase}/v1/available-slots?${q.toString()}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data?.slots || [];\n}\n\nexport async function createClient(cfg: ApiConfig, form: ClientFormValues): Promise<{ id: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/clients`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone,\n rut: form.rut || undefined,\n }),\n });\n if (!res.ok) throw new Error(\"Error registrando datos\");\n return res.json();\n}\n\nexport async function createBooking(\n cfg: ApiConfig,\n input: BookingCreateInput,\n clientToken?: string\n): Promise<BookingResult> {\n // A logged-in client's token takes priority so the server attributes the\n // booking to their account rather than treating it as anonymous — see\n // create_booking in routes/bookings.py, which ignores any client_id sent\n // by an unauthenticated caller.\n const reqHeaders = headers(cfg, true);\n if (clientToken) reqHeaders.Authorization = `Bearer ${clientToken}`;\n const res = await fetch(`${cfg.apiBase}/v1/bookings`, {\n method: \"POST\",\n headers: reqHeaders,\n body: JSON.stringify(input),\n });\n if (res.status === 409) {\n const data = await res.json().catch(() => ({}));\n return { ok: false, conflict: true, message: data.detail || \"Ese horario ya no está disponible.\" };\n }\n if (!res.ok) {\n return { ok: false, conflict: false, message: \"Error creando la reserva. Por favor intenta nuevamente.\" };\n }\n return { ok: true, booking: await res.json() };\n}\n\nexport async function sendMagicLink(\n cfg: ApiConfig,\n email: string,\n frontendUrl: string,\n profile?: { firstName?: string; lastName?: string; phone?: string; rut?: string }\n): Promise<void> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n email: email.trim().toLowerCase(),\n frontend_url: frontendUrl,\n first_name: profile?.firstName,\n last_name: profile?.lastName,\n phone: profile?.phone,\n rut: profile?.rut,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error enviando el link.\");\n}\n\nexport async function verifyMagicLink(cfg: ApiConfig, token: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link/verify`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ token }),\n });\n const data = await res.json();\n if (!data.access_token) throw new Error(data.detail || \"Link inválido.\");\n return data;\n}\n\nexport async function loginWithGoogle(cfg: ApiConfig, credential: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/google`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ credential }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error con Google.\");\n return data;\n}\n\nexport async function register(\n cfg: ApiConfig,\n form: { firstName: string; lastName: string; email: string; phone?: string; password: string }\n): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/register`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone || undefined,\n password: form.password,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error al registrarse.\");\n return data;\n}\n\nexport async function getMe(apiBase: string, token: string): Promise<ClientProfile> {\n const res = await fetch(`${apiBase}/v1/me`, { headers: authHeaders(token) });\n return res.json();\n}\n\nexport async function getMyBookings(\n apiBase: string,\n token: string,\n params?: { upcoming?: boolean; perPage?: number }\n): Promise<BookingRecord[]> {\n const q = new URLSearchParams();\n if (params?.upcoming) q.set(\"upcoming\", \"true\");\n q.set(\"per_page\", String(params?.perPage ?? 20));\n const res = await fetch(`${apiBase}/v1/me/bookings?${q.toString()}`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getMyPackages(apiBase: string, token: string): Promise<PackageRecord[]> {\n const res = await fetch(`${apiBase}/v1/me/packages`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\n/** Result of a client cancelling/rescheduling their own booking — callers\n * branch on `.ok` to show the server's specific reason (cutoff window,\n * overlap, etc.) instead of a generic error. */\nexport type MyBookingActionResult =\n | { ok: true; booking: BookingRecord }\n | { ok: false; message: string };\n\nexport async function cancelMyBooking(\n apiBase: string, token: string, bookingId: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/cancel`, {\n method: \"POST\",\n headers: authHeaders(token),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo cancelar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function rescheduleMyBooking(\n apiBase: string, token: string, bookingId: string, startTime: string, endTime: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/reschedule`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({ start_time: startTime, end_time: endTime }),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo reprogramar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function joinWaitlist(\n apiBase: string,\n token: string,\n params: { serviceId: string; locationId: string; providerId?: string; date?: string; classSessionId?: string }\n): Promise<WaitlistEntry> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({\n service_id: params.serviceId,\n location_id: params.locationId,\n provider_id: params.providerId,\n date: params.date,\n class_session_id: params.classSessionId,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"No se pudo unir a la lista de espera.\");\n return data;\n}\n\nexport async function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void> {\n await fetch(`${apiBase}/v1/me/waitlist/${entryId}`, {\n method: \"DELETE\",\n headers: authHeaders(token),\n });\n}\n","import { getMe } from \"./api\";\nimport type { ClientProfile } from \"./types\";\n\nconst TOKEN_KEY = \"client_token\";\n\nexport function getClientToken(): string | null {\n if (typeof window === \"undefined\") return null;\n return localStorage.getItem(TOKEN_KEY);\n}\n\nexport function setClientToken(token: string): void {\n if (typeof window === \"undefined\") return;\n localStorage.setItem(TOKEN_KEY, token);\n}\n\nexport function clearClientToken(): void {\n if (typeof window === \"undefined\") return;\n localStorage.removeItem(TOKEN_KEY);\n}\n\nexport async function fetchMe(apiBase: string, token: string): Promise<ClientProfile | null> {\n try {\n return await getMe(apiBase, token);\n } catch {\n return null;\n }\n}\n","export function getMondayOf(date: Date): Date {\n const d = new Date(date);\n const day = (d.getDay() + 6) % 7;\n d.setDate(d.getDate() - day);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\nexport function dateStr(d: Date): string {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`;\n}\n\nexport function formatMonthRange(monday: Date): string {\n const sunday = new Date(monday);\n sunday.setDate(monday.getDate() + 6);\n const opts: Intl.DateTimeFormatOptions = { day: \"numeric\", month: \"long\" };\n const start = monday.toLocaleDateString(\"es-CL\", opts);\n const end = sunday.toLocaleDateString(\"es-CL\", opts);\n return `${start} – ${end}`;\n}\n\nexport const DAY_NAMES = [\"Lun\", \"Mar\", \"Mié\", \"Jue\", \"Vie\", \"Sáb\", \"Dom\"];\nexport const DAY_NAMES_FULL = [\"Lunes\", \"Martes\", \"Miércoles\", \"Jueves\", \"Viernes\", \"Sábado\", \"Domingo\"];\n\nexport interface ProviderColor {\n bg: string;\n border: string;\n text: string;\n}\n\nexport const DEFAULT_PROVIDER_COLORS: ProviderColor[] = [\n { bg: \"#e8f5f0\", border: \"#2bbf8e\", text: \"#1a7a5a\" },\n { bg: \"#eef0fb\", border: \"#6b7de8\", text: \"#3d4fa8\" },\n { bg: \"#fdf3e8\", border: \"#e8a24b\", text: \"#a0600a\" },\n { bg: \"#fdeef4\", border: \"#e86b9a\", text: \"#a03060\" },\n];\n","import { useEffect, useState } from \"react\";\nimport {\n createBooking,\n getAvailableSlots,\n listLocations,\n listProviders,\n listServices,\n} from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport type {\n ApiConfig,\n BookingRecord,\n ClientFormValues,\n ClientProfile,\n Location,\n Provider,\n Service,\n Slot,\n} from \"../types\";\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClientForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n if (!form.rut.trim()) return \"Por favor ingresa tu RUT.\";\n return null;\n}\n\ninterface BuildBookingPayloadArgs {\n form: ClientFormValues;\n client: ClientProfile | null;\n selectedDate: string;\n selectedSlot: Slot;\n selectedSvc: string;\n selectedLoc: string;\n svcPrice?: string;\n defaultNotes?: string;\n overrides?: SubmitBookingOverrides;\n}\n\nfunction buildBookingPayload(args: BuildBookingPayloadArgs) {\n const { form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc } = args;\n const price = args.overrides?.price ?? args.svcPrice ?? \"0\";\n const notes = args.overrides?.notes ?? args.defaultNotes;\n return {\n start_time: `${selectedDate}T${selectedSlot.start_time}:00-04:00`,\n end_time: `${selectedDate}T${selectedSlot.end_time}:00-04:00`,\n service_id: selectedSvc,\n service_provider_id: selectedSlot.provider_id,\n location_id: selectedLoc,\n price,\n notes,\n // Ignored server-side unless a client/staff auth token proves the caller's\n // identity; for a logged-in client it's redundant but harmless to include.\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nexport interface UseBookingFlowOptions extends ApiConfig {\n onBookingComplete: (booking: BookingRecord) => void;\n /** Default notes attached to every booking (e.g. \"Reserva realizada desde sitio web X\"). */\n defaultNotes?: string;\n}\n\nexport interface SubmitBookingOverrides {\n /** Override the service's list price (e.g. magnolia's price-variant step). */\n price?: string;\n /** Override defaultNotes for this specific submission. */\n notes?: string;\n}\n\n/**\n * Shared booking-flow logic: catalog fetching (locations/services/providers/\n * slots), logged-in-client prefill, form validation, and submit-with-409-\n * handling. Does NOT own step navigation or app-specific filtering (e.g.\n * magnolia's category/price-variant logic) — those stay in the consuming\n * component, layered on top of the `services`/`providers` this hook returns.\n */\nexport function useBookingFlow(opts: UseBookingFlowOptions) {\n const [locations, setLocations] = useState<Location[]>([]);\n const [services, setServices] = useState<Service[]>([]);\n const [providers, setProviders] = useState<Provider[]>([]);\n const [slots, setSlots] = useState<Slot[]>([]);\n\n const [selectedLoc, setSelectedLoc] = useState(\"\");\n const [selectedSvc, setSelectedSvc] = useState(\"\");\n const [selectedProv, setSelectedProv] = useState(\"\");\n const [selectedDate, setSelectedDate] = useState(\"\");\n const [selectedSlot, setSelectedSlot] = useState<Slot | null>(null);\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n // Prefill from a logged-in client session, if any.\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n listLocations(opts)\n .then(setLocations)\n .catch(() => setError(\"Error cargando sucursales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!selectedLoc) return;\n listServices(opts)\n .then(setServices)\n .catch(() => setError(\"Error cargando servicios\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc]);\n\n useEffect(() => {\n if (!selectedSvc) return;\n listProviders(opts)\n .then(setProviders)\n .catch(() => setError(\"Error cargando profesionales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedSvc]);\n\n useEffect(() => {\n if (!selectedLoc || !selectedDate) return;\n setLoading(true);\n getAvailableSlots(opts, {\n locationId: selectedLoc,\n startDate: selectedDate,\n serviceId: selectedSvc || undefined,\n providerId: selectedProv || undefined,\n })\n .then(s => { setSlots(s); setLoading(false); })\n .catch(() => { setError(\"Error cargando horarios\"); setLoading(false); });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc, selectedSvc, selectedProv, selectedDate]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (overrides?: SubmitBookingOverrides) => {\n if (!selectedSlot) return;\n const validationError = validateClientForm(form);\n if (validationError) { setError(validationError); return; }\n\n setLoading(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.id === selectedSvc);\n const token = getClientToken();\n const payload = buildBookingPayload({\n form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc, overrides,\n svcPrice: svc?.price, defaultNotes: opts.defaultNotes,\n });\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar la reserva\");\n setLoading(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(result.message);\n if (result.conflict) setSelectedSlot(null);\n setLoading(false);\n return;\n }\n opts.onBookingComplete(result.booking);\n }\n\n return {\n locations, services, providers, slots,\n selectedLoc, setSelectedLoc,\n selectedSvc, setSelectedSvc,\n selectedProv, setSelectedProv,\n selectedDate, setSelectedDate,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n loading, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { createBooking, getAvailableSlots, listLocations, listServices } from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport { dateStr, DEFAULT_PROVIDER_COLORS, getMondayOf, type ProviderColor } from \"../dateUtils\";\nimport type { ApiConfig, ClientFormValues, ClientProfile, Service, Slot } from \"../types\";\n\nexport interface SelectedClassSlot {\n slot: Slot;\n date: string;\n}\n\nexport interface UseClassScheduleOptions extends ApiConfig {\n onBookingComplete: () => void;\n colors?: ProviderColor[];\n}\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClassForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n return null;\n}\n\nfunction buildClassBookingPayload(\n form: ClientFormValues,\n client: ClientProfile | null,\n selectedSlot: SelectedClassSlot,\n svc: Service | undefined,\n locationId: string\n) {\n return {\n start_time: `${selectedSlot.date}T${selectedSlot.slot.start_time}:00-04:00`,\n end_time: `${selectedSlot.date}T${selectedSlot.slot.end_time}:00-04:00`,\n service_id: svc?.id ?? \"\",\n service_provider_id: selectedSlot.slot.provider_id,\n location_id: locationId,\n price: svc?.price || \"0\",\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nfunction resolveConflictMessage(result: { conflict: boolean; message: string }): string {\n return result.conflict\n ? \"Ese cupo ya fue tomado por otra persona. Cierra esta ventana y elige otro horario.\"\n : result.message;\n}\n\n/**\n * Shared weekly group-class schedule logic: week-of-slots fetching, provider\n * color-palette assignment, and submit-with-409-handling. The week-grid table\n * JSX and modal markup stay in the consuming component — this hook only owns\n * data and state transitions.\n */\nexport function useClassSchedule(opts: UseClassScheduleOptions) {\n const colors = opts.colors ?? DEFAULT_PROVIDER_COLORS;\n\n const [monday, setMonday] = useState<Date>(() => getMondayOf(new Date()));\n const [slotsByDay, setSlotsByDay] = useState<Record<string, Slot[]>>({});\n const [services, setServices] = useState<Service[]>([]);\n const [locationId, setLocationId] = useState(\"\");\n const [loading, setLoading] = useState(true);\n const [selectedSlot, setSelectedSlot] = useState<SelectedClassSlot | null>(null);\n const [providerColorMap, setProviderColorMap] = useState<Record<string, ProviderColor>>({});\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n useEffect(() => {\n Promise.all([listLocations(opts), listServices(opts, 50)])\n .then(([locs, svcs]) => {\n if (locs.length) setLocationId(locs[0].id);\n setServices(svcs);\n })\n .catch(() => setError(\"Error cargando datos\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const loadWeek = useCallback(async (mon: Date, locId: string) => {\n if (!locId) return;\n setLoading(true);\n const days = Array.from({ length: 7 }, (_, i) => {\n const d = new Date(mon);\n d.setDate(mon.getDate() + i);\n return d;\n });\n\n const results = await Promise.all(\n days.map(async d => {\n const ds = dateStr(d);\n try {\n const slots = await getAvailableSlots(opts, { locationId: locId, startDate: ds });\n return { date: ds, slots };\n } catch {\n return { date: ds, slots: [] as Slot[] };\n }\n })\n );\n\n const map: Record<string, Slot[]> = {};\n const colorMap: Record<string, ProviderColor> = {};\n let colorIdx = 0;\n results.forEach(({ date, slots }) => {\n map[date] = slots;\n slots.forEach(s => {\n if (!colorMap[s.provider_id]) {\n colorMap[s.provider_id] = colors[colorIdx % colors.length];\n colorIdx++;\n }\n });\n });\n\n setSlotsByDay(map);\n setProviderColorMap(prev => ({ ...prev, ...colorMap }));\n setLoading(false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (locationId) loadWeek(monday, locationId);\n }, [monday, locationId, loadWeek]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!selectedSlot) return;\n const validationError = validateClassForm(form);\n if (validationError) { setError(validationError); return; }\n setSubmitting(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.name === selectedSlot.slot.service_name);\n const token = getClientToken();\n const payload = buildClassBookingPayload(form, client, selectedSlot, svc, locationId);\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar\");\n setSubmitting(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(resolveConflictMessage(result));\n setSubmitting(false);\n return;\n }\n opts.onBookingComplete();\n }\n\n return {\n monday, setMonday,\n slotsByDay, loading, providerColorMap,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n submitting, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useState } from \"react\";\nimport { loginWithGoogle, sendMagicLink } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\ndeclare global {\n interface Window {\n google?: {\n accounts: {\n id: {\n initialize: (config: { client_id: string; callback: (response: { credential: string }) => void }) => void;\n prompt: () => void;\n };\n };\n };\n }\n}\n\nexport interface UseMagicLinkAuthOptions extends ApiConfig {\n googleClientId?: string;\n frontendUrl: string;\n onGoogleLoggedIn: () => void;\n}\n\nexport type MagicLinkStep = \"email\" | \"sent\";\n\nexport function useMagicLinkAuth(opts: UseMagicLinkAuthOptions) {\n const [email, setEmail] = useState(\"\");\n // Optional — only relevant on a signup-style form (e.g. registro pages)\n // that collects a bit more than login does. Login pages can ignore these.\n const [firstName, setFirstName] = useState(\"\");\n const [lastName, setLastName] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [rut, setRut] = useState(\"\");\n const [step, setStep] = useState<MagicLinkStep>(\"email\");\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const handleMagicLink = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!email.trim() || !/\\S+@\\S+\\.\\S+/.test(email)) {\n setError(\"Ingresa un email válido.\");\n return;\n }\n setLoading(true);\n setError(\"\");\n try {\n await sendMagicLink(opts, email, opts.frontendUrl, {\n firstName: firstName || undefined,\n lastName: lastName || undefined,\n phone: phone || undefined,\n rut: rut || undefined,\n });\n setStep(\"sent\");\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error enviando el link.\");\n } finally {\n setLoading(false);\n }\n };\n\n const handleGoogle = () => {\n if (!opts.googleClientId || typeof window === \"undefined\" || !window.google) return;\n window.google.accounts.id.initialize({\n client_id: opts.googleClientId,\n callback: async (response: { credential: string }) => {\n setLoading(true);\n try {\n const data = await loginWithGoogle(opts, response.credential);\n setClientToken(data.access_token);\n opts.onGoogleLoggedIn();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error con Google.\");\n setLoading(false);\n }\n },\n });\n window.google.accounts.id.prompt();\n };\n\n const reset = () => {\n setStep(\"email\");\n setError(\"\");\n };\n\n return {\n email, setEmail,\n firstName, setFirstName,\n lastName, setLastName,\n phone, setPhone,\n rut, setRut,\n step, error, loading, handleMagicLink, handleGoogle, reset,\n };\n}\n","import { useState } from \"react\";\nimport { register } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\nexport interface RegisterFormValues {\n firstName: string;\n lastName: string;\n email: string;\n phone: string;\n password: string;\n confirm: string;\n}\n\nconst EMPTY: RegisterFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", password: \"\", confirm: \"\" };\n\nexport interface UseRegisterFormOptions extends ApiConfig {\n onRegistered: () => void;\n}\n\nexport function useRegisterForm(opts: UseRegisterFormOptions) {\n const [form, setForm] = useState<RegisterFormValues>(EMPTY);\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const updateField = (fields: Partial<RegisterFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const handleSubmit = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!form.firstName.trim()) { setError(\"Ingresa tu nombre.\"); return; }\n if (!form.lastName.trim()) { setError(\"Ingresa tu apellido.\"); return; }\n if (!form.email.trim()) { setError(\"Ingresa tu email.\"); return; }\n if (form.password.length < 6) { setError(\"La contraseña debe tener al menos 6 caracteres.\"); return; }\n if (form.password !== form.confirm) { setError(\"Las contraseñas no coinciden.\"); return; }\n setLoading(true);\n setError(\"\");\n try {\n const data = await register(opts, form);\n setClientToken(data.access_token);\n opts.onRegistered();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al registrarse.\");\n } finally {\n setLoading(false);\n }\n };\n\n return { form, updateField, error, loading, handleSubmit };\n}\n","import { useEffect, useState } from \"react\";\nimport { cancelMyBooking, getMe, getMyBookings, getMyPackages, rescheduleMyBooking } from \"../api\";\nimport { clearClientToken, getClientToken } from \"../clientAuth\";\nimport type { BookingRecord, ClientProfile, PackageRecord } from \"../types\";\n\nexport interface UseClientAccountOptions {\n apiBase: string;\n onUnauthenticated: () => void;\n onLoggedOut: () => void;\n}\n\nexport function useClientAccount(opts: UseClientAccountOptions) {\n const [profile, setProfile] = useState<ClientProfile | null>(null);\n const [upcoming, setUpcoming] = useState<BookingRecord[]>([]);\n const [history, setHistory] = useState<BookingRecord[]>([]);\n const [packages, setPackages] = useState<PackageRecord[]>([]);\n const [loading, setLoading] = useState(true);\n const [actionError, setActionError] = useState(\"\");\n const [actionLoading, setActionLoading] = useState(false);\n\n const loadAll = () => {\n const token = getClientToken();\n if (!token) {\n opts.onUnauthenticated();\n return;\n }\n Promise.all([\n getMe(opts.apiBase, token),\n getMyBookings(opts.apiBase, token, { upcoming: true, perPage: 10 }),\n getMyBookings(opts.apiBase, token, { perPage: 20 }),\n getMyPackages(opts.apiBase, token),\n ])\n .then(([prof, up, hist, pkgs]) => {\n setProfile(prof);\n setUpcoming(up);\n setHistory(hist);\n setPackages(pkgs);\n setLoading(false);\n })\n .catch(() => opts.onUnauthenticated());\n };\n\n useEffect(() => {\n loadAll();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const handleLogout = () => {\n clearClientToken();\n opts.onLoggedOut();\n };\n\n const cancelBooking = async (bookingId: string) => {\n const token = getClientToken();\n if (!token) return;\n setActionLoading(true);\n setActionError(\"\");\n const result = await cancelMyBooking(opts.apiBase, token, bookingId);\n if (!result.ok) {\n setActionError(result.message);\n setActionLoading(false);\n return;\n }\n loadAll();\n setActionLoading(false);\n };\n\n const rescheduleBooking = async (bookingId: string, startTime: string, endTime: string) => {\n const token = getClientToken();\n if (!token) return false;\n setActionLoading(true);\n setActionError(\"\");\n const result = await rescheduleMyBooking(opts.apiBase, token, bookingId, startTime, endTime);\n setActionLoading(false);\n if (!result.ok) {\n setActionError(result.message);\n return false;\n }\n loadAll();\n return true;\n };\n\n const totalCredits = packages.reduce((s, p) => s + p.remaining_credits, 0);\n\n return {\n profile, upcoming, history, packages, loading, totalCredits, handleLogout,\n cancelBooking, rescheduleBooking, actionError, setActionError, actionLoading,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACeA,SAAS,QAAQ,KAAgB,WAAW,OAA+B;AACzE,QAAM,IAA4B,EAAE,aAAa,IAAI,OAAO;AAC5D,MAAI,SAAU,GAAE,cAAc,IAAI;AAClC,SAAO;AACT;AAEA,SAAS,YAAY,OAAe,WAAW,OAA+B;AAC5E,QAAM,IAA4B,EAAE,eAAe,UAAU,KAAK,GAAG;AACrE,MAAI,SAAU,GAAE,cAAc,IAAI;AAClC,SAAO;AACT;AAEA,eAAsB,cAAc,KAAqC;AACvE,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,iBAAiB,EAAE,SAAS,QAAQ,GAAG,EAAE,CAAC;AAChF,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO,KAAK,QAAQ,CAAC;AACvB;AAEA,eAAsB,aAAa,KAAgB,UAAU,KAAyB;AACpF,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,yBAAyB,OAAO,IAAI,EAAE,SAAS,QAAQ,GAAG,EAAE,CAAC;AACnG,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO,KAAK,QAAQ,CAAC;AACvB;AAEA,eAAsB,cAAc,KAAgB,UAAU,KAA0B;AACtF,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,0BAA0B,OAAO,IAAI,EAAE,SAAS,QAAQ,GAAG,EAAE,CAAC;AACpG,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO,KAAK,QAAQ,CAAC;AACvB;AAEA,eAAsB,kBACpB,KACA,QACiB;AACjB,QAAM,IAAI,IAAI,gBAAgB,EAAE,aAAa,OAAO,YAAY,YAAY,OAAO,UAAU,CAAC;AAC9F,MAAI,OAAO,UAAW,GAAE,IAAI,cAAc,OAAO,SAAS;AAC1D,MAAI,OAAO,WAAY,GAAE,IAAI,eAAe,OAAO,UAAU;AAC7D,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,uBAAuB,EAAE,SAAS,CAAC,IAAI,EAAE,SAAS,QAAQ,GAAG,EAAE,CAAC;AACtG,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO,KAAK,MAAM,SAAS,CAAC;AAC9B;AAEA,eAAsB,aAAa,KAAgB,MAAiD;AAClG,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,eAAe;AAAA,IACnD,QAAQ;AAAA,IACR,SAAS,QAAQ,KAAK,IAAI;AAAA,IAC1B,MAAM,KAAK,UAAU;AAAA,MACnB,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,KAAK,KAAK,OAAO;AAAA,IACnB,CAAC;AAAA,EACH,CAAC;AACD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,yBAAyB;AACtD,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,cACpB,KACA,OACA,aACwB;AAKxB,QAAM,aAAa,QAAQ,KAAK,IAAI;AACpC,MAAI,YAAa,YAAW,gBAAgB,UAAU,WAAW;AACjE,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,gBAAgB;AAAA,IACpD,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM,KAAK,UAAU,KAAK;AAAA,EAC5B,CAAC;AACD,MAAI,IAAI,WAAW,KAAK;AACtB,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,WAAO,EAAE,IAAI,OAAO,UAAU,MAAM,SAAS,KAAK,UAAU,wCAAqC;AAAA,EACnG;AACA,MAAI,CAAC,IAAI,IAAI;AACX,WAAO,EAAE,IAAI,OAAO,UAAU,OAAO,SAAS,0DAA0D;AAAA,EAC1G;AACA,SAAO,EAAE,IAAI,MAAM,SAAS,MAAM,IAAI,KAAK,EAAE;AAC/C;AAEA,eAAsB,cACpB,KACA,OACA,aACA,SACe;AACf,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,8BAA8B;AAAA,IAClE,QAAQ;AAAA,IACR,SAAS,QAAQ,KAAK,IAAI;AAAA,IAC1B,MAAM,KAAK,UAAU;AAAA,MACnB,OAAO,MAAM,KAAK,EAAE,YAAY;AAAA,MAChC,cAAc;AAAA,MACd,YAAY,SAAS;AAAA,MACrB,WAAW,SAAS;AAAA,MACpB,OAAO,SAAS;AAAA,MAChB,KAAK,SAAS;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,KAAK,UAAU,yBAAyB;AACvE;AAEA,eAAsB,gBAAgB,KAAgB,OAAkD;AACtG,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,qCAAqC;AAAA,IACzE,QAAQ;AAAA,IACR,SAAS,QAAQ,KAAK,IAAI;AAAA,IAC1B,MAAM,KAAK,UAAU,EAAE,MAAM,CAAC;AAAA,EAChC,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,KAAK,aAAc,OAAM,IAAI,MAAM,KAAK,UAAU,mBAAgB;AACvE,SAAO;AACT;AAEA,eAAsB,gBAAgB,KAAgB,YAAuD;AAC3G,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,0BAA0B;AAAA,IAC9D,QAAQ;AAAA,IACR,SAAS,QAAQ,KAAK,IAAI;AAAA,IAC1B,MAAM,KAAK,UAAU,EAAE,WAAW,CAAC;AAAA,EACrC,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,KAAK,UAAU,mBAAmB;AAC/D,SAAO;AACT;AAEA,eAAsB,SACpB,KACA,MACmC;AACnC,QAAM,MAAM,MAAM,MAAM,GAAG,IAAI,OAAO,4BAA4B;AAAA,IAChE,QAAQ;AAAA,IACR,SAAS,QAAQ,KAAK,IAAI;AAAA,IAC1B,MAAM,KAAK,UAAU;AAAA,MACnB,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK,SAAS;AAAA,MACrB,UAAU,KAAK;AAAA,IACjB,CAAC;AAAA,EACH,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,KAAK,UAAU,uBAAuB;AACnE,SAAO;AACT;AAEA,eAAsB,MAAM,SAAiB,OAAuC;AAClF,QAAM,MAAM,MAAM,MAAM,GAAG,OAAO,UAAU,EAAE,SAAS,YAAY,KAAK,EAAE,CAAC;AAC3E,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,cACpB,SACA,OACA,QAC0B;AAC1B,QAAM,IAAI,IAAI,gBAAgB;AAC9B,MAAI,QAAQ,SAAU,GAAE,IAAI,YAAY,MAAM;AAC9C,IAAE,IAAI,YAAY,OAAO,QAAQ,WAAW,EAAE,CAAC;AAC/C,QAAM,MAAM,MAAM,MAAM,GAAG,OAAO,mBAAmB,EAAE,SAAS,CAAC,IAAI,EAAE,SAAS,YAAY,KAAK,EAAE,CAAC;AACpG,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO,KAAK,QAAQ,CAAC;AACvB;AAEA,eAAsB,cAAc,SAAiB,OAAyC;AAC5F,QAAM,MAAM,MAAM,MAAM,GAAG,OAAO,mBAAmB,EAAE,SAAS,YAAY,KAAK,EAAE,CAAC;AACpF,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO,KAAK,QAAQ,CAAC;AACvB;AASA,eAAsB,gBACpB,SAAiB,OAAe,WACA;AAChC,QAAM,MAAM,MAAM,MAAM,GAAG,OAAO,mBAAmB,SAAS,WAAW;AAAA,IACvE,QAAQ;AAAA,IACR,SAAS,YAAY,KAAK;AAAA,EAC5B,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,MAAI,CAAC,IAAI,GAAI,QAAO,EAAE,IAAI,OAAO,SAAS,KAAK,UAAU,kCAAkC;AAC3F,SAAO,EAAE,IAAI,MAAM,SAAS,KAAK;AACnC;AAEA,eAAsB,oBACpB,SAAiB,OAAe,WAAmB,WAAmB,SACtC;AAChC,QAAM,MAAM,MAAM,MAAM,GAAG,OAAO,mBAAmB,SAAS,eAAe;AAAA,IAC3E,QAAQ;AAAA,IACR,SAAS,YAAY,OAAO,IAAI;AAAA,IAChC,MAAM,KAAK,UAAU,EAAE,YAAY,WAAW,UAAU,QAAQ,CAAC;AAAA,EACnE,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,MAAI,CAAC,IAAI,GAAI,QAAO,EAAE,IAAI,OAAO,SAAS,KAAK,UAAU,qCAAqC;AAC9F,SAAO,EAAE,IAAI,MAAM,SAAS,KAAK;AACnC;AAEA,eAAsB,aACpB,SACA,OACA,QACwB;AACxB,QAAM,MAAM,MAAM,MAAM,GAAG,OAAO,mBAAmB;AAAA,IACnD,QAAQ;AAAA,IACR,SAAS,YAAY,OAAO,IAAI;AAAA,IAChC,MAAM,KAAK,UAAU;AAAA,MACnB,YAAY,OAAO;AAAA,MACnB,aAAa,OAAO;AAAA,MACpB,aAAa,OAAO;AAAA,MACpB,MAAM,OAAO;AAAA,MACb,kBAAkB,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH,CAAC;AACD,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,KAAK,UAAU,uCAAuC;AACnF,SAAO;AACT;AAEA,eAAsB,cAAc,SAAiB,OAAyC;AAC5F,QAAM,MAAM,MAAM,MAAM,GAAG,OAAO,mBAAmB,EAAE,SAAS,YAAY,KAAK,EAAE,CAAC;AACpF,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,SAAO,KAAK,QAAQ,CAAC;AACvB;AAEA,eAAsB,cAAc,SAAiB,OAAe,SAAgC;AAClG,QAAM,MAAM,GAAG,OAAO,mBAAmB,OAAO,IAAI;AAAA,IAClD,QAAQ;AAAA,IACR,SAAS,YAAY,KAAK;AAAA,EAC5B,CAAC;AACH;;;ACxPA,IAAM,YAAY;AAEX,SAAS,iBAAgC;AAC9C,MAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,SAAO,aAAa,QAAQ,SAAS;AACvC;AAEO,SAAS,eAAe,OAAqB;AAClD,MAAI,OAAO,WAAW,YAAa;AACnC,eAAa,QAAQ,WAAW,KAAK;AACvC;AAEO,SAAS,mBAAyB;AACvC,MAAI,OAAO,WAAW,YAAa;AACnC,eAAa,WAAW,SAAS;AACnC;AAEA,eAAsB,QAAQ,SAAiB,OAA8C;AAC3F,MAAI;AACF,WAAO,MAAM,MAAM,SAAS,KAAK;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC1BO,SAAS,YAAY,MAAkB;AAC5C,QAAM,IAAI,IAAI,KAAK,IAAI;AACvB,QAAM,OAAO,EAAE,OAAO,IAAI,KAAK;AAC/B,IAAE,QAAQ,EAAE,QAAQ,IAAI,GAAG;AAC3B,IAAE,SAAS,GAAG,GAAG,GAAG,CAAC;AACrB,SAAO;AACT;AAEO,SAAS,QAAQ,GAAiB;AACvC,SAAO,GAAG,EAAE,YAAY,CAAC,IAAI,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAChH;AAEO,SAAS,iBAAiB,QAAsB;AACrD,QAAM,SAAS,IAAI,KAAK,MAAM;AAC9B,SAAO,QAAQ,OAAO,QAAQ,IAAI,CAAC;AACnC,QAAM,OAAmC,EAAE,KAAK,WAAW,OAAO,OAAO;AACzE,QAAM,QAAQ,OAAO,mBAAmB,SAAS,IAAI;AACrD,QAAM,MAAM,OAAO,mBAAmB,SAAS,IAAI;AACnD,SAAO,GAAG,KAAK,WAAM,GAAG;AAC1B;AAEO,IAAM,YAAY,CAAC,OAAO,OAAO,UAAO,OAAO,OAAO,UAAO,KAAK;AAClE,IAAM,iBAAiB,CAAC,SAAS,UAAU,gBAAa,UAAU,WAAW,aAAU,SAAS;AAQhG,IAAM,0BAA2C;AAAA,EACtD,EAAE,IAAI,WAAW,QAAQ,WAAW,MAAM,UAAU;AAAA,EACpD,EAAE,IAAI,WAAW,QAAQ,WAAW,MAAM,UAAU;AAAA,EACpD,EAAE,IAAI,WAAW,QAAQ,WAAW,MAAM,UAAU;AAAA,EACpD,EAAE,IAAI,WAAW,QAAQ,WAAW,MAAM,UAAU;AACtD;;;ACnCA,mBAAoC;AAoBpC,IAAM,aAA+B,EAAE,WAAW,IAAI,UAAU,IAAI,OAAO,IAAI,OAAO,IAAI,KAAK,GAAG;AAElG,SAAS,aAAa,OAAwB;AAC5C,SAAO,MAAM,QAAQ,WAAW,EAAE,EAAE,UAAU;AAChD;AAEA,SAAS,mBAAmB,MAAuC;AACjE,MAAI,CAAC,KAAK,UAAU,KAAK,EAAG,QAAO;AACnC,MAAI,CAAC,KAAK,SAAS,KAAK,EAAG,QAAO;AAClC,MAAI,CAAC,KAAK,MAAM,KAAK,KAAK,CAAC,eAAe,KAAK,KAAK,KAAK,EAAG,QAAO;AACnE,MAAI,CAAC,KAAK,MAAM,KAAK,KAAK,CAAC,aAAa,KAAK,KAAK,EAAG,QAAO;AAC5D,MAAI,CAAC,KAAK,IAAI,KAAK,EAAG,QAAO;AAC7B,SAAO;AACT;AAcA,SAAS,oBAAoB,MAA+B;AAC1D,QAAM,EAAE,MAAM,QAAQ,cAAc,cAAc,aAAa,YAAY,IAAI;AAC/E,QAAM,QAAQ,KAAK,WAAW,SAAS,KAAK,YAAY;AACxD,QAAM,QAAQ,KAAK,WAAW,SAAS,KAAK;AAC5C,SAAO;AAAA,IACL,YAAY,GAAG,YAAY,IAAI,aAAa,UAAU;AAAA,IACtD,UAAU,GAAG,YAAY,IAAI,aAAa,QAAQ;AAAA,IAClD,YAAY;AAAA,IACZ,qBAAqB,aAAa;AAAA,IAClC,aAAa;AAAA,IACb;AAAA,IACA;AAAA;AAAA;AAAA,IAGA,WAAW,QAAQ;AAAA,IACnB,mBAAmB,KAAK;AAAA,IACxB,kBAAkB,KAAK;AAAA,IACvB,cAAc,KAAK;AAAA,IACnB,cAAc,KAAK;AAAA,IACnB,YAAY,KAAK,OAAO;AAAA,EAC1B;AACF;AAsBO,SAAS,eAAe,MAA6B;AAC1D,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAqB,CAAC,CAAC;AACzD,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAoB,CAAC,CAAC;AACtD,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAqB,CAAC,CAAC;AACzD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAiB,CAAC,CAAC;AAE7C,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,EAAE;AACjD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,EAAE;AACjD,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,EAAE;AACnD,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,EAAE;AACnD,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAsB,IAAI;AAElE,QAAM,CAAC,MAAM,OAAO,QAAI,uBAA2B,UAAU;AAC7D,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,EAAE;AACrC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAA+B,IAAI;AAG/D,8BAAU,MAAM;AACd,UAAM,QAAQ,eAAe;AAC7B,QAAI,CAAC,MAAO;AACZ,YAAQ,KAAK,SAAS,KAAK,EAAE,KAAK,aAAW;AAC3C,UAAI,CAAC,QAAS;AACd,gBAAU,OAAO;AACjB,cAAQ,QAAM;AAAA,QACZ,GAAG;AAAA,QACH,WAAW,QAAQ,cAAc,EAAE;AAAA,QACnC,UAAU,QAAQ,aAAa,EAAE;AAAA,QACjC,OAAO,QAAQ,SAAS,EAAE;AAAA,QAC1B,OAAO,QAAQ,SAAS,EAAE;AAAA,QAC1B,KAAK,QAAQ,OAAO,EAAE;AAAA,MACxB,EAAE;AAAA,IACJ,CAAC;AAAA,EAEH,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,kBAAc,IAAI,EACf,KAAK,YAAY,EACjB,MAAM,MAAM,SAAS,2BAA2B,CAAC;AAAA,EAEtD,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,QAAI,CAAC,YAAa;AAClB,iBAAa,IAAI,EACd,KAAK,WAAW,EAChB,MAAM,MAAM,SAAS,0BAA0B,CAAC;AAAA,EAErD,GAAG,CAAC,WAAW,CAAC;AAEhB,8BAAU,MAAM;AACd,QAAI,CAAC,YAAa;AAClB,kBAAc,IAAI,EACf,KAAK,YAAY,EACjB,MAAM,MAAM,SAAS,8BAA8B,CAAC;AAAA,EAEzD,GAAG,CAAC,WAAW,CAAC;AAEhB,8BAAU,MAAM;AACd,QAAI,CAAC,eAAe,CAAC,aAAc;AACnC,eAAW,IAAI;AACf,sBAAkB,MAAM;AAAA,MACtB,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW,eAAe;AAAA,MAC1B,YAAY,gBAAgB;AAAA,IAC9B,CAAC,EACE,KAAK,OAAK;AAAE,eAAS,CAAC;AAAG,iBAAW,KAAK;AAAA,IAAG,CAAC,EAC7C,MAAM,MAAM;AAAE,eAAS,yBAAyB;AAAG,iBAAW,KAAK;AAAA,IAAG,CAAC;AAAA,EAE5E,GAAG,CAAC,aAAa,aAAa,cAAc,YAAY,CAAC;AAEzD,QAAM,aAAa,CAAC,WAAsC,QAAQ,QAAM,EAAE,GAAG,GAAG,GAAG,OAAO,EAAE;AAE5F,QAAM,gBAAgB,OAAO,cAAuC;AAClE,QAAI,CAAC,aAAc;AACnB,UAAM,kBAAkB,mBAAmB,IAAI;AAC/C,QAAI,iBAAiB;AAAE,eAAS,eAAe;AAAG;AAAA,IAAQ;AAE1D,eAAW,IAAI;AACf,aAAS,EAAE;AACX,QAAI;AACF,YAAM,MAAM,SAAS,KAAK,OAAK,EAAE,OAAO,WAAW;AACnD,YAAM,QAAQ,eAAe;AAC7B,YAAM,UAAU,oBAAoB;AAAA,QAClC;AAAA,QAAM;AAAA,QAAQ;AAAA,QAAc;AAAA,QAAc;AAAA,QAAa;AAAA,QAAa;AAAA,QACpE,UAAU,KAAK;AAAA,QAAO,cAAc,KAAK;AAAA,MAC3C,CAAC;AACD,YAAM,SAAS,MAAM,cAAc,MAAM,SAAS,SAAS,MAAS;AACpE,yBAAmB,MAAM;AAAA,IAC3B,SAAS,KAAc;AACrB,eAAS,eAAe,QAAQ,IAAI,UAAU,8BAA8B;AAC5E,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,WAAS,mBAAmB,QAAmD;AAC7E,QAAI,CAAC,OAAO,IAAI;AACd,eAAS,OAAO,OAAO;AACvB,UAAI,OAAO,SAAU,iBAAgB,IAAI;AACzC,iBAAW,KAAK;AAChB;AAAA,IACF;AACA,SAAK,kBAAkB,OAAO,OAAO;AAAA,EACvC;AAEA,SAAO;AAAA,IACL;AAAA,IAAW;AAAA,IAAU;AAAA,IAAW;AAAA,IAChC;AAAA,IAAa;AAAA,IACb;AAAA,IAAa;AAAA,IACb;AAAA,IAAc;AAAA,IACd;AAAA,IAAc;AAAA,IACd;AAAA,IAAc;AAAA,IACd;AAAA,IAAM;AAAA,IACN;AAAA,IAAS;AAAA,IAAO;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;;;ACjNA,IAAAA,gBAAiD;AAgBjD,IAAMC,cAA+B,EAAE,WAAW,IAAI,UAAU,IAAI,OAAO,IAAI,OAAO,IAAI,KAAK,GAAG;AAElG,SAASC,cAAa,OAAwB;AAC5C,SAAO,MAAM,QAAQ,WAAW,EAAE,EAAE,UAAU;AAChD;AAEA,SAAS,kBAAkB,MAAuC;AAChE,MAAI,CAAC,KAAK,UAAU,KAAK,EAAG,QAAO;AACnC,MAAI,CAAC,KAAK,SAAS,KAAK,EAAG,QAAO;AAClC,MAAI,CAAC,KAAK,MAAM,KAAK,KAAK,CAAC,eAAe,KAAK,KAAK,KAAK,EAAG,QAAO;AACnE,MAAI,CAAC,KAAK,MAAM,KAAK,KAAK,CAACA,cAAa,KAAK,KAAK,EAAG,QAAO;AAC5D,SAAO;AACT;AAEA,SAAS,yBACP,MACA,QACA,cACA,KACA,YACA;AACA,SAAO;AAAA,IACL,YAAY,GAAG,aAAa,IAAI,IAAI,aAAa,KAAK,UAAU;AAAA,IAChE,UAAU,GAAG,aAAa,IAAI,IAAI,aAAa,KAAK,QAAQ;AAAA,IAC5D,YAAY,KAAK,MAAM;AAAA,IACvB,qBAAqB,aAAa,KAAK;AAAA,IACvC,aAAa;AAAA,IACb,OAAO,KAAK,SAAS;AAAA,IACrB,WAAW,QAAQ;AAAA,IACnB,mBAAmB,KAAK;AAAA,IACxB,kBAAkB,KAAK;AAAA,IACvB,cAAc,KAAK;AAAA,IACnB,cAAc,KAAK;AAAA,IACnB,YAAY,KAAK,OAAO;AAAA,EAC1B;AACF;AAEA,SAAS,uBAAuB,QAAwD;AACtF,SAAO,OAAO,WACV,uFACA,OAAO;AACb;AAQO,SAAS,iBAAiB,MAA+B;AAC9D,QAAM,SAAS,KAAK,UAAU;AAE9B,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAAe,MAAM,YAAY,oBAAI,KAAK,CAAC,CAAC;AACxE,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAiC,CAAC,CAAC;AACvE,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAoB,CAAC,CAAC;AACtD,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,EAAE;AAC/C,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,IAAI;AAC3C,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAmC,IAAI;AAC/E,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,wBAAwC,CAAC,CAAC;AAE1F,QAAM,CAAC,MAAM,OAAO,QAAI,wBAA2BD,WAAU;AAC7D,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAA+B,IAAI;AAE/D,+BAAU,MAAM;AACd,YAAQ,IAAI,CAAC,cAAc,IAAI,GAAG,aAAa,MAAM,EAAE,CAAC,CAAC,EACtD,KAAK,CAAC,CAAC,MAAM,IAAI,MAAM;AACtB,UAAI,KAAK,OAAQ,eAAc,KAAK,CAAC,EAAE,EAAE;AACzC,kBAAY,IAAI;AAAA,IAClB,CAAC,EACA,MAAM,MAAM,SAAS,sBAAsB,CAAC;AAAA,EAEjD,GAAG,CAAC,CAAC;AAEL,+BAAU,MAAM;AACd,UAAM,QAAQ,eAAe;AAC7B,QAAI,CAAC,MAAO;AACZ,YAAQ,KAAK,SAAS,KAAK,EAAE,KAAK,aAAW;AAC3C,UAAI,CAAC,QAAS;AACd,gBAAU,OAAO;AACjB,cAAQ,QAAM;AAAA,QACZ,GAAG;AAAA,QACH,WAAW,QAAQ,cAAc,EAAE;AAAA,QACnC,UAAU,QAAQ,aAAa,EAAE;AAAA,QACjC,OAAO,QAAQ,SAAS,EAAE;AAAA,QAC1B,OAAO,QAAQ,SAAS,EAAE;AAAA,QAC1B,KAAK,QAAQ,OAAO,EAAE;AAAA,MACxB,EAAE;AAAA,IACJ,CAAC;AAAA,EAEH,GAAG,CAAC,CAAC;AAEL,QAAM,eAAW,2BAAY,OAAO,KAAW,UAAkB;AAC/D,QAAI,CAAC,MAAO;AACZ,eAAW,IAAI;AACf,UAAM,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,MAAM;AAC/C,YAAM,IAAI,IAAI,KAAK,GAAG;AACtB,QAAE,QAAQ,IAAI,QAAQ,IAAI,CAAC;AAC3B,aAAO;AAAA,IACT,CAAC;AAED,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,KAAK,IAAI,OAAM,MAAK;AAClB,cAAM,KAAK,QAAQ,CAAC;AACpB,YAAI;AACF,gBAAM,QAAQ,MAAM,kBAAkB,MAAM,EAAE,YAAY,OAAO,WAAW,GAAG,CAAC;AAChF,iBAAO,EAAE,MAAM,IAAI,MAAM;AAAA,QAC3B,QAAQ;AACN,iBAAO,EAAE,MAAM,IAAI,OAAO,CAAC,EAAY;AAAA,QACzC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,MAA8B,CAAC;AACrC,UAAM,WAA0C,CAAC;AACjD,QAAI,WAAW;AACf,YAAQ,QAAQ,CAAC,EAAE,MAAM,MAAM,MAAM;AACnC,UAAI,IAAI,IAAI;AACZ,YAAM,QAAQ,OAAK;AACjB,YAAI,CAAC,SAAS,EAAE,WAAW,GAAG;AAC5B,mBAAS,EAAE,WAAW,IAAI,OAAO,WAAW,OAAO,MAAM;AACzD;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,kBAAc,GAAG;AACjB,wBAAoB,WAAS,EAAE,GAAG,MAAM,GAAG,SAAS,EAAE;AACtD,eAAW,KAAK;AAAA,EAElB,GAAG,CAAC,CAAC;AAEL,+BAAU,MAAM;AACd,QAAI,WAAY,UAAS,QAAQ,UAAU;AAAA,EAC7C,GAAG,CAAC,QAAQ,YAAY,QAAQ,CAAC;AAEjC,QAAM,aAAa,CAAC,WAAsC,QAAQ,QAAM,EAAE,GAAG,GAAG,GAAG,OAAO,EAAE;AAE5F,QAAM,gBAAgB,OAAO,MAAsC;AACjE,MAAE,eAAe;AACjB,QAAI,CAAC,aAAc;AACnB,UAAM,kBAAkB,kBAAkB,IAAI;AAC9C,QAAI,iBAAiB;AAAE,eAAS,eAAe;AAAG;AAAA,IAAQ;AAC1D,kBAAc,IAAI;AAClB,aAAS,EAAE;AACX,QAAI;AACF,YAAM,MAAM,SAAS,KAAK,OAAK,EAAE,SAAS,aAAa,KAAK,YAAY;AACxE,YAAM,QAAQ,eAAe;AAC7B,YAAM,UAAU,yBAAyB,MAAM,QAAQ,cAAc,KAAK,UAAU;AACpF,YAAM,SAAS,MAAM,cAAc,MAAM,SAAS,SAAS,MAAS;AACpE,yBAAmB,MAAM;AAAA,IAC3B,SAAS,KAAc;AACrB,eAAS,eAAe,QAAQ,IAAI,UAAU,mBAAmB;AACjE,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,WAAS,mBAAmB,QAAmD;AAC7E,QAAI,CAAC,OAAO,IAAI;AACd,eAAS,uBAAuB,MAAM,CAAC;AACvC,oBAAc,KAAK;AACnB;AAAA,IACF;AACA,SAAK,kBAAkB;AAAA,EACzB;AAEA,SAAO;AAAA,IACL;AAAA,IAAQ;AAAA,IACR;AAAA,IAAY;AAAA,IAAS;AAAA,IACrB;AAAA,IAAc;AAAA,IACd;AAAA,IAAM;AAAA,IACN;AAAA,IAAY;AAAA,IAAO;AAAA,IACnB;AAAA,IACA;AAAA,EACF;AACF;;;AChMA,IAAAE,gBAAyB;AA0BlB,SAAS,iBAAiB,MAA+B;AAC9D,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AAGrC,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,EAAE;AAC7C,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,EAAE;AAC3C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,KAAK,MAAM,QAAI,wBAAS,EAAE;AACjC,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAwB,OAAO;AACvD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAE5C,QAAM,kBAAkB,OAAO,MAAsC;AACnE,MAAE,eAAe;AACjB,QAAI,CAAC,MAAM,KAAK,KAAK,CAAC,eAAe,KAAK,KAAK,GAAG;AAChD,eAAS,6BAA0B;AACnC;AAAA,IACF;AACA,eAAW,IAAI;AACf,aAAS,EAAE;AACX,QAAI;AACF,YAAM,cAAc,MAAM,OAAO,KAAK,aAAa;AAAA,QACjD,WAAW,aAAa;AAAA,QACxB,UAAU,YAAY;AAAA,QACtB,OAAO,SAAS;AAAA,QAChB,KAAK,OAAO;AAAA,MACd,CAAC;AACD,cAAQ,MAAM;AAAA,IAChB,SAAS,KAAc;AACrB,eAAS,eAAe,QAAQ,IAAI,UAAU,yBAAyB;AAAA,IACzE,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,eAAe,MAAM;AACzB,QAAI,CAAC,KAAK,kBAAkB,OAAO,WAAW,eAAe,CAAC,OAAO,OAAQ;AAC7E,WAAO,OAAO,SAAS,GAAG,WAAW;AAAA,MACnC,WAAW,KAAK;AAAA,MAChB,UAAU,OAAO,aAAqC;AACpD,mBAAW,IAAI;AACf,YAAI;AACF,gBAAM,OAAO,MAAM,gBAAgB,MAAM,SAAS,UAAU;AAC5D,yBAAe,KAAK,YAAY;AAChC,eAAK,iBAAiB;AAAA,QACxB,SAAS,KAAc;AACrB,mBAAS,eAAe,QAAQ,IAAI,UAAU,mBAAmB;AACjE,qBAAW,KAAK;AAAA,QAClB;AAAA,MACF;AAAA,IACF,CAAC;AACD,WAAO,OAAO,SAAS,GAAG,OAAO;AAAA,EACnC;AAEA,QAAM,QAAQ,MAAM;AAClB,YAAQ,OAAO;AACf,aAAS,EAAE;AAAA,EACb;AAEA,SAAO;AAAA,IACL;AAAA,IAAO;AAAA,IACP;AAAA,IAAW;AAAA,IACX;AAAA,IAAU;AAAA,IACV;AAAA,IAAO;AAAA,IACP;AAAA,IAAK;AAAA,IACL;AAAA,IAAM;AAAA,IAAO;AAAA,IAAS;AAAA,IAAiB;AAAA,IAAc;AAAA,EACvD;AACF;;;AC7FA,IAAAC,gBAAyB;AAczB,IAAM,QAA4B,EAAE,WAAW,IAAI,UAAU,IAAI,OAAO,IAAI,OAAO,IAAI,UAAU,IAAI,SAAS,GAAG;AAM1G,SAAS,gBAAgB,MAA8B;AAC5D,QAAM,CAAC,MAAM,OAAO,QAAI,wBAA6B,KAAK;AAC1D,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAE5C,QAAM,cAAc,CAAC,WAAwC,QAAQ,QAAM,EAAE,GAAG,GAAG,GAAG,OAAO,EAAE;AAE/F,QAAM,eAAe,OAAO,MAAsC;AAChE,MAAE,eAAe;AACjB,QAAI,CAAC,KAAK,UAAU,KAAK,GAAG;AAAE,eAAS,oBAAoB;AAAG;AAAA,IAAQ;AACtE,QAAI,CAAC,KAAK,SAAS,KAAK,GAAG;AAAE,eAAS,sBAAsB;AAAG;AAAA,IAAQ;AACvE,QAAI,CAAC,KAAK,MAAM,KAAK,GAAG;AAAE,eAAS,mBAAmB;AAAG;AAAA,IAAQ;AACjE,QAAI,KAAK,SAAS,SAAS,GAAG;AAAE,eAAS,oDAAiD;AAAG;AAAA,IAAQ;AACrG,QAAI,KAAK,aAAa,KAAK,SAAS;AAAE,eAAS,kCAA+B;AAAG;AAAA,IAAQ;AACzF,eAAW,IAAI;AACf,aAAS,EAAE;AACX,QAAI;AACF,YAAM,OAAO,MAAM,SAAS,MAAM,IAAI;AACtC,qBAAe,KAAK,YAAY;AAChC,WAAK,aAAa;AAAA,IACpB,SAAS,KAAc;AACrB,eAAS,eAAe,QAAQ,IAAI,UAAU,uBAAuB;AAAA,IACvE,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,aAAa,OAAO,SAAS,aAAa;AAC3D;;;AChDA,IAAAC,gBAAoC;AAW7B,SAAS,iBAAiB,MAA+B;AAC9D,QAAM,CAAC,SAAS,UAAU,QAAI,wBAA+B,IAAI;AACjE,QAAM,CAAC,UAAU,WAAW,QAAI,wBAA0B,CAAC,CAAC;AAC5D,QAAM,CAAC,SAAS,UAAU,QAAI,wBAA0B,CAAC,CAAC;AAC1D,QAAM,CAAC,UAAU,WAAW,QAAI,wBAA0B,CAAC,CAAC;AAC5D,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,IAAI;AAC3C,QAAM,CAAC,aAAa,cAAc,QAAI,wBAAS,EAAE;AACjD,QAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAS,KAAK;AAExD,QAAM,UAAU,MAAM;AACpB,UAAM,QAAQ,eAAe;AAC7B,QAAI,CAAC,OAAO;AACV,WAAK,kBAAkB;AACvB;AAAA,IACF;AACA,YAAQ,IAAI;AAAA,MACV,MAAM,KAAK,SAAS,KAAK;AAAA,MACzB,cAAc,KAAK,SAAS,OAAO,EAAE,UAAU,MAAM,SAAS,GAAG,CAAC;AAAA,MAClE,cAAc,KAAK,SAAS,OAAO,EAAE,SAAS,GAAG,CAAC;AAAA,MAClD,cAAc,KAAK,SAAS,KAAK;AAAA,IACnC,CAAC,EACE,KAAK,CAAC,CAAC,MAAM,IAAI,MAAM,IAAI,MAAM;AAChC,iBAAW,IAAI;AACf,kBAAY,EAAE;AACd,iBAAW,IAAI;AACf,kBAAY,IAAI;AAChB,iBAAW,KAAK;AAAA,IAClB,CAAC,EACA,MAAM,MAAM,KAAK,kBAAkB,CAAC;AAAA,EACzC;AAEA,+BAAU,MAAM;AACd,YAAQ;AAAA,EAEV,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,MAAM;AACzB,qBAAiB;AACjB,SAAK,YAAY;AAAA,EACnB;AAEA,QAAM,gBAAgB,OAAO,cAAsB;AACjD,UAAM,QAAQ,eAAe;AAC7B,QAAI,CAAC,MAAO;AACZ,qBAAiB,IAAI;AACrB,mBAAe,EAAE;AACjB,UAAM,SAAS,MAAM,gBAAgB,KAAK,SAAS,OAAO,SAAS;AACnE,QAAI,CAAC,OAAO,IAAI;AACd,qBAAe,OAAO,OAAO;AAC7B,uBAAiB,KAAK;AACtB;AAAA,IACF;AACA,YAAQ;AACR,qBAAiB,KAAK;AAAA,EACxB;AAEA,QAAM,oBAAoB,OAAO,WAAmB,WAAmB,YAAoB;AACzF,UAAM,QAAQ,eAAe;AAC7B,QAAI,CAAC,MAAO,QAAO;AACnB,qBAAiB,IAAI;AACrB,mBAAe,EAAE;AACjB,UAAM,SAAS,MAAM,oBAAoB,KAAK,SAAS,OAAO,WAAW,WAAW,OAAO;AAC3F,qBAAiB,KAAK;AACtB,QAAI,CAAC,OAAO,IAAI;AACd,qBAAe,OAAO,OAAO;AAC7B,aAAO;AAAA,IACT;AACA,YAAQ;AACR,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,SAAS,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,mBAAmB,CAAC;AAEzE,SAAO;AAAA,IACL;AAAA,IAAS;AAAA,IAAU;AAAA,IAAS;AAAA,IAAU;AAAA,IAAS;AAAA,IAAc;AAAA,IAC7D;AAAA,IAAe;AAAA,IAAmB;AAAA,IAAa;AAAA,IAAgB;AAAA,EACjE;AACF;","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","import { getMe } from \"./api\";\nimport type { ClientProfile } from \"./types\";\n\nconst TOKEN_KEY = \"client_token\";\n\nexport function getClientToken(): string | null {\n if (typeof window === \"undefined\") return null;\n return localStorage.getItem(TOKEN_KEY);\n}\n\nexport function setClientToken(token: string): void {\n if (typeof window === \"undefined\") return;\n localStorage.setItem(TOKEN_KEY, token);\n}\n\nexport function clearClientToken(): void {\n if (typeof window === \"undefined\") return;\n localStorage.removeItem(TOKEN_KEY);\n}\n\nexport async function fetchMe(apiBase: string, token: string): Promise<ClientProfile | null> {\n try {\n return await getMe(apiBase, token);\n } catch {\n return null;\n }\n}\n","export function getMondayOf(date: Date): Date {\n const d = new Date(date);\n const day = (d.getDay() + 6) % 7;\n d.setDate(d.getDate() - day);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\nexport function dateStr(d: Date): string {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`;\n}\n\nexport function formatMonthRange(monday: Date): string {\n const sunday = new Date(monday);\n sunday.setDate(monday.getDate() + 6);\n const opts: Intl.DateTimeFormatOptions = { day: \"numeric\", month: \"long\" };\n const start = monday.toLocaleDateString(\"es-CL\", opts);\n const end = sunday.toLocaleDateString(\"es-CL\", opts);\n return `${start} – ${end}`;\n}\n\nexport const DAY_NAMES = [\"Lun\", \"Mar\", \"Mié\", \"Jue\", \"Vie\", \"Sáb\", \"Dom\"];\nexport const DAY_NAMES_FULL = [\"Lunes\", \"Martes\", \"Miércoles\", \"Jueves\", \"Viernes\", \"Sábado\", \"Domingo\"];\n\nexport interface ProviderColor {\n bg: string;\n border: string;\n text: string;\n}\n\nexport const DEFAULT_PROVIDER_COLORS: ProviderColor[] = [\n { bg: \"#e8f5f0\", border: \"#2bbf8e\", text: \"#1a7a5a\" },\n { bg: \"#eef0fb\", border: \"#6b7de8\", text: \"#3d4fa8\" },\n { bg: \"#fdf3e8\", border: \"#e8a24b\", text: \"#a0600a\" },\n { bg: \"#fdeef4\", border: \"#e86b9a\", text: \"#a03060\" },\n];\n","import { useEffect, useState } from \"react\";\nimport {\n createBooking,\n getAvailableSlots,\n listLocations,\n listProviders,\n listServices,\n} from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport type {\n ApiConfig,\n BookingRecord,\n ClientFormValues,\n ClientProfile,\n Location,\n Provider,\n Service,\n Slot,\n} from \"../types\";\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClientForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n if (!form.rut.trim()) return \"Por favor ingresa tu RUT.\";\n return null;\n}\n\ninterface BuildBookingPayloadArgs {\n form: ClientFormValues;\n client: ClientProfile | null;\n selectedDate: string;\n selectedSlot: Slot;\n selectedSvc: string;\n selectedLoc: string;\n svcPrice?: string;\n defaultNotes?: string;\n overrides?: SubmitBookingOverrides;\n}\n\nfunction buildBookingPayload(args: BuildBookingPayloadArgs) {\n const { form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc } = args;\n const price = args.overrides?.price ?? args.svcPrice ?? \"0\";\n const notes = args.overrides?.notes ?? args.defaultNotes;\n return {\n start_time: `${selectedDate}T${selectedSlot.start_time}:00-04:00`,\n end_time: `${selectedDate}T${selectedSlot.end_time}:00-04:00`,\n service_id: selectedSvc,\n service_provider_id: selectedSlot.provider_id,\n location_id: selectedLoc,\n price,\n notes,\n // Ignored server-side unless a client/staff auth token proves the caller's\n // identity; for a logged-in client it's redundant but harmless to include.\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nexport interface UseBookingFlowOptions extends ApiConfig {\n onBookingComplete: (booking: BookingRecord) => void;\n /** Default notes attached to every booking (e.g. \"Reserva realizada desde sitio web X\"). */\n defaultNotes?: string;\n}\n\nexport interface SubmitBookingOverrides {\n /** Override the service's list price (e.g. magnolia's price-variant step). */\n price?: string;\n /** Override defaultNotes for this specific submission. */\n notes?: string;\n}\n\n/**\n * Shared booking-flow logic: catalog fetching (locations/services/providers/\n * slots), logged-in-client prefill, form validation, and submit-with-409-\n * handling. Does NOT own step navigation or app-specific filtering (e.g.\n * magnolia's category/price-variant logic) — those stay in the consuming\n * component, layered on top of the `services`/`providers` this hook returns.\n */\nexport function useBookingFlow(opts: UseBookingFlowOptions) {\n const [locations, setLocations] = useState<Location[]>([]);\n const [services, setServices] = useState<Service[]>([]);\n const [providers, setProviders] = useState<Provider[]>([]);\n const [slots, setSlots] = useState<Slot[]>([]);\n\n const [selectedLoc, setSelectedLoc] = useState(\"\");\n const [selectedSvc, setSelectedSvc] = useState(\"\");\n const [selectedProv, setSelectedProv] = useState(\"\");\n const [selectedDate, setSelectedDate] = useState(\"\");\n const [selectedSlot, setSelectedSlot] = useState<Slot | null>(null);\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n // Prefill from a logged-in client session, if any.\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n listLocations(opts)\n .then(setLocations)\n .catch(() => setError(\"Error cargando sucursales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!selectedLoc) return;\n listServices(opts)\n .then(setServices)\n .catch(() => setError(\"Error cargando servicios\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc]);\n\n useEffect(() => {\n if (!selectedSvc) return;\n listProviders(opts)\n .then(setProviders)\n .catch(() => setError(\"Error cargando profesionales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedSvc]);\n\n useEffect(() => {\n if (!selectedLoc || !selectedDate) return;\n setLoading(true);\n getAvailableSlots(opts, {\n locationId: selectedLoc,\n startDate: selectedDate,\n serviceId: selectedSvc || undefined,\n providerId: selectedProv || undefined,\n })\n .then(s => { setSlots(s); setLoading(false); })\n .catch(() => { setError(\"Error cargando horarios\"); setLoading(false); });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc, selectedSvc, selectedProv, selectedDate]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (overrides?: SubmitBookingOverrides) => {\n if (!selectedSlot) return;\n const validationError = validateClientForm(form);\n if (validationError) { setError(validationError); return; }\n\n setLoading(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.id === selectedSvc);\n const token = getClientToken();\n const payload = buildBookingPayload({\n form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc, overrides,\n svcPrice: svc?.price, defaultNotes: opts.defaultNotes,\n });\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar la reserva\");\n setLoading(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(result.message);\n if (result.conflict) setSelectedSlot(null);\n setLoading(false);\n return;\n }\n opts.onBookingComplete(result.booking);\n }\n\n return {\n locations, services, providers, slots,\n selectedLoc, setSelectedLoc,\n selectedSvc, setSelectedSvc,\n selectedProv, setSelectedProv,\n selectedDate, setSelectedDate,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n loading, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { createBooking, getAvailableSlots, listLocations, listServices } from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport { dateStr, DEFAULT_PROVIDER_COLORS, getMondayOf, type ProviderColor } from \"../dateUtils\";\nimport type { ApiConfig, ClientFormValues, ClientProfile, Service, Slot } from \"../types\";\n\nexport interface SelectedClassSlot {\n slot: Slot;\n date: string;\n}\n\nexport interface UseClassScheduleOptions extends ApiConfig {\n onBookingComplete: () => void;\n colors?: ProviderColor[];\n}\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClassForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n return null;\n}\n\nfunction buildClassBookingPayload(\n form: ClientFormValues,\n client: ClientProfile | null,\n selectedSlot: SelectedClassSlot,\n svc: Service | undefined,\n locationId: string\n) {\n return {\n start_time: `${selectedSlot.date}T${selectedSlot.slot.start_time}:00-04:00`,\n end_time: `${selectedSlot.date}T${selectedSlot.slot.end_time}:00-04:00`,\n service_id: svc?.id ?? \"\",\n service_provider_id: selectedSlot.slot.provider_id,\n location_id: locationId,\n price: svc?.price || \"0\",\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nfunction resolveConflictMessage(result: { conflict: boolean; message: string }): string {\n return result.conflict\n ? \"Ese cupo ya fue tomado por otra persona. Cierra esta ventana y elige otro horario.\"\n : result.message;\n}\n\n/**\n * Shared weekly group-class schedule logic: week-of-slots fetching, provider\n * color-palette assignment, and submit-with-409-handling. The week-grid table\n * JSX and modal markup stay in the consuming component — this hook only owns\n * data and state transitions.\n */\nexport function useClassSchedule(opts: UseClassScheduleOptions) {\n const colors = opts.colors ?? DEFAULT_PROVIDER_COLORS;\n\n const [monday, setMonday] = useState<Date>(() => getMondayOf(new Date()));\n const [slotsByDay, setSlotsByDay] = useState<Record<string, Slot[]>>({});\n const [services, setServices] = useState<Service[]>([]);\n const [locationId, setLocationId] = useState(\"\");\n const [loading, setLoading] = useState(true);\n const [selectedSlot, setSelectedSlot] = useState<SelectedClassSlot | null>(null);\n const [providerColorMap, setProviderColorMap] = useState<Record<string, ProviderColor>>({});\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n useEffect(() => {\n Promise.all([listLocations(opts), listServices(opts, 50)])\n .then(([locs, svcs]) => {\n if (locs.length) setLocationId(locs[0].id);\n setServices(svcs);\n })\n .catch(() => setError(\"Error cargando datos\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const loadWeek = useCallback(async (mon: Date, locId: string) => {\n if (!locId) return;\n setLoading(true);\n const days = Array.from({ length: 7 }, (_, i) => {\n const d = new Date(mon);\n d.setDate(mon.getDate() + i);\n return d;\n });\n\n const results = await Promise.all(\n days.map(async d => {\n const ds = dateStr(d);\n try {\n const slots = await getAvailableSlots(opts, { locationId: locId, startDate: ds });\n return { date: ds, slots };\n } catch {\n return { date: ds, slots: [] as Slot[] };\n }\n })\n );\n\n const map: Record<string, Slot[]> = {};\n const colorMap: Record<string, ProviderColor> = {};\n let colorIdx = 0;\n results.forEach(({ date, slots }) => {\n map[date] = slots;\n slots.forEach(s => {\n if (!colorMap[s.provider_id]) {\n colorMap[s.provider_id] = colors[colorIdx % colors.length];\n colorIdx++;\n }\n });\n });\n\n setSlotsByDay(map);\n setProviderColorMap(prev => ({ ...prev, ...colorMap }));\n setLoading(false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (locationId) loadWeek(monday, locationId);\n }, [monday, locationId, loadWeek]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!selectedSlot) return;\n const validationError = validateClassForm(form);\n if (validationError) { setError(validationError); return; }\n setSubmitting(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.name === selectedSlot.slot.service_name);\n const token = getClientToken();\n const payload = buildClassBookingPayload(form, client, selectedSlot, svc, locationId);\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar\");\n setSubmitting(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(resolveConflictMessage(result));\n setSubmitting(false);\n return;\n }\n opts.onBookingComplete();\n }\n\n return {\n monday, setMonday,\n slotsByDay, loading, providerColorMap,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n submitting, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useState } from \"react\";\nimport { loginWithGoogle, sendMagicLink } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\ndeclare global {\n interface Window {\n google?: {\n accounts: {\n id: {\n initialize: (config: { client_id: string; callback: (response: { credential: string }) => void }) => void;\n prompt: () => void;\n };\n };\n };\n }\n}\n\nexport interface UseMagicLinkAuthOptions extends ApiConfig {\n googleClientId?: string;\n frontendUrl: string;\n onGoogleLoggedIn: () => void;\n}\n\nexport type MagicLinkStep = \"email\" | \"sent\";\n\nexport function useMagicLinkAuth(opts: UseMagicLinkAuthOptions) {\n const [email, setEmail] = useState(\"\");\n // Optional — only relevant on a signup-style form (e.g. registro pages)\n // that collects a bit more than login does. Login pages can ignore these.\n const [firstName, setFirstName] = useState(\"\");\n const [lastName, setLastName] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [rut, setRut] = useState(\"\");\n const [step, setStep] = useState<MagicLinkStep>(\"email\");\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const handleMagicLink = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!email.trim() || !/\\S+@\\S+\\.\\S+/.test(email)) {\n setError(\"Ingresa un email válido.\");\n return;\n }\n setLoading(true);\n setError(\"\");\n try {\n await sendMagicLink(opts, email, opts.frontendUrl, {\n firstName: firstName || undefined,\n lastName: lastName || undefined,\n phone: phone || undefined,\n rut: rut || undefined,\n });\n setStep(\"sent\");\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error enviando el link.\");\n } finally {\n setLoading(false);\n }\n };\n\n const handleGoogle = () => {\n if (!opts.googleClientId || typeof window === \"undefined\" || !window.google) return;\n window.google.accounts.id.initialize({\n client_id: opts.googleClientId,\n callback: async (response: { credential: string }) => {\n setLoading(true);\n try {\n const data = await loginWithGoogle(opts, response.credential);\n setClientToken(data.access_token);\n opts.onGoogleLoggedIn();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error con Google.\");\n setLoading(false);\n }\n },\n });\n window.google.accounts.id.prompt();\n };\n\n const reset = () => {\n setStep(\"email\");\n setError(\"\");\n };\n\n return {\n email, setEmail,\n firstName, setFirstName,\n lastName, setLastName,\n phone, setPhone,\n rut, setRut,\n step, error, loading, handleMagicLink, handleGoogle, reset,\n };\n}\n","import { useState } from \"react\";\nimport { register } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\nexport interface RegisterFormValues {\n firstName: string;\n lastName: string;\n email: string;\n phone: string;\n password: string;\n confirm: string;\n}\n\nconst EMPTY: RegisterFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", password: \"\", confirm: \"\" };\n\nexport interface UseRegisterFormOptions extends ApiConfig {\n onRegistered: () => void;\n}\n\nexport function useRegisterForm(opts: UseRegisterFormOptions) {\n const [form, setForm] = useState<RegisterFormValues>(EMPTY);\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const updateField = (fields: Partial<RegisterFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const handleSubmit = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!form.firstName.trim()) { setError(\"Ingresa tu nombre.\"); return; }\n if (!form.lastName.trim()) { setError(\"Ingresa tu apellido.\"); return; }\n if (!form.email.trim()) { setError(\"Ingresa tu email.\"); return; }\n if (form.password.length < 6) { setError(\"La contraseña debe tener al menos 6 caracteres.\"); return; }\n if (form.password !== form.confirm) { setError(\"Las contraseñas no coinciden.\"); return; }\n setLoading(true);\n setError(\"\");\n try {\n const data = await register(opts, form);\n setClientToken(data.access_token);\n opts.onRegistered();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al registrarse.\");\n } finally {\n setLoading(false);\n }\n };\n\n return { form, updateField, error, loading, handleSubmit };\n}\n","import { useEffect, useState } from \"react\";\nimport { cancelMyBooking, getMe, getMyBookings, getMyPackages, rescheduleMyBooking } from \"../api\";\nimport { clearClientToken, getClientToken } from \"../clientAuth\";\nimport type { BookingRecord, ClientProfile, PackageRecord } from \"../types\";\n\nexport interface UseClientAccountOptions {\n apiBase: string;\n onUnauthenticated: () => void;\n onLoggedOut: () => void;\n}\n\nexport function useClientAccount(opts: UseClientAccountOptions) {\n const [profile, setProfile] = useState<ClientProfile | null>(null);\n const [upcoming, setUpcoming] = useState<BookingRecord[]>([]);\n const [history, setHistory] = useState<BookingRecord[]>([]);\n const [packages, setPackages] = useState<PackageRecord[]>([]);\n const [loading, setLoading] = useState(true);\n const [actionError, setActionError] = useState(\"\");\n const [actionLoading, setActionLoading] = useState(false);\n\n const loadAll = () => {\n const token = getClientToken();\n if (!token) {\n opts.onUnauthenticated();\n return;\n }\n Promise.all([\n getMe(opts.apiBase, token),\n getMyBookings(opts.apiBase, token, { upcoming: true, perPage: 10 }),\n getMyBookings(opts.apiBase, token, { perPage: 20 }),\n getMyPackages(opts.apiBase, token),\n ])\n .then(([prof, up, hist, pkgs]) => {\n setProfile(prof);\n setUpcoming(up);\n setHistory(hist);\n setPackages(pkgs);\n setLoading(false);\n })\n .catch(() => opts.onUnauthenticated());\n };\n\n useEffect(() => {\n loadAll();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const handleLogout = () => {\n clearClientToken();\n opts.onLoggedOut();\n };\n\n const cancelBooking = async (bookingId: string) => {\n const token = getClientToken();\n if (!token) return;\n setActionLoading(true);\n setActionError(\"\");\n const result = await cancelMyBooking(opts.apiBase, token, bookingId);\n if (!result.ok) {\n setActionError(result.message);\n setActionLoading(false);\n return;\n }\n loadAll();\n setActionLoading(false);\n };\n\n const rescheduleBooking = async (bookingId: string, startTime: string, endTime: string) => {\n const token = getClientToken();\n if (!token) return false;\n setActionLoading(true);\n setActionError(\"\");\n const result = await rescheduleMyBooking(opts.apiBase, token, bookingId, startTime, endTime);\n setActionLoading(false);\n if (!result.ok) {\n setActionError(result.message);\n return false;\n }\n loadAll();\n return true;\n };\n\n const totalCredits = packages.reduce((s, p) => s + p.remaining_credits, 0);\n\n return {\n profile, upcoming, history, packages, loading, totalCredits, handleLogout,\n cancelBooking, rescheduleBooking, actionError, setActionError, actionLoading,\n };\n}\n"],"mappings":"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","names":["import_react","EMPTY_FORM","isValidPhone","import_react","import_react","import_react"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -42,7 +42,10 @@ interface WaitlistEntry {
|
|
|
42
42
|
location_id: string;
|
|
43
43
|
class_session_id: string | null;
|
|
44
44
|
date: string | null;
|
|
45
|
+
date_until: string | null;
|
|
46
|
+
status: "waiting" | "offered" | "confirmed" | "expired";
|
|
45
47
|
notified_at: string | null;
|
|
48
|
+
offer_expires_at: string | null;
|
|
46
49
|
created_at: string;
|
|
47
50
|
}
|
|
48
51
|
interface ClientProfile {
|
|
@@ -172,6 +175,7 @@ declare function joinWaitlist(apiBase: string, token: string, params: {
|
|
|
172
175
|
locationId: string;
|
|
173
176
|
providerId?: string;
|
|
174
177
|
date?: string;
|
|
178
|
+
dateUntil?: string;
|
|
175
179
|
classSessionId?: string;
|
|
176
180
|
}): Promise<WaitlistEntry>;
|
|
177
181
|
declare function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,10 @@ interface WaitlistEntry {
|
|
|
42
42
|
location_id: string;
|
|
43
43
|
class_session_id: string | null;
|
|
44
44
|
date: string | null;
|
|
45
|
+
date_until: string | null;
|
|
46
|
+
status: "waiting" | "offered" | "confirmed" | "expired";
|
|
45
47
|
notified_at: string | null;
|
|
48
|
+
offer_expires_at: string | null;
|
|
46
49
|
created_at: string;
|
|
47
50
|
}
|
|
48
51
|
interface ClientProfile {
|
|
@@ -172,6 +175,7 @@ declare function joinWaitlist(apiBase: string, token: string, params: {
|
|
|
172
175
|
locationId: string;
|
|
173
176
|
providerId?: string;
|
|
174
177
|
date?: string;
|
|
178
|
+
dateUntil?: string;
|
|
175
179
|
classSessionId?: string;
|
|
176
180
|
}): Promise<WaitlistEntry>;
|
|
177
181
|
declare function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]>;
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api.ts","../src/clientAuth.ts","../src/dateUtils.ts","../src/hooks/useBookingFlow.ts","../src/hooks/useClassSchedule.ts","../src/hooks/useMagicLinkAuth.ts","../src/hooks/useRegisterForm.ts","../src/hooks/useClientAccount.ts"],"sourcesContent":["import type {\n ApiConfig,\n BookingCreateInput,\n BookingRecord,\n BookingResult,\n ClientFormValues,\n ClientProfile,\n Location,\n PackageRecord,\n Provider,\n Service,\n Slot,\n WaitlistEntry,\n} from \"./types\";\n\nfunction headers(cfg: ApiConfig, withJson = false): Record<string, string> {\n const h: Record<string, string> = { \"X-API-Key\": cfg.apiKey };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nfunction authHeaders(token: string, withJson = false): Record<string, string> {\n const h: Record<string, string> = { Authorization: `Bearer ${token}` };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nexport async function listLocations(cfg: ApiConfig): Promise<Location[]> {\n const res = await fetch(`${cfg.apiBase}/v1/locations`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listServices(cfg: ApiConfig, perPage = 100): Promise<Service[]> {\n const res = await fetch(`${cfg.apiBase}/v1/services?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listProviders(cfg: ApiConfig, perPage = 100): Promise<Provider[]> {\n const res = await fetch(`${cfg.apiBase}/v1/providers?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getAvailableSlots(\n cfg: ApiConfig,\n params: { locationId: string; startDate: string; serviceId?: string; providerId?: string }\n): Promise<Slot[]> {\n const q = new URLSearchParams({ location_id: params.locationId, start_date: params.startDate });\n if (params.serviceId) q.set(\"service_id\", params.serviceId);\n if (params.providerId) q.set(\"provider_id\", params.providerId);\n const res = await fetch(`${cfg.apiBase}/v1/available-slots?${q.toString()}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data?.slots || [];\n}\n\nexport async function createClient(cfg: ApiConfig, form: ClientFormValues): Promise<{ id: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/clients`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone,\n rut: form.rut || undefined,\n }),\n });\n if (!res.ok) throw new Error(\"Error registrando datos\");\n return res.json();\n}\n\nexport async function createBooking(\n cfg: ApiConfig,\n input: BookingCreateInput,\n clientToken?: string\n): Promise<BookingResult> {\n // A logged-in client's token takes priority so the server attributes the\n // booking to their account rather than treating it as anonymous — see\n // create_booking in routes/bookings.py, which ignores any client_id sent\n // by an unauthenticated caller.\n const reqHeaders = headers(cfg, true);\n if (clientToken) reqHeaders.Authorization = `Bearer ${clientToken}`;\n const res = await fetch(`${cfg.apiBase}/v1/bookings`, {\n method: \"POST\",\n headers: reqHeaders,\n body: JSON.stringify(input),\n });\n if (res.status === 409) {\n const data = await res.json().catch(() => ({}));\n return { ok: false, conflict: true, message: data.detail || \"Ese horario ya no está disponible.\" };\n }\n if (!res.ok) {\n return { ok: false, conflict: false, message: \"Error creando la reserva. Por favor intenta nuevamente.\" };\n }\n return { ok: true, booking: await res.json() };\n}\n\nexport async function sendMagicLink(\n cfg: ApiConfig,\n email: string,\n frontendUrl: string,\n profile?: { firstName?: string; lastName?: string; phone?: string; rut?: string }\n): Promise<void> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n email: email.trim().toLowerCase(),\n frontend_url: frontendUrl,\n first_name: profile?.firstName,\n last_name: profile?.lastName,\n phone: profile?.phone,\n rut: profile?.rut,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error enviando el link.\");\n}\n\nexport async function verifyMagicLink(cfg: ApiConfig, token: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link/verify`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ token }),\n });\n const data = await res.json();\n if (!data.access_token) throw new Error(data.detail || \"Link inválido.\");\n return data;\n}\n\nexport async function loginWithGoogle(cfg: ApiConfig, credential: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/google`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ credential }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error con Google.\");\n return data;\n}\n\nexport async function register(\n cfg: ApiConfig,\n form: { firstName: string; lastName: string; email: string; phone?: string; password: string }\n): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/register`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone || undefined,\n password: form.password,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error al registrarse.\");\n return data;\n}\n\nexport async function getMe(apiBase: string, token: string): Promise<ClientProfile> {\n const res = await fetch(`${apiBase}/v1/me`, { headers: authHeaders(token) });\n return res.json();\n}\n\nexport async function getMyBookings(\n apiBase: string,\n token: string,\n params?: { upcoming?: boolean; perPage?: number }\n): Promise<BookingRecord[]> {\n const q = new URLSearchParams();\n if (params?.upcoming) q.set(\"upcoming\", \"true\");\n q.set(\"per_page\", String(params?.perPage ?? 20));\n const res = await fetch(`${apiBase}/v1/me/bookings?${q.toString()}`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getMyPackages(apiBase: string, token: string): Promise<PackageRecord[]> {\n const res = await fetch(`${apiBase}/v1/me/packages`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\n/** Result of a client cancelling/rescheduling their own booking — callers\n * branch on `.ok` to show the server's specific reason (cutoff window,\n * overlap, etc.) instead of a generic error. */\nexport type MyBookingActionResult =\n | { ok: true; booking: BookingRecord }\n | { ok: false; message: string };\n\nexport async function cancelMyBooking(\n apiBase: string, token: string, bookingId: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/cancel`, {\n method: \"POST\",\n headers: authHeaders(token),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo cancelar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function rescheduleMyBooking(\n apiBase: string, token: string, bookingId: string, startTime: string, endTime: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/reschedule`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({ start_time: startTime, end_time: endTime }),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo reprogramar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function joinWaitlist(\n apiBase: string,\n token: string,\n params: { serviceId: string; locationId: string; providerId?: string; date?: string; classSessionId?: string }\n): Promise<WaitlistEntry> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({\n service_id: params.serviceId,\n location_id: params.locationId,\n provider_id: params.providerId,\n date: params.date,\n class_session_id: params.classSessionId,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"No se pudo unir a la lista de espera.\");\n return data;\n}\n\nexport async function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void> {\n await fetch(`${apiBase}/v1/me/waitlist/${entryId}`, {\n method: \"DELETE\",\n headers: authHeaders(token),\n });\n}\n","import { getMe } from \"./api\";\nimport type { ClientProfile } from \"./types\";\n\nconst TOKEN_KEY = \"client_token\";\n\nexport function getClientToken(): string | null {\n if (typeof window === \"undefined\") return null;\n return localStorage.getItem(TOKEN_KEY);\n}\n\nexport function setClientToken(token: string): void {\n if (typeof window === \"undefined\") return;\n localStorage.setItem(TOKEN_KEY, token);\n}\n\nexport function clearClientToken(): void {\n if (typeof window === \"undefined\") return;\n localStorage.removeItem(TOKEN_KEY);\n}\n\nexport async function fetchMe(apiBase: string, token: string): Promise<ClientProfile | null> {\n try {\n return await getMe(apiBase, token);\n } catch {\n return null;\n }\n}\n","export function getMondayOf(date: Date): Date {\n const d = new Date(date);\n const day = (d.getDay() + 6) % 7;\n d.setDate(d.getDate() - day);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\nexport function dateStr(d: Date): string {\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`;\n}\n\nexport function formatMonthRange(monday: Date): string {\n const sunday = new Date(monday);\n sunday.setDate(monday.getDate() + 6);\n const opts: Intl.DateTimeFormatOptions = { day: \"numeric\", month: \"long\" };\n const start = monday.toLocaleDateString(\"es-CL\", opts);\n const end = sunday.toLocaleDateString(\"es-CL\", opts);\n return `${start} – ${end}`;\n}\n\nexport const DAY_NAMES = [\"Lun\", \"Mar\", \"Mié\", \"Jue\", \"Vie\", \"Sáb\", \"Dom\"];\nexport const DAY_NAMES_FULL = [\"Lunes\", \"Martes\", \"Miércoles\", \"Jueves\", \"Viernes\", \"Sábado\", \"Domingo\"];\n\nexport interface ProviderColor {\n bg: string;\n border: string;\n text: string;\n}\n\nexport const DEFAULT_PROVIDER_COLORS: ProviderColor[] = [\n { bg: \"#e8f5f0\", border: \"#2bbf8e\", text: \"#1a7a5a\" },\n { bg: \"#eef0fb\", border: \"#6b7de8\", text: \"#3d4fa8\" },\n { bg: \"#fdf3e8\", border: \"#e8a24b\", text: \"#a0600a\" },\n { bg: \"#fdeef4\", border: \"#e86b9a\", text: \"#a03060\" },\n];\n","import { useEffect, useState } from \"react\";\nimport {\n createBooking,\n getAvailableSlots,\n listLocations,\n listProviders,\n listServices,\n} from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport type {\n ApiConfig,\n BookingRecord,\n ClientFormValues,\n ClientProfile,\n Location,\n Provider,\n Service,\n Slot,\n} from \"../types\";\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClientForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n if (!form.rut.trim()) return \"Por favor ingresa tu RUT.\";\n return null;\n}\n\ninterface BuildBookingPayloadArgs {\n form: ClientFormValues;\n client: ClientProfile | null;\n selectedDate: string;\n selectedSlot: Slot;\n selectedSvc: string;\n selectedLoc: string;\n svcPrice?: string;\n defaultNotes?: string;\n overrides?: SubmitBookingOverrides;\n}\n\nfunction buildBookingPayload(args: BuildBookingPayloadArgs) {\n const { form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc } = args;\n const price = args.overrides?.price ?? args.svcPrice ?? \"0\";\n const notes = args.overrides?.notes ?? args.defaultNotes;\n return {\n start_time: `${selectedDate}T${selectedSlot.start_time}:00-04:00`,\n end_time: `${selectedDate}T${selectedSlot.end_time}:00-04:00`,\n service_id: selectedSvc,\n service_provider_id: selectedSlot.provider_id,\n location_id: selectedLoc,\n price,\n notes,\n // Ignored server-side unless a client/staff auth token proves the caller's\n // identity; for a logged-in client it's redundant but harmless to include.\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nexport interface UseBookingFlowOptions extends ApiConfig {\n onBookingComplete: (booking: BookingRecord) => void;\n /** Default notes attached to every booking (e.g. \"Reserva realizada desde sitio web X\"). */\n defaultNotes?: string;\n}\n\nexport interface SubmitBookingOverrides {\n /** Override the service's list price (e.g. magnolia's price-variant step). */\n price?: string;\n /** Override defaultNotes for this specific submission. */\n notes?: string;\n}\n\n/**\n * Shared booking-flow logic: catalog fetching (locations/services/providers/\n * slots), logged-in-client prefill, form validation, and submit-with-409-\n * handling. Does NOT own step navigation or app-specific filtering (e.g.\n * magnolia's category/price-variant logic) — those stay in the consuming\n * component, layered on top of the `services`/`providers` this hook returns.\n */\nexport function useBookingFlow(opts: UseBookingFlowOptions) {\n const [locations, setLocations] = useState<Location[]>([]);\n const [services, setServices] = useState<Service[]>([]);\n const [providers, setProviders] = useState<Provider[]>([]);\n const [slots, setSlots] = useState<Slot[]>([]);\n\n const [selectedLoc, setSelectedLoc] = useState(\"\");\n const [selectedSvc, setSelectedSvc] = useState(\"\");\n const [selectedProv, setSelectedProv] = useState(\"\");\n const [selectedDate, setSelectedDate] = useState(\"\");\n const [selectedSlot, setSelectedSlot] = useState<Slot | null>(null);\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n // Prefill from a logged-in client session, if any.\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n listLocations(opts)\n .then(setLocations)\n .catch(() => setError(\"Error cargando sucursales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (!selectedLoc) return;\n listServices(opts)\n .then(setServices)\n .catch(() => setError(\"Error cargando servicios\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc]);\n\n useEffect(() => {\n if (!selectedSvc) return;\n listProviders(opts)\n .then(setProviders)\n .catch(() => setError(\"Error cargando profesionales\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedSvc]);\n\n useEffect(() => {\n if (!selectedLoc || !selectedDate) return;\n setLoading(true);\n getAvailableSlots(opts, {\n locationId: selectedLoc,\n startDate: selectedDate,\n serviceId: selectedSvc || undefined,\n providerId: selectedProv || undefined,\n })\n .then(s => { setSlots(s); setLoading(false); })\n .catch(() => { setError(\"Error cargando horarios\"); setLoading(false); });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedLoc, selectedSvc, selectedProv, selectedDate]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (overrides?: SubmitBookingOverrides) => {\n if (!selectedSlot) return;\n const validationError = validateClientForm(form);\n if (validationError) { setError(validationError); return; }\n\n setLoading(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.id === selectedSvc);\n const token = getClientToken();\n const payload = buildBookingPayload({\n form, client, selectedDate, selectedSlot, selectedSvc, selectedLoc, overrides,\n svcPrice: svc?.price, defaultNotes: opts.defaultNotes,\n });\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar la reserva\");\n setLoading(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(result.message);\n if (result.conflict) setSelectedSlot(null);\n setLoading(false);\n return;\n }\n opts.onBookingComplete(result.booking);\n }\n\n return {\n locations, services, providers, slots,\n selectedLoc, setSelectedLoc,\n selectedSvc, setSelectedSvc,\n selectedProv, setSelectedProv,\n selectedDate, setSelectedDate,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n loading, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { createBooking, getAvailableSlots, listLocations, listServices } from \"../api\";\nimport { fetchMe, getClientToken } from \"../clientAuth\";\nimport { dateStr, DEFAULT_PROVIDER_COLORS, getMondayOf, type ProviderColor } from \"../dateUtils\";\nimport type { ApiConfig, ClientFormValues, ClientProfile, Service, Slot } from \"../types\";\n\nexport interface SelectedClassSlot {\n slot: Slot;\n date: string;\n}\n\nexport interface UseClassScheduleOptions extends ApiConfig {\n onBookingComplete: () => void;\n colors?: ProviderColor[];\n}\n\nconst EMPTY_FORM: ClientFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", rut: \"\" };\n\nfunction isValidPhone(phone: string): boolean {\n return phone.replace(/[^0-9]/g, \"\").length >= 8;\n}\n\nfunction validateClassForm(form: ClientFormValues): string | null {\n if (!form.firstName.trim()) return \"Por favor ingresa tu nombre.\";\n if (!form.lastName.trim()) return \"Por favor ingresa tu apellido.\";\n if (!form.email.trim() || !/\\S+@\\S+\\.\\S+/.test(form.email)) return \"Por favor ingresa un email válido.\";\n if (!form.phone.trim() || !isValidPhone(form.phone)) return \"Por favor ingresa un teléfono válido.\";\n return null;\n}\n\nfunction buildClassBookingPayload(\n form: ClientFormValues,\n client: ClientProfile | null,\n selectedSlot: SelectedClassSlot,\n svc: Service | undefined,\n locationId: string\n) {\n return {\n start_time: `${selectedSlot.date}T${selectedSlot.slot.start_time}:00-04:00`,\n end_time: `${selectedSlot.date}T${selectedSlot.slot.end_time}:00-04:00`,\n service_id: svc?.id ?? \"\",\n service_provider_id: selectedSlot.slot.provider_id,\n location_id: locationId,\n price: svc?.price || \"0\",\n client_id: client?.id,\n client_first_name: form.firstName,\n client_last_name: form.lastName,\n client_email: form.email,\n client_phone: form.phone,\n client_rut: form.rut || undefined,\n };\n}\n\nfunction resolveConflictMessage(result: { conflict: boolean; message: string }): string {\n return result.conflict\n ? \"Ese cupo ya fue tomado por otra persona. Cierra esta ventana y elige otro horario.\"\n : result.message;\n}\n\n/**\n * Shared weekly group-class schedule logic: week-of-slots fetching, provider\n * color-palette assignment, and submit-with-409-handling. The week-grid table\n * JSX and modal markup stay in the consuming component — this hook only owns\n * data and state transitions.\n */\nexport function useClassSchedule(opts: UseClassScheduleOptions) {\n const colors = opts.colors ?? DEFAULT_PROVIDER_COLORS;\n\n const [monday, setMonday] = useState<Date>(() => getMondayOf(new Date()));\n const [slotsByDay, setSlotsByDay] = useState<Record<string, Slot[]>>({});\n const [services, setServices] = useState<Service[]>([]);\n const [locationId, setLocationId] = useState(\"\");\n const [loading, setLoading] = useState(true);\n const [selectedSlot, setSelectedSlot] = useState<SelectedClassSlot | null>(null);\n const [providerColorMap, setProviderColorMap] = useState<Record<string, ProviderColor>>({});\n\n const [form, setForm] = useState<ClientFormValues>(EMPTY_FORM);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState(\"\");\n const [client, setClient] = useState<ClientProfile | null>(null);\n\n useEffect(() => {\n Promise.all([listLocations(opts), listServices(opts, 50)])\n .then(([locs, svcs]) => {\n if (locs.length) setLocationId(locs[0].id);\n setServices(svcs);\n })\n .catch(() => setError(\"Error cargando datos\"));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n const token = getClientToken();\n if (!token) return;\n fetchMe(opts.apiBase, token).then(profile => {\n if (!profile) return;\n setClient(profile);\n setForm(f => ({\n ...f,\n firstName: profile.first_name || f.firstName,\n lastName: profile.last_name || f.lastName,\n email: profile.email || f.email,\n phone: profile.phone || f.phone,\n rut: profile.rut || f.rut,\n }));\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const loadWeek = useCallback(async (mon: Date, locId: string) => {\n if (!locId) return;\n setLoading(true);\n const days = Array.from({ length: 7 }, (_, i) => {\n const d = new Date(mon);\n d.setDate(mon.getDate() + i);\n return d;\n });\n\n const results = await Promise.all(\n days.map(async d => {\n const ds = dateStr(d);\n try {\n const slots = await getAvailableSlots(opts, { locationId: locId, startDate: ds });\n return { date: ds, slots };\n } catch {\n return { date: ds, slots: [] as Slot[] };\n }\n })\n );\n\n const map: Record<string, Slot[]> = {};\n const colorMap: Record<string, ProviderColor> = {};\n let colorIdx = 0;\n results.forEach(({ date, slots }) => {\n map[date] = slots;\n slots.forEach(s => {\n if (!colorMap[s.provider_id]) {\n colorMap[s.provider_id] = colors[colorIdx % colors.length];\n colorIdx++;\n }\n });\n });\n\n setSlotsByDay(map);\n setProviderColorMap(prev => ({ ...prev, ...colorMap }));\n setLoading(false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n if (locationId) loadWeek(monday, locationId);\n }, [monday, locationId, loadWeek]);\n\n const updateForm = (fields: Partial<ClientFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const submitBooking = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!selectedSlot) return;\n const validationError = validateClassForm(form);\n if (validationError) { setError(validationError); return; }\n setSubmitting(true);\n setError(\"\");\n try {\n const svc = services.find(s => s.name === selectedSlot.slot.service_name);\n const token = getClientToken();\n const payload = buildClassBookingPayload(form, client, selectedSlot, svc, locationId);\n const result = await createBooking(opts, payload, token || undefined);\n handleSubmitResult(result);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al procesar\");\n setSubmitting(false);\n }\n };\n\n function handleSubmitResult(result: Awaited<ReturnType<typeof createBooking>>) {\n if (!result.ok) {\n setError(resolveConflictMessage(result));\n setSubmitting(false);\n return;\n }\n opts.onBookingComplete();\n }\n\n return {\n monday, setMonday,\n slotsByDay, loading, providerColorMap,\n selectedSlot, setSelectedSlot,\n form, updateForm,\n submitting, error, setError,\n client,\n submitBooking,\n };\n}\n","import { useState } from \"react\";\nimport { loginWithGoogle, sendMagicLink } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\ndeclare global {\n interface Window {\n google?: {\n accounts: {\n id: {\n initialize: (config: { client_id: string; callback: (response: { credential: string }) => void }) => void;\n prompt: () => void;\n };\n };\n };\n }\n}\n\nexport interface UseMagicLinkAuthOptions extends ApiConfig {\n googleClientId?: string;\n frontendUrl: string;\n onGoogleLoggedIn: () => void;\n}\n\nexport type MagicLinkStep = \"email\" | \"sent\";\n\nexport function useMagicLinkAuth(opts: UseMagicLinkAuthOptions) {\n const [email, setEmail] = useState(\"\");\n // Optional — only relevant on a signup-style form (e.g. registro pages)\n // that collects a bit more than login does. Login pages can ignore these.\n const [firstName, setFirstName] = useState(\"\");\n const [lastName, setLastName] = useState(\"\");\n const [phone, setPhone] = useState(\"\");\n const [rut, setRut] = useState(\"\");\n const [step, setStep] = useState<MagicLinkStep>(\"email\");\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const handleMagicLink = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!email.trim() || !/\\S+@\\S+\\.\\S+/.test(email)) {\n setError(\"Ingresa un email válido.\");\n return;\n }\n setLoading(true);\n setError(\"\");\n try {\n await sendMagicLink(opts, email, opts.frontendUrl, {\n firstName: firstName || undefined,\n lastName: lastName || undefined,\n phone: phone || undefined,\n rut: rut || undefined,\n });\n setStep(\"sent\");\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error enviando el link.\");\n } finally {\n setLoading(false);\n }\n };\n\n const handleGoogle = () => {\n if (!opts.googleClientId || typeof window === \"undefined\" || !window.google) return;\n window.google.accounts.id.initialize({\n client_id: opts.googleClientId,\n callback: async (response: { credential: string }) => {\n setLoading(true);\n try {\n const data = await loginWithGoogle(opts, response.credential);\n setClientToken(data.access_token);\n opts.onGoogleLoggedIn();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error con Google.\");\n setLoading(false);\n }\n },\n });\n window.google.accounts.id.prompt();\n };\n\n const reset = () => {\n setStep(\"email\");\n setError(\"\");\n };\n\n return {\n email, setEmail,\n firstName, setFirstName,\n lastName, setLastName,\n phone, setPhone,\n rut, setRut,\n step, error, loading, handleMagicLink, handleGoogle, reset,\n };\n}\n","import { useState } from \"react\";\nimport { register } from \"../api\";\nimport { setClientToken } from \"../clientAuth\";\nimport type { ApiConfig } from \"../types\";\n\nexport interface RegisterFormValues {\n firstName: string;\n lastName: string;\n email: string;\n phone: string;\n password: string;\n confirm: string;\n}\n\nconst EMPTY: RegisterFormValues = { firstName: \"\", lastName: \"\", email: \"\", phone: \"\", password: \"\", confirm: \"\" };\n\nexport interface UseRegisterFormOptions extends ApiConfig {\n onRegistered: () => void;\n}\n\nexport function useRegisterForm(opts: UseRegisterFormOptions) {\n const [form, setForm] = useState<RegisterFormValues>(EMPTY);\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const updateField = (fields: Partial<RegisterFormValues>) => setForm(f => ({ ...f, ...fields }));\n\n const handleSubmit = async (e: { preventDefault: () => void }) => {\n e.preventDefault();\n if (!form.firstName.trim()) { setError(\"Ingresa tu nombre.\"); return; }\n if (!form.lastName.trim()) { setError(\"Ingresa tu apellido.\"); return; }\n if (!form.email.trim()) { setError(\"Ingresa tu email.\"); return; }\n if (form.password.length < 6) { setError(\"La contraseña debe tener al menos 6 caracteres.\"); return; }\n if (form.password !== form.confirm) { setError(\"Las contraseñas no coinciden.\"); return; }\n setLoading(true);\n setError(\"\");\n try {\n const data = await register(opts, form);\n setClientToken(data.access_token);\n opts.onRegistered();\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : \"Error al registrarse.\");\n } finally {\n setLoading(false);\n }\n };\n\n return { form, updateField, error, loading, handleSubmit };\n}\n","import { useEffect, useState } from \"react\";\nimport { cancelMyBooking, getMe, getMyBookings, getMyPackages, rescheduleMyBooking } from \"../api\";\nimport { clearClientToken, getClientToken } from \"../clientAuth\";\nimport type { BookingRecord, ClientProfile, PackageRecord } from \"../types\";\n\nexport interface UseClientAccountOptions {\n apiBase: string;\n onUnauthenticated: () => void;\n onLoggedOut: () => void;\n}\n\nexport function useClientAccount(opts: UseClientAccountOptions) {\n const [profile, setProfile] = useState<ClientProfile | null>(null);\n const [upcoming, setUpcoming] = useState<BookingRecord[]>([]);\n const [history, setHistory] = useState<BookingRecord[]>([]);\n const [packages, setPackages] = useState<PackageRecord[]>([]);\n const [loading, setLoading] = useState(true);\n const [actionError, setActionError] = useState(\"\");\n const [actionLoading, setActionLoading] = useState(false);\n\n const loadAll = () => {\n const token = getClientToken();\n if (!token) {\n opts.onUnauthenticated();\n return;\n }\n Promise.all([\n getMe(opts.apiBase, token),\n getMyBookings(opts.apiBase, token, { upcoming: true, perPage: 10 }),\n getMyBookings(opts.apiBase, token, { perPage: 20 }),\n getMyPackages(opts.apiBase, token),\n ])\n .then(([prof, up, hist, pkgs]) => {\n setProfile(prof);\n setUpcoming(up);\n setHistory(hist);\n setPackages(pkgs);\n setLoading(false);\n })\n .catch(() => opts.onUnauthenticated());\n };\n\n useEffect(() => {\n loadAll();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const handleLogout = () => {\n clearClientToken();\n opts.onLoggedOut();\n };\n\n const cancelBooking = async (bookingId: string) => {\n const token = getClientToken();\n if (!token) return;\n setActionLoading(true);\n setActionError(\"\");\n const result = await cancelMyBooking(opts.apiBase, token, bookingId);\n if (!result.ok) {\n setActionError(result.message);\n setActionLoading(false);\n return;\n }\n loadAll();\n setActionLoading(false);\n };\n\n const rescheduleBooking = async (bookingId: string, startTime: string, endTime: string) => {\n const token = getClientToken();\n if (!token) return false;\n setActionLoading(true);\n setActionError(\"\");\n const result = await rescheduleMyBooking(opts.apiBase, token, bookingId, startTime, endTime);\n setActionLoading(false);\n if (!result.ok) {\n setActionError(result.message);\n return false;\n }\n loadAll();\n return true;\n };\n\n const totalCredits = packages.reduce((s, p) => s + p.remaining_credits, 0);\n\n return {\n profile, upcoming, history, packages, loading, totalCredits, handleLogout,\n cancelBooking, rescheduleBooking, actionError, setActionError, actionLoading,\n };\n}\n"],"mappings":"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","names":["useEffect","useState","EMPTY_FORM","isValidPhone","useState","useEffect","useState","useState","useState","useState","useEffect","useState","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/api.ts","../src/clientAuth.ts","../src/dateUtils.ts","../src/hooks/useBookingFlow.ts","../src/hooks/useClassSchedule.ts","../src/hooks/useMagicLinkAuth.ts","../src/hooks/useRegisterForm.ts","../src/hooks/useClientAccount.ts"],"sourcesContent":["import type {\n ApiConfig,\n BookingCreateInput,\n BookingRecord,\n BookingResult,\n ClientFormValues,\n ClientProfile,\n Location,\n PackageRecord,\n Provider,\n Service,\n Slot,\n WaitlistEntry,\n} from \"./types\";\n\nfunction headers(cfg: ApiConfig, withJson = false): Record<string, string> {\n const h: Record<string, string> = { \"X-API-Key\": cfg.apiKey };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nfunction authHeaders(token: string, withJson = false): Record<string, string> {\n const h: Record<string, string> = { Authorization: `Bearer ${token}` };\n if (withJson) h[\"Content-Type\"] = \"application/json\";\n return h;\n}\n\nexport async function listLocations(cfg: ApiConfig): Promise<Location[]> {\n const res = await fetch(`${cfg.apiBase}/v1/locations`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listServices(cfg: ApiConfig, perPage = 100): Promise<Service[]> {\n const res = await fetch(`${cfg.apiBase}/v1/services?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function listProviders(cfg: ApiConfig, perPage = 100): Promise<Provider[]> {\n const res = await fetch(`${cfg.apiBase}/v1/providers?per_page=${perPage}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getAvailableSlots(\n cfg: ApiConfig,\n params: { locationId: string; startDate: string; serviceId?: string; providerId?: string }\n): Promise<Slot[]> {\n const q = new URLSearchParams({ location_id: params.locationId, start_date: params.startDate });\n if (params.serviceId) q.set(\"service_id\", params.serviceId);\n if (params.providerId) q.set(\"provider_id\", params.providerId);\n const res = await fetch(`${cfg.apiBase}/v1/available-slots?${q.toString()}`, { headers: headers(cfg) });\n const data = await res.json();\n return data.data?.slots || [];\n}\n\nexport async function createClient(cfg: ApiConfig, form: ClientFormValues): Promise<{ id: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/clients`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone,\n rut: form.rut || undefined,\n }),\n });\n if (!res.ok) throw new Error(\"Error registrando datos\");\n return res.json();\n}\n\nexport async function createBooking(\n cfg: ApiConfig,\n input: BookingCreateInput,\n clientToken?: string\n): Promise<BookingResult> {\n // A logged-in client's token takes priority so the server attributes the\n // booking to their account rather than treating it as anonymous — see\n // create_booking in routes/bookings.py, which ignores any client_id sent\n // by an unauthenticated caller.\n const reqHeaders = headers(cfg, true);\n if (clientToken) reqHeaders.Authorization = `Bearer ${clientToken}`;\n const res = await fetch(`${cfg.apiBase}/v1/bookings`, {\n method: \"POST\",\n headers: reqHeaders,\n body: JSON.stringify(input),\n });\n if (res.status === 409) {\n const data = await res.json().catch(() => ({}));\n return { ok: false, conflict: true, message: data.detail || \"Ese horario ya no está disponible.\" };\n }\n if (!res.ok) {\n return { ok: false, conflict: false, message: \"Error creando la reserva. Por favor intenta nuevamente.\" };\n }\n return { ok: true, booking: await res.json() };\n}\n\nexport async function sendMagicLink(\n cfg: ApiConfig,\n email: string,\n frontendUrl: string,\n profile?: { firstName?: string; lastName?: string; phone?: string; rut?: string }\n): Promise<void> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n email: email.trim().toLowerCase(),\n frontend_url: frontendUrl,\n first_name: profile?.firstName,\n last_name: profile?.lastName,\n phone: profile?.phone,\n rut: profile?.rut,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error enviando el link.\");\n}\n\nexport async function verifyMagicLink(cfg: ApiConfig, token: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/magic-link/verify`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ token }),\n });\n const data = await res.json();\n if (!data.access_token) throw new Error(data.detail || \"Link inválido.\");\n return data;\n}\n\nexport async function loginWithGoogle(cfg: ApiConfig, credential: string): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/google`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({ credential }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error con Google.\");\n return data;\n}\n\nexport async function register(\n cfg: ApiConfig,\n form: { firstName: string; lastName: string; email: string; phone?: string; password: string }\n): Promise<{ access_token: string }> {\n const res = await fetch(`${cfg.apiBase}/v1/client-auth/register`, {\n method: \"POST\",\n headers: headers(cfg, true),\n body: JSON.stringify({\n first_name: form.firstName,\n last_name: form.lastName,\n email: form.email,\n phone: form.phone || undefined,\n password: form.password,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"Error al registrarse.\");\n return data;\n}\n\nexport async function getMe(apiBase: string, token: string): Promise<ClientProfile> {\n const res = await fetch(`${apiBase}/v1/me`, { headers: authHeaders(token) });\n return res.json();\n}\n\nexport async function getMyBookings(\n apiBase: string,\n token: string,\n params?: { upcoming?: boolean; perPage?: number }\n): Promise<BookingRecord[]> {\n const q = new URLSearchParams();\n if (params?.upcoming) q.set(\"upcoming\", \"true\");\n q.set(\"per_page\", String(params?.perPage ?? 20));\n const res = await fetch(`${apiBase}/v1/me/bookings?${q.toString()}`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function getMyPackages(apiBase: string, token: string): Promise<PackageRecord[]> {\n const res = await fetch(`${apiBase}/v1/me/packages`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\n/** Result of a client cancelling/rescheduling their own booking — callers\n * branch on `.ok` to show the server's specific reason (cutoff window,\n * overlap, etc.) instead of a generic error. */\nexport type MyBookingActionResult =\n | { ok: true; booking: BookingRecord }\n | { ok: false; message: string };\n\nexport async function cancelMyBooking(\n apiBase: string, token: string, bookingId: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/cancel`, {\n method: \"POST\",\n headers: authHeaders(token),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo cancelar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function rescheduleMyBooking(\n apiBase: string, token: string, bookingId: string, startTime: string, endTime: string\n): Promise<MyBookingActionResult> {\n const res = await fetch(`${apiBase}/v1/me/bookings/${bookingId}/reschedule`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({ start_time: startTime, end_time: endTime }),\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) return { ok: false, message: data.detail || \"No se pudo reprogramar la reserva.\" };\n return { ok: true, booking: data };\n}\n\nexport async function joinWaitlist(\n apiBase: string,\n token: string,\n params: {\n serviceId: string;\n locationId: string;\n providerId?: string;\n date?: string;\n dateUntil?: string;\n classSessionId?: string;\n }\n): Promise<WaitlistEntry> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, {\n method: \"POST\",\n headers: authHeaders(token, true),\n body: JSON.stringify({\n service_id: params.serviceId,\n location_id: params.locationId,\n provider_id: params.providerId,\n date: params.date,\n date_until: params.dateUntil,\n class_session_id: params.classSessionId,\n }),\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.detail || \"No se pudo unir a la lista de espera.\");\n return data;\n}\n\nexport async function getMyWaitlist(apiBase: string, token: string): Promise<WaitlistEntry[]> {\n const res = await fetch(`${apiBase}/v1/me/waitlist`, { headers: authHeaders(token) });\n const data = await res.json();\n return data.data || [];\n}\n\nexport async function leaveWaitlist(apiBase: string, token: string, entryId: string): Promise<void> {\n await fetch(`${apiBase}/v1/me/waitlist/${entryId}`, {\n method: \"DELETE\",\n headers: authHeaders(token),\n });\n}\n","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"]}
|