@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.
Files changed (83) hide show
  1. package/README.md +319 -0
  2. package/TENANT_DATA_INTEGRATION.md +402 -0
  3. package/TENANT_SETUP.md +316 -0
  4. package/components/BookingFlow/BookingFlow.tsx +790 -0
  5. package/components/BookingFlow/index.ts +5 -0
  6. package/components/BookingFlow/steps/AddonsSelection.tsx +118 -0
  7. package/components/BookingFlow/steps/Confirmation.tsx +185 -0
  8. package/components/BookingFlow/steps/ContactForm.tsx +292 -0
  9. package/components/BookingFlow/steps/CycleAwareDateSelection.tsx +277 -0
  10. package/components/BookingFlow/steps/DateSelection.tsx +473 -0
  11. package/components/BookingFlow/steps/ServiceSelection.tsx +315 -0
  12. package/components/BookingFlow/steps/TimeSelection.tsx +230 -0
  13. package/components/BookingFlow/steps/index.ts +10 -0
  14. package/components/BottomSheet/index.tsx +120 -0
  15. package/components/Forms/FormBlock.tsx +283 -0
  16. package/components/Forms/FormField.tsx +385 -0
  17. package/components/Forms/FormRenderer.tsx +216 -0
  18. package/components/Forms/FormValidation.ts +122 -0
  19. package/components/Forms/index.ts +4 -0
  20. package/components/HoldTimer/HoldTimer.tsx +266 -0
  21. package/components/HoldTimer/index.ts +2 -0
  22. package/components/SectionRenderer.tsx +558 -0
  23. package/components/Sections/About.tsx +145 -0
  24. package/components/Sections/BeforeAfter.tsx +81 -0
  25. package/components/Sections/BookingSection.tsx +76 -0
  26. package/components/Sections/Contact.tsx +103 -0
  27. package/components/Sections/FAQSection.tsx +239 -0
  28. package/components/Sections/FeatureContent.tsx +113 -0
  29. package/components/Sections/FeaturedLink.tsx +103 -0
  30. package/components/Sections/FixedInfoCard.tsx +189 -0
  31. package/components/Sections/Gallery.tsx +83 -0
  32. package/components/Sections/Header.tsx +78 -0
  33. package/components/Sections/Hero.tsx +178 -0
  34. package/components/Sections/ImageSection.tsx +147 -0
  35. package/components/Sections/InstagramFeed.tsx +38 -0
  36. package/components/Sections/LinkList.tsx +76 -0
  37. package/components/Sections/LocationMap.tsx +202 -0
  38. package/components/Sections/Logo.tsx +61 -0
  39. package/components/Sections/MinimalFooter.tsx +78 -0
  40. package/components/Sections/MinimalHeader.tsx +81 -0
  41. package/components/Sections/MinimalNavigation.tsx +63 -0
  42. package/components/Sections/Navbar.tsx +258 -0
  43. package/components/Sections/PricingTable.tsx +106 -0
  44. package/components/Sections/ScrollingTextDivider.tsx +138 -0
  45. package/components/Sections/ScrollingTextDivider.tsx.bak +138 -0
  46. package/components/Sections/ServicesPreview.tsx +129 -0
  47. package/components/Sections/SocialBar.tsx +177 -0
  48. package/components/Sections/Team.tsx +80 -0
  49. package/components/Sections/Testimonials.tsx +92 -0
  50. package/components/Sections/TextSection.tsx +116 -0
  51. package/components/Sections/VideoSection.tsx +178 -0
  52. package/components/Sections/index.ts +57 -0
  53. package/components/index.ts +21 -0
  54. package/dist/index-DAai7Glf.d.mts +474 -0
  55. package/dist/index-DAai7Glf.d.ts +474 -0
  56. package/dist/index.d.mts +1075 -0
  57. package/dist/index.d.ts +1075 -0
  58. package/dist/index.js +22 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/index.mjs +22 -0
  61. package/dist/index.mjs.map +1 -0
  62. package/dist/styles/index.d.mts +1 -0
  63. package/dist/styles/index.d.ts +1 -0
  64. package/dist/styles/index.js +2 -0
  65. package/dist/styles/index.js.map +1 -0
  66. package/dist/styles/index.mjs +2 -0
  67. package/dist/styles/index.mjs.map +1 -0
  68. package/docs/API.md +849 -0
  69. package/docs/CALLBACKS.md +760 -0
  70. package/docs/COMPLETE_SESSION_SUMMARY.md +404 -0
  71. package/docs/DATA_SHAPES.md +684 -0
  72. package/docs/MIGRATION.md +662 -0
  73. package/docs/PAYMENT_INTEGRATION.md +766 -0
  74. package/docs/SESSION_SUMMARY.md +185 -0
  75. package/docs/STYLING.md +735 -0
  76. package/index.ts +4 -0
  77. package/lib/storage.ts +239 -0
  78. package/package.json +59 -0
  79. package/styles/animations.ts +210 -0
  80. package/styles/index.ts +1 -0
  81. package/tsconfig.json +32 -0
  82. package/tsup.config.ts +13 -0
  83. package/types/index.ts +369 -0
