@bailierich/booking-components 2.0.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/README.md +319 -0
- package/TENANT_DATA_INTEGRATION.md +402 -0
- package/TENANT_SETUP.md +316 -0
- package/components/BookingFlow/BookingFlow.tsx +790 -0
- package/components/BookingFlow/index.ts +5 -0
- package/components/BookingFlow/steps/AddonsSelection.tsx +118 -0
- package/components/BookingFlow/steps/Confirmation.tsx +185 -0
- package/components/BookingFlow/steps/ContactForm.tsx +292 -0
- package/components/BookingFlow/steps/CycleAwareDateSelection.tsx +277 -0
- package/components/BookingFlow/steps/DateSelection.tsx +473 -0
- package/components/BookingFlow/steps/ServiceSelection.tsx +315 -0
- package/components/BookingFlow/steps/TimeSelection.tsx +230 -0
- package/components/BookingFlow/steps/index.ts +10 -0
- package/components/BottomSheet/index.tsx +120 -0
- package/components/Forms/FormBlock.tsx +283 -0
- package/components/Forms/FormField.tsx +385 -0
- package/components/Forms/FormRenderer.tsx +216 -0
- package/components/Forms/FormValidation.ts +122 -0
- package/components/Forms/index.ts +4 -0
- package/components/HoldTimer/HoldTimer.tsx +266 -0
- package/components/HoldTimer/index.ts +2 -0
- package/components/SectionRenderer.tsx +558 -0
- package/components/Sections/About.tsx +145 -0
- package/components/Sections/BeforeAfter.tsx +81 -0
- package/components/Sections/BookingSection.tsx +76 -0
- package/components/Sections/Contact.tsx +103 -0
- package/components/Sections/FAQSection.tsx +239 -0
- package/components/Sections/FeatureContent.tsx +113 -0
- package/components/Sections/FeaturedLink.tsx +103 -0
- package/components/Sections/FixedInfoCard.tsx +189 -0
- package/components/Sections/Gallery.tsx +83 -0
- package/components/Sections/Header.tsx +78 -0
- package/components/Sections/Hero.tsx +178 -0
- package/components/Sections/ImageSection.tsx +147 -0
- package/components/Sections/InstagramFeed.tsx +38 -0
- package/components/Sections/LinkList.tsx +76 -0
- package/components/Sections/LocationMap.tsx +202 -0
- package/components/Sections/Logo.tsx +61 -0
- package/components/Sections/MinimalFooter.tsx +78 -0
- package/components/Sections/MinimalHeader.tsx +81 -0
- package/components/Sections/MinimalNavigation.tsx +63 -0
- package/components/Sections/Navbar.tsx +258 -0
- package/components/Sections/PricingTable.tsx +106 -0
- package/components/Sections/ScrollingTextDivider.tsx +138 -0
- package/components/Sections/ScrollingTextDivider.tsx.bak +138 -0
- package/components/Sections/ServicesPreview.tsx +129 -0
- package/components/Sections/SocialBar.tsx +177 -0
- package/components/Sections/Team.tsx +80 -0
- package/components/Sections/Testimonials.tsx +92 -0
- package/components/Sections/TextSection.tsx +116 -0
- package/components/Sections/VideoSection.tsx +178 -0
- package/components/Sections/index.ts +57 -0
- package/components/index.ts +21 -0
- package/dist/index-DAai7Glf.d.mts +474 -0
- package/dist/index-DAai7Glf.d.ts +474 -0
- package/dist/index.d.mts +1075 -0
- package/dist/index.d.ts +1075 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +22 -0
- package/dist/index.mjs.map +1 -0
- package/dist/styles/index.d.mts +1 -0
- package/dist/styles/index.d.ts +1 -0
- package/dist/styles/index.js +2 -0
- package/dist/styles/index.js.map +1 -0
- package/dist/styles/index.mjs +2 -0
- package/dist/styles/index.mjs.map +1 -0
- package/docs/API.md +849 -0
- package/docs/CALLBACKS.md +760 -0
- package/docs/COMPLETE_SESSION_SUMMARY.md +404 -0
- package/docs/DATA_SHAPES.md +684 -0
- package/docs/MIGRATION.md +662 -0
- package/docs/PAYMENT_INTEGRATION.md +766 -0
- package/docs/SESSION_SUMMARY.md +185 -0
- package/docs/STYLING.md +735 -0
- package/index.ts +4 -0
- package/lib/storage.ts +239 -0
- package/package.json +59 -0
- package/styles/animations.ts +210 -0
- package/styles/index.ts +1 -0
- package/tsconfig.json +32 -0
- package/tsup.config.ts +13 -0
- package/types/index.ts +369 -0
package/types/index.ts
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Core Data Types
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
export interface Service {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
price: number;
|
|
9
|
+
duration: number; // in minutes
|
|
10
|
+
description: string;
|
|
11
|
+
category?: string;
|
|
12
|
+
imageUrl?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ServiceCategory {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
services: Service[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Addon {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
price: number;
|
|
26
|
+
addonPrice?: number; // Alternative price field for addons (used by some implementations)
|
|
27
|
+
duration: number; // in minutes
|
|
28
|
+
description: string;
|
|
29
|
+
imageUrl?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface OptInModule {
|
|
33
|
+
id: string;
|
|
34
|
+
label: string;
|
|
35
|
+
required: boolean;
|
|
36
|
+
formTitle?: string;
|
|
37
|
+
formFields?: FormField[];
|
|
38
|
+
// Optional: custom render function for advanced modules
|
|
39
|
+
// Returns the content to render inside the BottomSheet (not the BottomSheet itself)
|
|
40
|
+
renderCustomForm?: (
|
|
41
|
+
onClose: () => void,
|
|
42
|
+
onSubmitData: (data: any) => void,
|
|
43
|
+
colors: { primary: string; secondary: string; bookingText?: string }
|
|
44
|
+
) => React.ReactNode;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface FormField {
|
|
48
|
+
id: string;
|
|
49
|
+
label: string;
|
|
50
|
+
type: 'text' | 'email' | 'tel' | 'textarea' | 'select' | 'checkbox';
|
|
51
|
+
placeholder?: string;
|
|
52
|
+
required?: boolean;
|
|
53
|
+
options?: { value: string; label: string }[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// Booking Data
|
|
58
|
+
// ============================================================================
|
|
59
|
+
|
|
60
|
+
export interface BookingData {
|
|
61
|
+
serviceId: string;
|
|
62
|
+
date: string; // ISO date string
|
|
63
|
+
time: string;
|
|
64
|
+
addonIds: string[];
|
|
65
|
+
contactInfo: ContactInfo;
|
|
66
|
+
optInData?: Record<string, any>;
|
|
67
|
+
paymentIntentId?: string;
|
|
68
|
+
totalPrice: number;
|
|
69
|
+
depositAmount: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ContactInfo {
|
|
73
|
+
name: string;
|
|
74
|
+
email: string;
|
|
75
|
+
phone: string;
|
|
76
|
+
notes?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// Configuration Types
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Note: BookingFlowConfig and BookingFlowProps are exported from BookingFlow component
|
|
83
|
+
// to avoid duplication. Import those types from the component instead.
|
|
84
|
+
|
|
85
|
+
export interface BackgroundConfig {
|
|
86
|
+
type: 'color' | 'gradient' | 'image';
|
|
87
|
+
value: string; // hex color, gradient CSS, or image URL
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface TransitionConfig {
|
|
91
|
+
style: 'slide' | 'fade';
|
|
92
|
+
speed: 'fast' | 'normal' | 'slow';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface ProgressBarConfig {
|
|
96
|
+
style: 'dots' | 'bar' | 'minimal';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface StepConfig {
|
|
100
|
+
enabled?: boolean;
|
|
101
|
+
settings?: Record<string, any>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Service Selection Step Settings
|
|
105
|
+
export interface ServiceSelectionSettings {
|
|
106
|
+
headerContent?: { value: string };
|
|
107
|
+
subheaderContent?: { value: string };
|
|
108
|
+
serviceLayout?: 'grid' | 'list';
|
|
109
|
+
columns?: 1 | 2 | 3 | 4;
|
|
110
|
+
showPricing?: boolean;
|
|
111
|
+
showDuration?: boolean;
|
|
112
|
+
showDescription?: boolean;
|
|
113
|
+
enableCategories?: boolean;
|
|
114
|
+
categoryStyle?: 'dropdown' | 'tabs' | 'pills' | 'chips' | 'accordion';
|
|
115
|
+
defaultCategoryView?: 'all' | string; // category ID
|
|
116
|
+
policyImages?: PolicyImage[];
|
|
117
|
+
policyText?: string;
|
|
118
|
+
imageSpacing?: 'none' | 'small' | 'medium' | 'large';
|
|
119
|
+
imageBorderRadius?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface PolicyImage {
|
|
123
|
+
url: string;
|
|
124
|
+
alt?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Date Selection Step Settings
|
|
128
|
+
export interface DateSelectionSettings {
|
|
129
|
+
headerContent?: { value: string };
|
|
130
|
+
calendarView?: 'month' | 'week';
|
|
131
|
+
allowedDaysAhead?: number;
|
|
132
|
+
blockedDates?: string[]; // ISO date strings
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Time Selection Step Settings
|
|
136
|
+
export interface TimeSelectionSettings {
|
|
137
|
+
headerContent?: { value: string };
|
|
138
|
+
timeFormat?: '12h' | '24h';
|
|
139
|
+
showDuration?: boolean;
|
|
140
|
+
columns?: 2 | 3 | 4;
|
|
141
|
+
slotDuration?: number; // minutes
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Addon Selection Step Settings
|
|
145
|
+
export interface AddonSelectionSettings {
|
|
146
|
+
headerContent?: { value: string };
|
|
147
|
+
subheaderContent?: { value: string };
|
|
148
|
+
showPricing?: boolean;
|
|
149
|
+
showDuration?: boolean;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Contact Form Step Settings
|
|
153
|
+
export interface ContactFormSettings {
|
|
154
|
+
headerContent?: { value: string };
|
|
155
|
+
requiredFields?: ('name' | 'email' | 'phone' | 'notes')[];
|
|
156
|
+
customFields?: FormField[];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// Component Props
|
|
161
|
+
// ============================================================================
|
|
162
|
+
// Note: BookingFlowProps is exported from BookingFlow component. Import from there.
|
|
163
|
+
|
|
164
|
+
export interface DataProviders {
|
|
165
|
+
/** Fetch available services */
|
|
166
|
+
getServices: () => Promise<Service[]>;
|
|
167
|
+
|
|
168
|
+
/** Fetch available dates for a service */
|
|
169
|
+
getAvailableDates: (serviceId: string) => Promise<string[]>;
|
|
170
|
+
|
|
171
|
+
/** Fetch available time slots for a service on a specific date */
|
|
172
|
+
getAvailableTimes: (serviceId: string, date: string) => Promise<string[]>;
|
|
173
|
+
|
|
174
|
+
/** Fetch available add-ons for a service */
|
|
175
|
+
getAddons: (serviceId: string) => Promise<Addon[]>;
|
|
176
|
+
|
|
177
|
+
/** Optional: Fetch opt-in modules (custom forms) */
|
|
178
|
+
getOptInModules?: () => Promise<OptInModule[]>;
|
|
179
|
+
|
|
180
|
+
/** Optional: Fetch service categories */
|
|
181
|
+
getServiceCategories?: () => Promise<ServiceCategory[]>;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface PaymentConfig {
|
|
185
|
+
// Square configuration
|
|
186
|
+
squareApplicationId?: string;
|
|
187
|
+
squareLocationId?: string;
|
|
188
|
+
|
|
189
|
+
// Stripe configuration
|
|
190
|
+
stripePublishableKey?: string;
|
|
191
|
+
|
|
192
|
+
// Common settings
|
|
193
|
+
depositPercentage?: number; // Default: 20 (20%)
|
|
194
|
+
currency?: string; // Default: 'USD'
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ============================================================================
|
|
198
|
+
// BottomSheet Props
|
|
199
|
+
// ============================================================================
|
|
200
|
+
|
|
201
|
+
export interface BottomSheetProps {
|
|
202
|
+
isOpen: boolean;
|
|
203
|
+
onClose: () => void;
|
|
204
|
+
title?: string;
|
|
205
|
+
children: React.ReactNode;
|
|
206
|
+
isRequired?: boolean;
|
|
207
|
+
maxHeight?: string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ============================================================================
|
|
211
|
+
// Internal Step Component Props
|
|
212
|
+
// ============================================================================
|
|
213
|
+
|
|
214
|
+
export interface StepComponentProps {
|
|
215
|
+
config: StepConfig;
|
|
216
|
+
colors: {
|
|
217
|
+
primary: string;
|
|
218
|
+
secondary: string;
|
|
219
|
+
bookingText?: string;
|
|
220
|
+
};
|
|
221
|
+
onNext: () => void;
|
|
222
|
+
onBack: () => void;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export interface ServiceSelectionStepProps extends StepComponentProps {
|
|
226
|
+
services: Service[];
|
|
227
|
+
categories?: ServiceCategory[];
|
|
228
|
+
selectedService: string | null;
|
|
229
|
+
onServiceSelect: (serviceId: string) => void;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface DateSelectionStepProps extends StepComponentProps {
|
|
233
|
+
availableDates: string[];
|
|
234
|
+
selectedDate: string | null;
|
|
235
|
+
onDateSelect: (date: string) => void;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface TimeSelectionStepProps extends StepComponentProps {
|
|
239
|
+
availableTimes: string[];
|
|
240
|
+
selectedTime: string | null;
|
|
241
|
+
onTimeSelect: (time: string) => void;
|
|
242
|
+
serviceDuration?: number;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export interface AddonSelectionStepProps extends StepComponentProps {
|
|
246
|
+
addons: Addon[];
|
|
247
|
+
selectedAddons: string[];
|
|
248
|
+
onAddonsChange: (addonIds: string[]) => void;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface ContactFormStepProps extends StepComponentProps {
|
|
252
|
+
contactInfo: Partial<ContactInfo>;
|
|
253
|
+
onContactInfoChange: (info: Partial<ContactInfo>) => void;
|
|
254
|
+
optInModules?: OptInModule[];
|
|
255
|
+
onOptInData?: (moduleId: string, data: any) => void;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export interface ConfirmationStepProps extends StepComponentProps {
|
|
259
|
+
bookingData: Partial<BookingData>;
|
|
260
|
+
service?: Service;
|
|
261
|
+
addons?: Addon[];
|
|
262
|
+
paymentProvider: 'square' | 'stripe';
|
|
263
|
+
paymentConfig: PaymentConfig;
|
|
264
|
+
onConfirm: () => Promise<void>;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// ============================================================================
|
|
268
|
+
// Cycle-Aware Booking Types
|
|
269
|
+
// ============================================================================
|
|
270
|
+
|
|
271
|
+
export interface CyclePhase {
|
|
272
|
+
phase: 'avoid' | 'caution' | 'optimal' | 'neutral' | 'unknown';
|
|
273
|
+
color: string;
|
|
274
|
+
bgColor: string;
|
|
275
|
+
label: string;
|
|
276
|
+
icon: string;
|
|
277
|
+
description: string;
|
|
278
|
+
daysSinceStart?: number;
|
|
279
|
+
confidence?: number;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export interface CyclePhaseMap {
|
|
283
|
+
[dateString: string]: CyclePhase;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export interface CycleClient {
|
|
287
|
+
id: string;
|
|
288
|
+
cycle_opt_in: boolean;
|
|
289
|
+
cycle_last_period_start?: string;
|
|
290
|
+
cycle_avg_days?: number;
|
|
291
|
+
cycle_period_len?: number;
|
|
292
|
+
[key: string]: any; // Allow other client properties
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Function that fetches cycle phase data for a date range */
|
|
296
|
+
export type FetchCycleDataFn = (
|
|
297
|
+
client: CycleClient,
|
|
298
|
+
dateRange: string[]
|
|
299
|
+
) => Promise<CyclePhaseMap>;
|
|
300
|
+
|
|
301
|
+
/** Callback when a cycle warning should be shown */
|
|
302
|
+
export type CycleWarningCallback = (phase: CyclePhase, date: string) => void;
|
|
303
|
+
|
|
304
|
+
// ============================================================================
|
|
305
|
+
// Hold Timer Types
|
|
306
|
+
// ============================================================================
|
|
307
|
+
|
|
308
|
+
export interface HoldTimerConfig {
|
|
309
|
+
enabled: boolean;
|
|
310
|
+
duration: number; // in milliseconds (default: 600000 = 10 minutes)
|
|
311
|
+
warningThreshold: number; // in milliseconds (default: 120000 = 2 minutes)
|
|
312
|
+
maxExtensions: number; // default: 2
|
|
313
|
+
extensionDuration: number; // in milliseconds (default: 300000 = 5 minutes)
|
|
314
|
+
showActions: boolean; // show extend/release buttons (default: true)
|
|
315
|
+
showWarning: boolean; // show warning state (default: true)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export interface HoldStatus {
|
|
319
|
+
holdId: string;
|
|
320
|
+
holdKey: string;
|
|
321
|
+
date: string;
|
|
322
|
+
time: string;
|
|
323
|
+
serviceId: string;
|
|
324
|
+
createdAt: number; // timestamp
|
|
325
|
+
expiresAt: number; // timestamp
|
|
326
|
+
extensions: number;
|
|
327
|
+
maxExtensions: number;
|
|
328
|
+
canExtend: boolean;
|
|
329
|
+
status: 'active' | 'warning' | 'expired';
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export interface HoldManagerCallbacks {
|
|
333
|
+
/** Called when hold is created successfully */
|
|
334
|
+
onHoldCreated?: (hold: HoldStatus) => void;
|
|
335
|
+
/** Called when hold is extended */
|
|
336
|
+
onHoldExtended?: (hold: HoldStatus) => void;
|
|
337
|
+
/** Called when hold is released manually */
|
|
338
|
+
onHoldReleased?: (holdId: string) => void;
|
|
339
|
+
/** Called when entering warning threshold */
|
|
340
|
+
onHoldWarning?: (hold: HoldStatus) => void;
|
|
341
|
+
/** Called when hold expires */
|
|
342
|
+
onHoldExpired?: (hold: HoldStatus) => void;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Function that creates a hold on the backend */
|
|
346
|
+
export type CreateHoldFn = (data: {
|
|
347
|
+
date: string;
|
|
348
|
+
time: string;
|
|
349
|
+
serviceId: string;
|
|
350
|
+
serviceDuration: number;
|
|
351
|
+
}) => Promise<HoldStatus>;
|
|
352
|
+
|
|
353
|
+
/** Function that extends an existing hold */
|
|
354
|
+
export type ExtendHoldFn = (holdId: string) => Promise<HoldStatus>;
|
|
355
|
+
|
|
356
|
+
/** Function that releases a hold */
|
|
357
|
+
export type ReleaseHoldFn = (holdId: string) => Promise<void>;
|
|
358
|
+
|
|
359
|
+
// ============================================================================
|
|
360
|
+
// Animation Types
|
|
361
|
+
// ============================================================================
|
|
362
|
+
|
|
363
|
+
export type TransitionDirection = 'forward' | 'backward';
|
|
364
|
+
|
|
365
|
+
export interface AnimationVariants {
|
|
366
|
+
enter: (direction: TransitionDirection) => Record<string, any>;
|
|
367
|
+
center: Record<string, any>;
|
|
368
|
+
exit: (direction: TransitionDirection) => Record<string, any>;
|
|
369
|
+
}
|