@bookr-cl/widget 0.0.1

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.
@@ -0,0 +1,317 @@
1
+ import * as react from 'react';
2
+
3
+ interface ApiConfig {
4
+ apiBase: string;
5
+ apiKey: string;
6
+ }
7
+ interface Location {
8
+ id: string;
9
+ name: string;
10
+ address?: string;
11
+ }
12
+ interface Service {
13
+ id: string;
14
+ name: string;
15
+ price: string;
16
+ duration: number;
17
+ price_variants?: Record<string, number> | null;
18
+ }
19
+ interface Provider {
20
+ id: string;
21
+ public_name: string;
22
+ }
23
+ /** A bookable slot from GET /v1/available-slots. */
24
+ interface Slot {
25
+ start_time: string;
26
+ end_time: string;
27
+ provider_id: string;
28
+ provider_name: string;
29
+ service_name?: string;
30
+ title?: string;
31
+ description?: string;
32
+ capacity?: number;
33
+ enrolled_count?: number;
34
+ class_session_id?: string;
35
+ }
36
+ interface ClientProfile {
37
+ id: string;
38
+ first_name: string;
39
+ last_name: string;
40
+ email: string | null;
41
+ phone: string | null;
42
+ }
43
+ interface BookingRecord {
44
+ id: string;
45
+ start_time: string;
46
+ end_time: string;
47
+ service_name: string;
48
+ provider_name: string;
49
+ payment_status: string;
50
+ price: string;
51
+ status?: {
52
+ id: string;
53
+ name: string;
54
+ };
55
+ approval_status?: string | null;
56
+ }
57
+ interface PackageRecord {
58
+ id: string;
59
+ service_name: string;
60
+ total_credits: number;
61
+ used_credits: number;
62
+ remaining_credits: number;
63
+ expiration_date: string;
64
+ }
65
+ interface ClientFormValues {
66
+ firstName: string;
67
+ lastName: string;
68
+ email: string;
69
+ phone: string;
70
+ rut: string;
71
+ }
72
+ interface BookingCreateInput {
73
+ start_time: string;
74
+ end_time: string;
75
+ service_id: string;
76
+ service_provider_id: string;
77
+ location_id: string;
78
+ price?: string;
79
+ notes?: string;
80
+ /** Only honored by the server when a client/staff auth token is sent alongside. */
81
+ client_id?: string;
82
+ /** Contact fields the server uses to find-or-create the client when no auth token is present. */
83
+ client_first_name?: string;
84
+ client_last_name?: string;
85
+ client_email?: string;
86
+ client_phone?: string;
87
+ client_rut?: string;
88
+ }
89
+ /** Result of a booking attempt — callers branch on `.ok` instead of parsing
90
+ * status codes/error strings themselves. */
91
+ type BookingResult = {
92
+ ok: true;
93
+ booking: BookingRecord;
94
+ } | {
95
+ ok: false;
96
+ conflict: true;
97
+ message: string;
98
+ } | {
99
+ ok: false;
100
+ conflict: false;
101
+ message: string;
102
+ };
103
+
104
+ declare function listLocations(cfg: ApiConfig): Promise<Location[]>;
105
+ declare function listServices(cfg: ApiConfig, perPage?: number): Promise<Service[]>;
106
+ declare function listProviders(cfg: ApiConfig, perPage?: number): Promise<Provider[]>;
107
+ declare function getAvailableSlots(cfg: ApiConfig, params: {
108
+ locationId: string;
109
+ startDate: string;
110
+ serviceId?: string;
111
+ providerId?: string;
112
+ }): Promise<Slot[]>;
113
+ declare function createClient(cfg: ApiConfig, form: ClientFormValues): Promise<{
114
+ id: string;
115
+ }>;
116
+ declare function createBooking(cfg: ApiConfig, input: BookingCreateInput, clientToken?: string): Promise<BookingResult>;
117
+ declare function sendMagicLink(cfg: ApiConfig, email: string, frontendUrl: string, profile?: {
118
+ firstName?: string;
119
+ lastName?: string;
120
+ phone?: string;
121
+ rut?: string;
122
+ }): Promise<void>;
123
+ declare function verifyMagicLink(cfg: ApiConfig, token: string): Promise<{
124
+ access_token: string;
125
+ }>;
126
+ declare function loginWithGoogle(cfg: ApiConfig, credential: string): Promise<{
127
+ access_token: string;
128
+ }>;
129
+ declare function register(cfg: ApiConfig, form: {
130
+ firstName: string;
131
+ lastName: string;
132
+ email: string;
133
+ phone?: string;
134
+ password: string;
135
+ }): Promise<{
136
+ access_token: string;
137
+ }>;
138
+ declare function getMe(apiBase: string, token: string): Promise<ClientProfile>;
139
+ declare function getMyBookings(apiBase: string, token: string, params?: {
140
+ upcoming?: boolean;
141
+ perPage?: number;
142
+ }): Promise<BookingRecord[]>;
143
+ declare function getMyPackages(apiBase: string, token: string): Promise<PackageRecord[]>;
144
+
145
+ declare function getClientToken(): string | null;
146
+ declare function setClientToken(token: string): void;
147
+ declare function clearClientToken(): void;
148
+ declare function fetchMe(apiBase: string, token: string): Promise<ClientProfile | null>;
149
+
150
+ declare function getMondayOf(date: Date): Date;
151
+ declare function dateStr(d: Date): string;
152
+ declare function formatMonthRange(monday: Date): string;
153
+ declare const DAY_NAMES: string[];
154
+ declare const DAY_NAMES_FULL: string[];
155
+ interface ProviderColor {
156
+ bg: string;
157
+ border: string;
158
+ text: string;
159
+ }
160
+ declare const DEFAULT_PROVIDER_COLORS: ProviderColor[];
161
+
162
+ interface UseBookingFlowOptions extends ApiConfig {
163
+ onBookingComplete: (booking: BookingRecord) => void;
164
+ /** Default notes attached to every booking (e.g. "Reserva realizada desde sitio web X"). */
165
+ defaultNotes?: string;
166
+ }
167
+ interface SubmitBookingOverrides {
168
+ /** Override the service's list price (e.g. magnolia's price-variant step). */
169
+ price?: string;
170
+ /** Override defaultNotes for this specific submission. */
171
+ notes?: string;
172
+ }
173
+ /**
174
+ * Shared booking-flow logic: catalog fetching (locations/services/providers/
175
+ * slots), logged-in-client prefill, form validation, and submit-with-409-
176
+ * handling. Does NOT own step navigation or app-specific filtering (e.g.
177
+ * magnolia's category/price-variant logic) — those stay in the consuming
178
+ * component, layered on top of the `services`/`providers` this hook returns.
179
+ */
180
+ declare function useBookingFlow(opts: UseBookingFlowOptions): {
181
+ locations: Location[];
182
+ services: Service[];
183
+ providers: Provider[];
184
+ slots: Slot[];
185
+ selectedLoc: string;
186
+ setSelectedLoc: react.Dispatch<react.SetStateAction<string>>;
187
+ selectedSvc: string;
188
+ setSelectedSvc: react.Dispatch<react.SetStateAction<string>>;
189
+ selectedProv: string;
190
+ setSelectedProv: react.Dispatch<react.SetStateAction<string>>;
191
+ selectedDate: string;
192
+ setSelectedDate: react.Dispatch<react.SetStateAction<string>>;
193
+ selectedSlot: Slot | null;
194
+ setSelectedSlot: react.Dispatch<react.SetStateAction<Slot | null>>;
195
+ form: ClientFormValues;
196
+ updateForm: (fields: Partial<ClientFormValues>) => void;
197
+ loading: boolean;
198
+ error: string;
199
+ setError: react.Dispatch<react.SetStateAction<string>>;
200
+ client: ClientProfile | null;
201
+ submitBooking: (overrides?: SubmitBookingOverrides) => Promise<void>;
202
+ };
203
+
204
+ interface SelectedClassSlot {
205
+ slot: Slot;
206
+ date: string;
207
+ }
208
+ interface UseClassScheduleOptions extends ApiConfig {
209
+ onBookingComplete: () => void;
210
+ colors?: ProviderColor[];
211
+ }
212
+ /**
213
+ * Shared weekly group-class schedule logic: week-of-slots fetching, provider
214
+ * color-palette assignment, and submit-with-409-handling. The week-grid table
215
+ * JSX and modal markup stay in the consuming component — this hook only owns
216
+ * data and state transitions.
217
+ */
218
+ declare function useClassSchedule(opts: UseClassScheduleOptions): {
219
+ monday: Date;
220
+ setMonday: react.Dispatch<react.SetStateAction<Date>>;
221
+ slotsByDay: Record<string, Slot[]>;
222
+ loading: boolean;
223
+ providerColorMap: Record<string, ProviderColor>;
224
+ selectedSlot: SelectedClassSlot | null;
225
+ setSelectedSlot: react.Dispatch<react.SetStateAction<SelectedClassSlot | null>>;
226
+ form: ClientFormValues;
227
+ updateForm: (fields: Partial<ClientFormValues>) => void;
228
+ submitting: boolean;
229
+ error: string;
230
+ setError: react.Dispatch<react.SetStateAction<string>>;
231
+ client: ClientProfile | null;
232
+ submitBooking: (e: {
233
+ preventDefault: () => void;
234
+ }) => Promise<void>;
235
+ };
236
+
237
+ declare global {
238
+ interface Window {
239
+ google?: {
240
+ accounts: {
241
+ id: {
242
+ initialize: (config: {
243
+ client_id: string;
244
+ callback: (response: {
245
+ credential: string;
246
+ }) => void;
247
+ }) => void;
248
+ prompt: () => void;
249
+ };
250
+ };
251
+ };
252
+ }
253
+ }
254
+ interface UseMagicLinkAuthOptions extends ApiConfig {
255
+ googleClientId?: string;
256
+ frontendUrl: string;
257
+ onGoogleLoggedIn: () => void;
258
+ }
259
+ type MagicLinkStep = "email" | "sent";
260
+ declare function useMagicLinkAuth(opts: UseMagicLinkAuthOptions): {
261
+ email: string;
262
+ setEmail: react.Dispatch<react.SetStateAction<string>>;
263
+ firstName: string;
264
+ setFirstName: react.Dispatch<react.SetStateAction<string>>;
265
+ lastName: string;
266
+ setLastName: react.Dispatch<react.SetStateAction<string>>;
267
+ phone: string;
268
+ setPhone: react.Dispatch<react.SetStateAction<string>>;
269
+ rut: string;
270
+ setRut: react.Dispatch<react.SetStateAction<string>>;
271
+ step: MagicLinkStep;
272
+ error: string;
273
+ loading: boolean;
274
+ handleMagicLink: (e: {
275
+ preventDefault: () => void;
276
+ }) => Promise<void>;
277
+ handleGoogle: () => void;
278
+ reset: () => void;
279
+ };
280
+
281
+ interface RegisterFormValues {
282
+ firstName: string;
283
+ lastName: string;
284
+ email: string;
285
+ phone: string;
286
+ password: string;
287
+ confirm: string;
288
+ }
289
+ interface UseRegisterFormOptions extends ApiConfig {
290
+ onRegistered: () => void;
291
+ }
292
+ declare function useRegisterForm(opts: UseRegisterFormOptions): {
293
+ form: RegisterFormValues;
294
+ updateField: (fields: Partial<RegisterFormValues>) => void;
295
+ error: string;
296
+ loading: boolean;
297
+ handleSubmit: (e: {
298
+ preventDefault: () => void;
299
+ }) => Promise<void>;
300
+ };
301
+
302
+ interface UseClientAccountOptions {
303
+ apiBase: string;
304
+ onUnauthenticated: () => void;
305
+ onLoggedOut: () => void;
306
+ }
307
+ declare function useClientAccount(opts: UseClientAccountOptions): {
308
+ profile: ClientProfile | null;
309
+ upcoming: BookingRecord[];
310
+ history: BookingRecord[];
311
+ packages: PackageRecord[];
312
+ loading: boolean;
313
+ totalCredits: number;
314
+ handleLogout: () => void;
315
+ };
316
+
317
+ export { type ApiConfig, type BookingCreateInput, type BookingRecord, type BookingResult, type ClientFormValues, type ClientProfile, DAY_NAMES, DAY_NAMES_FULL, DEFAULT_PROVIDER_COLORS, type Location, type MagicLinkStep, type PackageRecord, type Provider, type ProviderColor, type RegisterFormValues, type SelectedClassSlot, type Service, type Slot, type SubmitBookingOverrides, type UseBookingFlowOptions, type UseClassScheduleOptions, type UseClientAccountOptions, type UseMagicLinkAuthOptions, type UseRegisterFormOptions, clearClientToken, createBooking, createClient, dateStr, fetchMe, formatMonthRange, getAvailableSlots, getClientToken, getMe, getMondayOf, getMyBookings, getMyPackages, listLocations, listProviders, listServices, loginWithGoogle, register, sendMagicLink, setClientToken, useBookingFlow, useClassSchedule, useClientAccount, useMagicLinkAuth, useRegisterForm, verifyMagicLink };