@tebuto/react-booking-widget 1.0.6 → 1.1.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/.storybook/main.ts +15 -0
- package/.storybook/preview.ts +39 -0
- package/README.md +308 -31
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/types.d.ts +493 -3
- package/package.json +24 -8
- package/vite.config.ts +6 -0
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,49 @@
|
|
|
1
|
-
import { JSX } from 'react';
|
|
1
|
+
import { JSX, ReactNode } from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Theme configuration for the Tebuto Booking Widget.
|
|
6
|
+
* All colors should be valid CSS color strings (e.g., '#00B4A9', 'rgb(0, 180, 169)').
|
|
7
|
+
*
|
|
8
|
+
* Note: The widget automatically generates color variations (light, dark, etc.)
|
|
9
|
+
* from the primaryColor, so only the base colors need to be configured.
|
|
10
|
+
*/
|
|
11
|
+
type TebutoWidgetTheme = {
|
|
12
|
+
/** Primary brand color - used for buttons, highlights, selected states */
|
|
13
|
+
primaryColor?: string;
|
|
14
|
+
/** Main widget background color */
|
|
15
|
+
backgroundColor?: string;
|
|
16
|
+
/** Main text color */
|
|
17
|
+
textPrimary?: string;
|
|
18
|
+
/** Secondary/muted text color */
|
|
19
|
+
textSecondary?: string;
|
|
20
|
+
/** General border color */
|
|
21
|
+
borderColor?: string;
|
|
22
|
+
/** Widget font family */
|
|
23
|
+
fontFamily?: string;
|
|
24
|
+
/** Inherit font from parent page instead of using widget font */
|
|
25
|
+
inheritFont?: boolean;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Configuration options for the Tebuto Booking Widget.
|
|
29
|
+
*/
|
|
3
30
|
type TebutoBookingWidgetConfiguration = {
|
|
31
|
+
/** UUID of the therapist whose calendar should be displayed (required) */
|
|
4
32
|
therapistUUID: string;
|
|
33
|
+
/** Background color of the widget (shorthand for theme.backgroundColor) */
|
|
5
34
|
backgroundColor?: string;
|
|
35
|
+
/** Array of category IDs to filter available appointments */
|
|
6
36
|
categories?: number[];
|
|
37
|
+
/** Whether to display a border around the widget (default: true) */
|
|
7
38
|
border?: boolean;
|
|
39
|
+
/** Include subuser appointments in the calendar (default: false) */
|
|
40
|
+
includeSubusers?: boolean;
|
|
41
|
+
/** Show quick filter buttons for time slots (default: false) */
|
|
42
|
+
showQuickFilters?: boolean;
|
|
43
|
+
/** Inherit font from parent page instead of using widget font (default: false) */
|
|
44
|
+
inheritFont?: boolean;
|
|
45
|
+
/** Theme configuration for customizing colors and fonts */
|
|
46
|
+
theme?: TebutoWidgetTheme;
|
|
8
47
|
};
|
|
9
48
|
|
|
10
49
|
type TebutoBookingWidgetProps = {
|
|
@@ -12,5 +51,456 @@ type TebutoBookingWidgetProps = {
|
|
|
12
51
|
} & TebutoBookingWidgetConfiguration;
|
|
13
52
|
declare function TebutoBookingWidget({ noScriptText, ...config }: TebutoBookingWidgetProps): JSX.Element;
|
|
14
53
|
|
|
15
|
-
|
|
16
|
-
|
|
54
|
+
type CustomBookingExampleProps = {
|
|
55
|
+
therapistUUID: string;
|
|
56
|
+
categories?: number[];
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* CustomBookingExample - A modern, fully-featured booking interface
|
|
60
|
+
*
|
|
61
|
+
* This example demonstrates how to use the Tebuto hooks to build
|
|
62
|
+
* a completely custom booking experience.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```tsx
|
|
66
|
+
* import { CustomBookingExample } from '@tebuto/react-booking-widget'
|
|
67
|
+
*
|
|
68
|
+
* function BookingPage() {
|
|
69
|
+
* return <CustomBookingExample therapistUUID="your-uuid" />
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
declare function CustomBookingExample({ therapistUUID, categories }: CustomBookingExampleProps): react_jsx_runtime.JSX.Element;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* API Types for Tebuto Booking Hooks
|
|
77
|
+
* These types represent the data structures returned by the Tebuto API.
|
|
78
|
+
*/
|
|
79
|
+
/** Location type for appointments */
|
|
80
|
+
type AppointmentLocation = 'virtual' | 'onsite' | 'not-fixed';
|
|
81
|
+
/** Address structure for therapist/location */
|
|
82
|
+
type Address = {
|
|
83
|
+
streetAndNumber: string;
|
|
84
|
+
additionalInformation?: string;
|
|
85
|
+
city: {
|
|
86
|
+
name: string;
|
|
87
|
+
zip: string;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
/** Therapist information */
|
|
91
|
+
type Therapist = {
|
|
92
|
+
name: string;
|
|
93
|
+
firstName: string;
|
|
94
|
+
lastName: string;
|
|
95
|
+
address: Address;
|
|
96
|
+
showWatermark: boolean;
|
|
97
|
+
};
|
|
98
|
+
/** Therapist reference in events */
|
|
99
|
+
type TherapistReference = {
|
|
100
|
+
id: number;
|
|
101
|
+
uuid: string;
|
|
102
|
+
name: string;
|
|
103
|
+
};
|
|
104
|
+
/** Available time slot / event */
|
|
105
|
+
type TimeSlot = {
|
|
106
|
+
title: string;
|
|
107
|
+
start: string;
|
|
108
|
+
end: string;
|
|
109
|
+
location: AppointmentLocation;
|
|
110
|
+
color: string;
|
|
111
|
+
price: string;
|
|
112
|
+
taxRate: string;
|
|
113
|
+
outageFeeEnabled: boolean;
|
|
114
|
+
outageFeeHours: number;
|
|
115
|
+
outageFeePrice: number;
|
|
116
|
+
eventRuleId: number;
|
|
117
|
+
eventCategoryId: number;
|
|
118
|
+
paymentEnabled: boolean;
|
|
119
|
+
paymentDuringBooking: boolean;
|
|
120
|
+
therapist: TherapistReference;
|
|
121
|
+
};
|
|
122
|
+
/** Response from claim endpoint */
|
|
123
|
+
type ClaimResponse = {
|
|
124
|
+
isAvailable: boolean;
|
|
125
|
+
requirePhoneNumber: boolean;
|
|
126
|
+
requireAddress: boolean;
|
|
127
|
+
};
|
|
128
|
+
/** Payment configuration */
|
|
129
|
+
type PaymentConfiguration = {
|
|
130
|
+
paymentTypes: string[];
|
|
131
|
+
onlinePaymentMethods: string[];
|
|
132
|
+
};
|
|
133
|
+
/** Client information for booking */
|
|
134
|
+
type ClientInfo = {
|
|
135
|
+
firstName: string;
|
|
136
|
+
lastName: string;
|
|
137
|
+
email: string;
|
|
138
|
+
phone?: string;
|
|
139
|
+
address?: {
|
|
140
|
+
streetAndNumber: string;
|
|
141
|
+
additionalInformation?: string;
|
|
142
|
+
city: string;
|
|
143
|
+
zip: string;
|
|
144
|
+
};
|
|
145
|
+
notes?: string;
|
|
146
|
+
};
|
|
147
|
+
/** Booking request payload */
|
|
148
|
+
type BookingRequest = {
|
|
149
|
+
start: string;
|
|
150
|
+
end: string;
|
|
151
|
+
eventRuleId: number;
|
|
152
|
+
locationSelection: AppointmentLocation;
|
|
153
|
+
client: ClientInfo;
|
|
154
|
+
};
|
|
155
|
+
/** Booking response */
|
|
156
|
+
type BookingResponse = {
|
|
157
|
+
id: number;
|
|
158
|
+
createdAt: string;
|
|
159
|
+
locationSelection: AppointmentLocation;
|
|
160
|
+
isConfirmed: boolean;
|
|
161
|
+
isOutage: boolean;
|
|
162
|
+
ics: string;
|
|
163
|
+
};
|
|
164
|
+
/** Hook state for async operations */
|
|
165
|
+
type AsyncState<T> = {
|
|
166
|
+
data: T | null;
|
|
167
|
+
isLoading: boolean;
|
|
168
|
+
error: Error | null;
|
|
169
|
+
};
|
|
170
|
+
/** Category for filtering */
|
|
171
|
+
type EventCategory = {
|
|
172
|
+
id: number;
|
|
173
|
+
name: string;
|
|
174
|
+
color: string;
|
|
175
|
+
price: string;
|
|
176
|
+
location: AppointmentLocation;
|
|
177
|
+
};
|
|
178
|
+
/** Grouped time slots by date */
|
|
179
|
+
type SlotsByDate = {
|
|
180
|
+
[date: string]: TimeSlot[];
|
|
181
|
+
};
|
|
182
|
+
/** Time slot with additional computed properties */
|
|
183
|
+
type EnrichedTimeSlot = TimeSlot & {
|
|
184
|
+
dateKey: string;
|
|
185
|
+
timeString: string;
|
|
186
|
+
durationMinutes: number;
|
|
187
|
+
formattedPrice: string;
|
|
188
|
+
isToday: boolean;
|
|
189
|
+
isPast: boolean;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
type TebutoConfig = {
|
|
193
|
+
therapistUUID: string;
|
|
194
|
+
apiBaseUrl: string;
|
|
195
|
+
categories?: number[];
|
|
196
|
+
includeSubusers?: boolean;
|
|
197
|
+
};
|
|
198
|
+
type TebutoContextValue = TebutoConfig & {
|
|
199
|
+
buildUrl: (path: string) => string;
|
|
200
|
+
};
|
|
201
|
+
type TebutoProviderProps = {
|
|
202
|
+
therapistUUID: string;
|
|
203
|
+
apiBaseUrl?: string;
|
|
204
|
+
categories?: number[];
|
|
205
|
+
includeSubusers?: boolean;
|
|
206
|
+
children: ReactNode;
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* TebutoProvider - Context provider for Tebuto booking hooks
|
|
210
|
+
*
|
|
211
|
+
* Wrap your booking components with this provider to share configuration
|
|
212
|
+
* across all Tebuto hooks.
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```tsx
|
|
216
|
+
* <TebutoProvider therapistUUID="your-uuid">
|
|
217
|
+
* <YourBookingComponent />
|
|
218
|
+
* </TebutoProvider>
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
declare function TebutoProvider({ therapistUUID, apiBaseUrl, categories, includeSubusers, children }: TebutoProviderProps): react_jsx_runtime.JSX.Element;
|
|
222
|
+
/**
|
|
223
|
+
* useTebutoContext - Access the Tebuto configuration context
|
|
224
|
+
*
|
|
225
|
+
* Must be used within a TebutoProvider.
|
|
226
|
+
*
|
|
227
|
+
* @throws Error if used outside of TebutoProvider
|
|
228
|
+
*/
|
|
229
|
+
declare function useTebutoContext(): TebutoContextValue;
|
|
230
|
+
|
|
231
|
+
type UseTherapistReturn = AsyncState<Therapist> & {
|
|
232
|
+
refetch: () => Promise<void>;
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* useTherapist - Fetch therapist information
|
|
236
|
+
*
|
|
237
|
+
* Automatically fetches the therapist data when the component mounts.
|
|
238
|
+
* Uses the therapistUUID from the TebutoProvider context.
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```tsx
|
|
242
|
+
* const { data: therapist, isLoading, error } = useTherapist()
|
|
243
|
+
*
|
|
244
|
+
* if (isLoading) return <Spinner />
|
|
245
|
+
* if (error) return <Error message={error.message} />
|
|
246
|
+
*
|
|
247
|
+
* return <h1>Book with {therapist.name}</h1>
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
declare function useTherapist(): UseTherapistReturn;
|
|
251
|
+
|
|
252
|
+
type UseAvailableSlotsOptions = {
|
|
253
|
+
/** Auto-fetch on mount (default: true) */
|
|
254
|
+
autoFetch?: boolean;
|
|
255
|
+
/** Filter by specific category IDs */
|
|
256
|
+
categories?: number[];
|
|
257
|
+
};
|
|
258
|
+
type UseAvailableSlotsReturn = AsyncState<TimeSlot[]> & {
|
|
259
|
+
/** Refetch available slots */
|
|
260
|
+
refetch: () => Promise<void>;
|
|
261
|
+
/** Slots grouped by date (YYYY-MM-DD) */
|
|
262
|
+
slotsByDate: SlotsByDate;
|
|
263
|
+
/** All unique dates with available slots */
|
|
264
|
+
availableDates: Date[];
|
|
265
|
+
/** Get enriched slots for a specific date */
|
|
266
|
+
getSlotsForDate: (date: Date) => EnrichedTimeSlot[];
|
|
267
|
+
/** All unique categories from available slots */
|
|
268
|
+
categories: Array<{
|
|
269
|
+
id: number;
|
|
270
|
+
name: string;
|
|
271
|
+
color: string;
|
|
272
|
+
}>;
|
|
273
|
+
/** Total count of available slots */
|
|
274
|
+
totalSlots: number;
|
|
275
|
+
};
|
|
276
|
+
/**
|
|
277
|
+
* useAvailableSlots - Fetch and manage available time slots
|
|
278
|
+
*
|
|
279
|
+
* Provides available appointment slots with helpers for grouping,
|
|
280
|
+
* filtering, and date navigation.
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```tsx
|
|
284
|
+
* const {
|
|
285
|
+
* slotsByDate,
|
|
286
|
+
* availableDates,
|
|
287
|
+
* getSlotsForDate,
|
|
288
|
+
* isLoading
|
|
289
|
+
* } = useAvailableSlots()
|
|
290
|
+
*
|
|
291
|
+
* const [selectedDate, setSelectedDate] = useState<Date | null>(null)
|
|
292
|
+
*
|
|
293
|
+
* return (
|
|
294
|
+
* <div>
|
|
295
|
+
* <DatePicker dates={availableDates} onSelect={setSelectedDate} />
|
|
296
|
+
* {selectedDate && (
|
|
297
|
+
* <TimeSlotList slots={getSlotsForDate(selectedDate)} />
|
|
298
|
+
* )}
|
|
299
|
+
* </div>
|
|
300
|
+
* )
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
declare function useAvailableSlots(options?: UseAvailableSlotsOptions): UseAvailableSlotsReturn;
|
|
304
|
+
|
|
305
|
+
type ClaimState = {
|
|
306
|
+
claimedSlot: TimeSlot | null;
|
|
307
|
+
claimResponse: ClaimResponse | null;
|
|
308
|
+
isLoading: boolean;
|
|
309
|
+
error: Error | null;
|
|
310
|
+
};
|
|
311
|
+
type UseClaimSlotReturn = ClaimState & {
|
|
312
|
+
/** Claim a time slot to reserve it temporarily */
|
|
313
|
+
claim: (slot: TimeSlot) => Promise<ClaimResponse | null>;
|
|
314
|
+
/** Release the currently claimed slot */
|
|
315
|
+
unclaim: () => Promise<void>;
|
|
316
|
+
/** Check if a specific slot is currently claimed */
|
|
317
|
+
isClaimed: (slot: TimeSlot) => boolean;
|
|
318
|
+
/** Clear error state */
|
|
319
|
+
clearError: () => void;
|
|
320
|
+
};
|
|
321
|
+
/**
|
|
322
|
+
* useClaimSlot - Temporarily claim a time slot
|
|
323
|
+
*
|
|
324
|
+
* Claims a time slot to reserve it while the user fills out
|
|
325
|
+
* their booking information. Automatically handles unclaiming
|
|
326
|
+
* when claiming a new slot.
|
|
327
|
+
*
|
|
328
|
+
* @example
|
|
329
|
+
* ```tsx
|
|
330
|
+
* const { claim, unclaim, claimedSlot, claimResponse, isLoading } = useClaimSlot()
|
|
331
|
+
*
|
|
332
|
+
* const handleSlotSelect = async (slot: TimeSlot) => {
|
|
333
|
+
* const response = await claim(slot)
|
|
334
|
+
* if (response?.isAvailable) {
|
|
335
|
+
* setStep('booking-form')
|
|
336
|
+
* }
|
|
337
|
+
* }
|
|
338
|
+
*
|
|
339
|
+
* const handleCancel = () => {
|
|
340
|
+
* unclaim()
|
|
341
|
+
* setStep('slot-selection')
|
|
342
|
+
* }
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
declare function useClaimSlot(): UseClaimSlotReturn;
|
|
346
|
+
|
|
347
|
+
type BookingState = {
|
|
348
|
+
booking: BookingResponse | null;
|
|
349
|
+
isLoading: boolean;
|
|
350
|
+
error: Error | null;
|
|
351
|
+
isSuccess: boolean;
|
|
352
|
+
};
|
|
353
|
+
type BookAppointmentParams = {
|
|
354
|
+
slot: TimeSlot;
|
|
355
|
+
client: ClientInfo;
|
|
356
|
+
locationSelection?: AppointmentLocation;
|
|
357
|
+
};
|
|
358
|
+
type UseBookAppointmentReturn = BookingState & {
|
|
359
|
+
/** Book the appointment */
|
|
360
|
+
book: (params: BookAppointmentParams) => Promise<BookingResponse | null>;
|
|
361
|
+
/** Reset the booking state */
|
|
362
|
+
reset: () => void;
|
|
363
|
+
/** Download the calendar file (.ics) */
|
|
364
|
+
downloadCalendar: () => void;
|
|
365
|
+
};
|
|
366
|
+
/**
|
|
367
|
+
* useBookAppointment - Complete the booking process
|
|
368
|
+
*
|
|
369
|
+
* Submits the booking with client information and handles
|
|
370
|
+
* the response including calendar download.
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```tsx
|
|
374
|
+
* const { book, booking, isLoading, isSuccess, downloadCalendar, reset } = useBookAppointment()
|
|
375
|
+
*
|
|
376
|
+
* const handleSubmit = async (clientInfo: ClientInfo) => {
|
|
377
|
+
* const result = await book({
|
|
378
|
+
* slot: claimedSlot,
|
|
379
|
+
* client: clientInfo,
|
|
380
|
+
* locationSelection: selectedLocation
|
|
381
|
+
* })
|
|
382
|
+
*
|
|
383
|
+
* if (result) {
|
|
384
|
+
* setStep('confirmation')
|
|
385
|
+
* }
|
|
386
|
+
* }
|
|
387
|
+
*
|
|
388
|
+
* if (isSuccess) {
|
|
389
|
+
* return (
|
|
390
|
+
* <SuccessMessage>
|
|
391
|
+
* <button onClick={downloadCalendar}>Add to Calendar</button>
|
|
392
|
+
* <button onClick={reset}>Book Another</button>
|
|
393
|
+
* </SuccessMessage>
|
|
394
|
+
* )
|
|
395
|
+
* }
|
|
396
|
+
* ```
|
|
397
|
+
*/
|
|
398
|
+
declare function useBookAppointment(): UseBookAppointmentReturn;
|
|
399
|
+
|
|
400
|
+
type BookingStep = 'loading' | 'date-selection' | 'time-selection' | 'booking-form' | 'confirmation' | 'error';
|
|
401
|
+
type UseBookingFlowOptions = {
|
|
402
|
+
/** Categories to filter by */
|
|
403
|
+
categories?: number[];
|
|
404
|
+
/** Callback when booking is complete */
|
|
405
|
+
onBookingComplete?: (booking: BookingResponse) => void;
|
|
406
|
+
/** Callback on any error */
|
|
407
|
+
onError?: (error: Error) => void;
|
|
408
|
+
};
|
|
409
|
+
type UseBookingFlowReturn = {
|
|
410
|
+
/** Current booking step */
|
|
411
|
+
step: BookingStep;
|
|
412
|
+
/** Go to a specific step */
|
|
413
|
+
goToStep: (step: BookingStep) => void;
|
|
414
|
+
/** Therapist information */
|
|
415
|
+
therapist: ReturnType<typeof useTherapist>;
|
|
416
|
+
/** Available slots management */
|
|
417
|
+
slots: ReturnType<typeof useAvailableSlots>;
|
|
418
|
+
/** Selected date */
|
|
419
|
+
selectedDate: Date | null;
|
|
420
|
+
/** Select a date */
|
|
421
|
+
selectDate: (date: Date | null) => void;
|
|
422
|
+
/** Slots for the selected date */
|
|
423
|
+
selectedDateSlots: EnrichedTimeSlot[];
|
|
424
|
+
/** Selected time slot */
|
|
425
|
+
selectedSlot: TimeSlot | null;
|
|
426
|
+
/** Select a time slot (claims it) */
|
|
427
|
+
selectSlot: (slot: TimeSlot | null) => Promise<boolean>;
|
|
428
|
+
/** Selected location (for not-fixed appointments) */
|
|
429
|
+
selectedLocation: AppointmentLocation | null;
|
|
430
|
+
/** Set the location selection */
|
|
431
|
+
setLocation: (location: AppointmentLocation) => void;
|
|
432
|
+
/** Claim state */
|
|
433
|
+
claim: ReturnType<typeof useClaimSlot>;
|
|
434
|
+
/** Booking state */
|
|
435
|
+
booking: ReturnType<typeof useBookAppointment>;
|
|
436
|
+
/** Submit booking with client info */
|
|
437
|
+
submitBooking: (client: ClientInfo) => Promise<boolean>;
|
|
438
|
+
/** Start over from the beginning */
|
|
439
|
+
reset: () => void;
|
|
440
|
+
/** Overall loading state */
|
|
441
|
+
isLoading: boolean;
|
|
442
|
+
/** Current error if any */
|
|
443
|
+
error: Error | null;
|
|
444
|
+
};
|
|
445
|
+
/**
|
|
446
|
+
* useBookingFlow - Complete booking flow orchestration
|
|
447
|
+
*
|
|
448
|
+
* A convenience hook that combines all booking hooks and manages
|
|
449
|
+
* the booking flow state. Perfect for quickly building a booking UI.
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* ```tsx
|
|
453
|
+
* function BookingPage() {
|
|
454
|
+
* const {
|
|
455
|
+
* step,
|
|
456
|
+
* therapist,
|
|
457
|
+
* slots,
|
|
458
|
+
* selectedDate,
|
|
459
|
+
* selectDate,
|
|
460
|
+
* selectedDateSlots,
|
|
461
|
+
* selectSlot,
|
|
462
|
+
* submitBooking,
|
|
463
|
+
* booking,
|
|
464
|
+
* reset
|
|
465
|
+
* } = useBookingFlow()
|
|
466
|
+
*
|
|
467
|
+
* switch (step) {
|
|
468
|
+
* case 'loading':
|
|
469
|
+
* return <LoadingSpinner />
|
|
470
|
+
*
|
|
471
|
+
* case 'date-selection':
|
|
472
|
+
* return (
|
|
473
|
+
* <DatePicker
|
|
474
|
+
* availableDates={slots.availableDates}
|
|
475
|
+
* onSelect={selectDate}
|
|
476
|
+
* />
|
|
477
|
+
* )
|
|
478
|
+
*
|
|
479
|
+
* case 'time-selection':
|
|
480
|
+
* return (
|
|
481
|
+
* <TimeSlotPicker
|
|
482
|
+
* slots={selectedDateSlots}
|
|
483
|
+
* onSelect={selectSlot}
|
|
484
|
+
* />
|
|
485
|
+
* )
|
|
486
|
+
*
|
|
487
|
+
* case 'booking-form':
|
|
488
|
+
* return (
|
|
489
|
+
* <BookingForm onSubmit={submitBooking} />
|
|
490
|
+
* )
|
|
491
|
+
*
|
|
492
|
+
* case 'confirmation':
|
|
493
|
+
* return (
|
|
494
|
+
* <Confirmation
|
|
495
|
+
* booking={booking.booking}
|
|
496
|
+
* onReset={reset}
|
|
497
|
+
* />
|
|
498
|
+
* )
|
|
499
|
+
* }
|
|
500
|
+
* }
|
|
501
|
+
* ```
|
|
502
|
+
*/
|
|
503
|
+
declare function useBookingFlow(options?: UseBookingFlowOptions): UseBookingFlowReturn;
|
|
504
|
+
|
|
505
|
+
export { CustomBookingExample, TebutoBookingWidget, TebutoProvider, useAvailableSlots, useBookAppointment, useBookingFlow, useClaimSlot, useTebutoContext, useTherapist };
|
|
506
|
+
export type { Address, AppointmentLocation, AsyncState, BookingRequest, BookingResponse, ClaimResponse, ClientInfo, EnrichedTimeSlot, EventCategory, PaymentConfiguration, SlotsByDate, TebutoBookingWidgetConfiguration, TebutoWidgetTheme, Therapist, TherapistReference, TimeSlot };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tebuto/react-booking-widget",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "React Component for the Tebuto Booking Widget",
|
|
5
5
|
"author": "Tebuto GmbH",
|
|
6
6
|
"homepage": "https://tebuto.de",
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"module": "dist/esm/index.js",
|
|
10
10
|
"types": "dist/types.d.ts",
|
|
11
11
|
"scripts": {
|
|
12
|
+
"dev": "storybook dev -p 6006",
|
|
13
|
+
"build:storybook": "storybook build",
|
|
12
14
|
"test": "jest",
|
|
13
15
|
"build": "rollup -c --bundleConfigAsCjs",
|
|
14
16
|
"prepare": "husky",
|
|
@@ -25,26 +27,35 @@
|
|
|
25
27
|
"@babel/preset-env": "7.28.5",
|
|
26
28
|
"@babel/preset-react": "7.28.5",
|
|
27
29
|
"@babel/preset-typescript": "7.28.5",
|
|
28
|
-
"@biomejs/biome": "2.3.
|
|
30
|
+
"@biomejs/biome": "2.3.10",
|
|
29
31
|
"@rollup/plugin-commonjs": "29.0.0",
|
|
30
32
|
"@rollup/plugin-node-resolve": "16.0.3",
|
|
31
33
|
"@rollup/plugin-terser": "0.4.4",
|
|
32
34
|
"@rollup/plugin-typescript": "12.3.0",
|
|
33
|
-
"@
|
|
35
|
+
"@storybook/react": "^10.1.10",
|
|
36
|
+
"@storybook/react-vite": "^10.1.10",
|
|
37
|
+
"@testing-library/react": "16.3.1",
|
|
34
38
|
"@types/jest": "30.0.0",
|
|
35
|
-
"@types/react": "19.2.
|
|
39
|
+
"@types/react": "19.2.7",
|
|
40
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
36
41
|
"babel-jest": "30.2.0",
|
|
37
42
|
"husky": "9.1.7",
|
|
38
43
|
"jest": "30.2.0",
|
|
39
44
|
"jest-environment-jsdom": "30.2.0",
|
|
40
|
-
"
|
|
41
|
-
"rollup
|
|
45
|
+
"msw": "^2.12.6",
|
|
46
|
+
"rollup": "4.54.0",
|
|
47
|
+
"rollup-plugin-dts": "6.3.0",
|
|
42
48
|
"rollup-plugin-peer-deps-external": "2.2.4",
|
|
49
|
+
"storybook": "^10.1.10",
|
|
43
50
|
"tslib": "2.8.1",
|
|
44
|
-
"typescript": "5.9.3"
|
|
51
|
+
"typescript": "5.9.3",
|
|
52
|
+
"vite": "^7.3.0"
|
|
45
53
|
},
|
|
46
54
|
"jest": {
|
|
47
|
-
"testEnvironment": "jsdom"
|
|
55
|
+
"testEnvironment": "jsdom",
|
|
56
|
+
"setupFilesAfterEnv": [
|
|
57
|
+
"<rootDir>/src/setupTests.ts"
|
|
58
|
+
]
|
|
48
59
|
},
|
|
49
60
|
"babel": {
|
|
50
61
|
"presets": [
|
|
@@ -81,5 +92,10 @@
|
|
|
81
92
|
],
|
|
82
93
|
"publishConfig": {
|
|
83
94
|
"access": "public"
|
|
95
|
+
},
|
|
96
|
+
"msw": {
|
|
97
|
+
"workerDirectory": [
|
|
98
|
+
"public"
|
|
99
|
+
]
|
|
84
100
|
}
|
|
85
101
|
}
|