@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
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
+ }