@@ -0,0 +1,474 @@
1
+ interface Service {
2
+ id: string;
3
+ name: string;
4
+ price: number;
5
+ duration: number;
6
+ description: string;
7
+ category?: string;
8
+ imageUrl?: string;
9
+ }
10
+ interface ServiceCategory {
11
+ id: string;
12
+ name: string;
13
+ description?: string;
14
+ services: Service[];
15
+ }
16
+ interface Addon {
17
+ id: string;
18
+ name: string;
19
+ price: number;
20
+ addonPrice?: number;
21
+ duration: number;
22
+ description: string;
23
+ imageUrl?: string;
24
+ }
25
+ interface OptInModule {
26
+ id: string;
27
+ label: string;
28
+ required: boolean;
29
+ formTitle?: string;
30
+ formFields?: FormField[];
31
+ renderCustomForm?: (onClose: () => void, onSubmitData: (data: any) => void, colors: {
32
+ primary: string;
33
+ secondary: string;
34
+ bookingText?: string;
35
+ }) => React.ReactNode;
36
+ }
37
+ interface FormField {
38
+ id: string;
39
+ label: string;
40
+ type: 'text' | 'email' | 'tel' | 'textarea' | 'select' | 'checkbox';
41
+ placeholder?: string;
42
+ required?: boolean;
43
+ options?: {
44
+ value: string;
45
+ label: string;
46
+ }[];
47
+ }
48
+ interface BookingData {
49
+ serviceId: string;
50
+ date: string;
51
+ time: string;
52
+ addonIds: string[];
53
+ contactInfo: ContactInfo;
54
+ optInData?: Record<string, any>;
55
+ paymentIntentId?: string;
56
+ totalPrice: number;
57
+ depositAmount: number;
58
+ }
59
+ interface ContactInfo {
60
+ name: string;
61
+ email: string;
62
+ phone: string;
63
+ notes?: string;
64
+ }
65
+ interface BackgroundConfig {
66
+ type: 'color' | 'gradient' | 'image';
67
+ value: string;
68
+ }
69
+ interface TransitionConfig {
70
+ style: 'slide' | 'fade';
71
+ speed: 'fast' | 'normal' | 'slow';
72
+ }
73
+ interface ProgressBarConfig {
74
+ style: 'dots' | 'bar' | 'minimal';
75
+ }
76
+ interface StepConfig {
77
+ enabled?: boolean;
78
+ settings?: Record<string, any>;
79
+ }
80
+ interface ServiceSelectionSettings {
81
+ headerContent?: {
82
+ value: string;
83
+ };
84
+ subheaderContent?: {
85
+ value: string;
86
+ };
87
+ serviceLayout?: 'grid' | 'list';
88
+ columns?: 1 | 2 | 3 | 4;
89
+ showPricing?: boolean;
90
+ showDuration?: boolean;
91
+ showDescription?: boolean;
92
+ enableCategories?: boolean;
93
+ categoryStyle?: 'dropdown' | 'tabs' | 'pills' | 'chips' | 'accordion';
94
+ defaultCategoryView?: 'all' | string;
95
+ policyImages?: PolicyImage[];
96
+ policyText?: string;
97
+ imageSpacing?: 'none' | 'small' | 'medium' | 'large';
98
+ imageBorderRadius?: string;
99
+ }
100
+ interface PolicyImage {
101
+ url: string;
102
+ alt?: string;
103
+ }
104
+ interface DateSelectionSettings {
105
+ headerContent?: {
106
+ value: string;
107
+ };
108
+ calendarView?: 'month' | 'week';
109
+ allowedDaysAhead?: number;
110
+ blockedDates?: string[];
111
+ }
112
+ interface TimeSelectionSettings {
113
+ headerContent?: {
114
+ value: string;
115
+ };
116
+ timeFormat?: '12h' | '24h';
117
+ showDuration?: boolean;
118
+ columns?: 2 | 3 | 4;
119
+ slotDuration?: number;
120
+ }
121
+ interface AddonSelectionSettings {
122
+ headerContent?: {
123
+ value: string;
124
+ };
125
+ subheaderContent?: {
126
+ value: string;
127
+ };
128
+ showPricing?: boolean;
129
+ showDuration?: boolean;
130
+ }
131
+ interface ContactFormSettings {
132
+ headerContent?: {
133
+ value: string;
134
+ };
135
+ requiredFields?: ('name' | 'email' | 'phone' | 'notes')[];
136
+ customFields?: FormField[];
137
+ }
138
+ interface DataProviders {
139
+ /** Fetch available services */
140
+ getServices: () => Promise<Service[]>;
141
+ /** Fetch available dates for a service */
142
+ getAvailableDates: (serviceId: string) => Promise<string[]>;
143
+ /** Fetch available time slots for a service on a specific date */
144
+ getAvailableTimes: (serviceId: string, date: string) => Promise<string[]>;
145
+ /** Fetch available add-ons for a service */
146
+ getAddons: (serviceId: string) => Promise<Addon[]>;
147
+ /** Optional: Fetch opt-in modules (custom forms) */
148
+ getOptInModules?: () => Promise<OptInModule[]>;
149
+ /** Optional: Fetch service categories */
150
+ getServiceCategories?: () => Promise<ServiceCategory[]>;
151
+ }
152
+ interface PaymentConfig {
153
+ squareApplicationId?: string;
154
+ squareLocationId?: string;
155
+ stripePublishableKey?: string;
156
+ depositPercentage?: number;
157
+ currency?: string;
158
+ }
159
+ interface BottomSheetProps {
160
+ isOpen: boolean;
161
+ onClose: () => void;
162
+ title?: string;
163
+ children: React.ReactNode;
164
+ isRequired?: boolean;
165
+ maxHeight?: string;
166
+ }
167
+ interface StepComponentProps {
168
+ config: StepConfig;
169
+ colors: {
170
+ primary: string;
171
+ secondary: string;
172
+ bookingText?: string;
173
+ };
174
+ onNext: () => void;
175
+ onBack: () => void;
176
+ }
177
+ interface ServiceSelectionStepProps extends StepComponentProps {
178
+ services: Service[];
179
+ categories?: ServiceCategory[];
180
+ selectedService: string | null;
181
+ onServiceSelect: (serviceId: string) => void;
182
+ }
183
+ interface DateSelectionStepProps extends StepComponentProps {
184
+ availableDates: string[];
185
+ selectedDate: string | null;
186
+ onDateSelect: (date: string) => void;
187
+ }
188
+ interface TimeSelectionStepProps extends StepComponentProps {
189
+ availableTimes: string[];
190
+ selectedTime: string | null;
191
+ onTimeSelect: (time: string) => void;
192
+ serviceDuration?: number;
193
+ }
194
+ interface AddonSelectionStepProps extends StepComponentProps {
195
+ addons: Addon[];
196
+ selectedAddons: string[];
197
+ onAddonsChange: (addonIds: string[]) => void;
198
+ }
199
+ interface ContactFormStepProps extends StepComponentProps {
200
+ contactInfo: Partial<ContactInfo>;
201
+ onContactInfoChange: (info: Partial<ContactInfo>) => void;
202
+ optInModules?: OptInModule[];
203
+ onOptInData?: (moduleId: string, data: any) => void;
204
+ }
205
+ interface ConfirmationStepProps extends StepComponentProps {
206
+ bookingData: Partial<BookingData>;
207
+ service?: Service;
208
+ addons?: Addon[];
209
+ paymentProvider: 'square' | 'stripe';
210
+ paymentConfig: PaymentConfig;
211
+ onConfirm: () => Promise<void>;
212
+ }
213
+ interface CyclePhase {
214
+ phase: 'avoid' | 'caution' | 'optimal' | 'neutral' | 'unknown';
215
+ color: string;
216
+ bgColor: string;
217
+ label: string;
218
+ icon: string;
219
+ description: string;
220
+ daysSinceStart?: number;
221
+ confidence?: number;
222
+ }
223
+ interface CyclePhaseMap {
224
+ [dateString: string]: CyclePhase;
225
+ }
226
+ interface CycleClient {
227
+ id: string;
228
+ cycle_opt_in: boolean;
229
+ cycle_last_period_start?: string;
230
+ cycle_avg_days?: number;
231
+ cycle_period_len?: number;
232
+ [key: string]: any;
233
+ }
234
+ /** Function that fetches cycle phase data for a date range */
235
+ type FetchCycleDataFn = (client: CycleClient, dateRange: string[]) => Promise<CyclePhaseMap>;
236
+ /** Callback when a cycle warning should be shown */
237
+ type CycleWarningCallback = (phase: CyclePhase, date: string) => void;
238
+ interface HoldTimerConfig {
239
+ enabled: boolean;
240
+ duration: number;
241
+ warningThreshold: number;
242
+ maxExtensions: number;
243
+ extensionDuration: number;
244
+ showActions: boolean;
245
+ showWarning: boolean;
246
+ }
247
+ interface HoldStatus {
248
+ holdId: string;
249
+ holdKey: string;
250
+ date: string;
251
+ time: string;
252
+ serviceId: string;
253
+ createdAt: number;
254
+ expiresAt: number;
255
+ extensions: number;
256
+ maxExtensions: number;
257
+ canExtend: boolean;
258
+ status: 'active' | 'warning' | 'expired';
259
+ }
260
+ interface HoldManagerCallbacks {
261
+ /** Called when hold is created successfully */
262
+ onHoldCreated?: (hold: HoldStatus) => void;
263
+ /** Called when hold is extended */
264
+ onHoldExtended?: (hold: HoldStatus) => void;
265
+ /** Called when hold is released manually */
266
+ onHoldReleased?: (holdId: string) => void;
267
+ /** Called when entering warning threshold */
268
+ onHoldWarning?: (hold: HoldStatus) => void;
269
+ /** Called when hold expires */
270
+ onHoldExpired?: (hold: HoldStatus) => void;
271
+ }
272
+ /** Function that creates a hold on the backend */
273
+ type CreateHoldFn = (data: {
274
+ date: string;
275
+ time: string;
276
+ serviceId: string;
277
+ serviceDuration: number;
278
+ }) => Promise<HoldStatus>;
279
+ /** Function that extends an existing hold */
280
+ type ExtendHoldFn = (holdId: string) => Promise<HoldStatus>;
281
+ /** Function that releases a hold */
282
+ type ReleaseHoldFn = (holdId: string) => Promise<void>;
283
+ type TransitionDirection = 'forward' | 'backward';
284
+ interface AnimationVariants {
285
+ enter: (direction: TransitionDirection) => Record<string, any>;
286
+ center: Record<string, any>;
287
+ exit: (direction: TransitionDirection) => Record<string, any>;
288
+ }
289
+
290
+ /**
291
+ * Animation duration calculator based on speed and reduced motion preference
292
+ */
293
+ declare function getAnimationDuration(speed: 'fast' | 'normal' | 'slow', reducedMotion?: boolean): number;
294
+ /**
295
+ * Slide animation variants for step transitions
296
+ */
297
+ declare function getSlideVariants(slideDistance?: number): AnimationVariants;
298
+ /**
299
+ * Fade animation variants for step transitions
300
+ */
301
+ declare function getFadeVariants(): AnimationVariants;
302
+ /**
303
+ * Get transition variants based on style preference
304
+ */
305
+ declare function getTransitionVariants(style: 'slide' | 'fade', slideDistance?: number): AnimationVariants;
306
+ /**
307
+ * Common animation configurations
308
+ */
309
+ declare const animations: {
310
+ /**
311
+ * Smooth easing curve for natural motion
312
+ */
313
+ easing: readonly [0.4, 0, 0.2, 1];
314
+ /**
315
+ * Spring configuration for elastic animations
316
+ */
317
+ spring: {
318
+ type: "spring";
319
+ damping: number;
320
+ stiffness: number;
321
+ };
322
+ /**
323
+ * Stagger children animation
324
+ */
325
+ staggerChildren: {
326
+ staggerChildren: number;
327
+ delayChildren: number;
328
+ };
329
+ /**
330
+ * Card hover animation
331
+ */
332
+ cardHover: {
333
+ scale: number;
334
+ transition: {
335
+ duration: number;
336
+ };
337
+ };
338
+ /**
339
+ * Button hover animation
340
+ */
341
+ buttonHover: {
342
+ scale: number;
343
+ transition: {
344
+ duration: number;
345
+ };
346
+ };
347
+ /**
348
+ * Fade in animation
349
+ */
350
+ fadeIn: {
351
+ initial: {
352
+ opacity: number;
353
+ };
354
+ animate: {
355
+ opacity: number;
356
+ };
357
+ exit: {
358
+ opacity: number;
359
+ };
360
+ };
361
+ /**
362
+ * Slide up animation (for bottom sheets)
363
+ */
364
+ slideUp: {
365
+ initial: {
366
+ y: string;
367
+ };
368
+ animate: {
369
+ y: number;
370
+ };
371
+ exit: {
372
+ y: string;
373
+ };
374
+ };
375
+ /**
376
+ * Scale in animation
377
+ */
378
+ scaleIn: {
379
+ initial: {
380
+ opacity: number;
381
+ scale: number;
382
+ };
383
+ animate: {
384
+ opacity: number;
385
+ scale: number;
386
+ };
387
+ exit: {
388
+ opacity: number;
389
+ scale: number;
390
+ };
391
+ };
392
+ /**
393
+ * Slide in from left
394
+ */
395
+ slideInLeft: {
396
+ initial: {
397
+ opacity: number;
398
+ x: number;
399
+ };
400
+ animate: {
401
+ opacity: number;
402
+ x: number;
403
+ };
404
+ };
405
+ /**
406
+ * Slide in from right
407
+ */
408
+ slideInRight: {
409
+ initial: {
410
+ opacity: number;
411
+ x: number;
412
+ };
413
+ animate: {
414
+ opacity: number;
415
+ x: number;
416
+ };
417
+ };
418
+ /**
419
+ * Backdrop animation
420
+ */
421
+ backdrop: {
422
+ initial: {
423
+ opacity: number;
424
+ };
425
+ animate: {
426
+ opacity: number;
427
+ };
428
+ exit: {
429
+ opacity: number;
430
+ };
431
+ };
432
+ };
433
+ /**
434
+ * Accessibility: Check for reduced motion preference
435
+ */
436
+ declare function shouldReduceMotion(): boolean;
437
+ /**
438
+ * Create stagger animation for list items
439
+ */
440
+ declare function createStaggerAnimation(itemCount: number, baseDelay?: number, delayIncrement?: number): {
441
+ initial: {
442
+ opacity: number;
443
+ y: number;
444
+ };
445
+ animate: {
446
+ opacity: number;
447
+ y: number;
448
+ };
449
+ transition: {
450
+ duration: number;
451
+ delay: number;
452
+ ease: readonly [0.4, 0, 0.2, 1];
453
+ };
454
+ }[];
455
+ /**
456
+ * Utility to create entrance animation with delay
457
+ */
458
+ declare function createEntranceAnimation(delay?: number, duration?: number): {
459
+ initial: {
460
+ opacity: number;
461
+ y: number;
462
+ };
463
+ animate: {
464
+ opacity: number;
465
+ y: number;
466
+ };
467
+ transition: {
468
+ duration: number;
469
+ delay: number;
470
+ ease: readonly [0.4, 0, 0.2, 1];
471
+ };
472
+ };
473
+
474
+ export { type Addon as A, type BottomSheetProps as B, type CreateHoldFn as C, type DateSelectionSettings as D, type ExtendHoldFn as E, type FetchCycleDataFn as F, type TransitionDirection as G, type HoldTimerConfig as H, type AnimationVariants as I, getAnimationDuration as J, getSlideVariants as K, getFadeVariants as L, getTransitionVariants as M, animations as N, type OptInModule as O, type PaymentConfig as P, shouldReduceMotion as Q, type ReleaseHoldFn as R, type Service as S, type TimeSelectionSettings as T, createStaggerAnimation as U, createEntranceAnimation as V, type ServiceCategory as a, type ServiceSelectionSettings as b, type AddonSelectionSettings as c, type ContactInfo as d, type ContactFormSettings as e, type CyclePhase as f, type CycleClient as g, type CycleWarningCallback as h, type HoldStatus as i, type FormField as j, type BookingData as k, type BackgroundConfig as l, type TransitionConfig as m, type ProgressBarConfig as n, type StepConfig as o, type PolicyImage as p, type DataProviders as q, type StepComponentProps as r, type ServiceSelectionStepProps as s, type DateSelectionStepProps as t, type TimeSelectionStepProps as u, type AddonSelectionStepProps as v, type ContactFormStepProps as w, type ConfirmationStepProps as x, type CyclePhaseMap as y, type HoldManagerCallbacks as z };