@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/README.md ADDED
@@ -0,0 +1,319 @@
1
+ # @oviah/booking-components
2
+
3
+ Reusable booking and section components for the OVIAH multi-tenant booking platform.
4
+
5
+ ## 📦 What's Included
6
+
7
+ - **21 Section Components** - Logo, Hero, Gallery, Testimonials, and more
8
+ - **Complete Booking Flow** - Multi-step booking with validation and animations
9
+ - **Universal Renderers** - SectionRenderer and BookingFlow orchestrator
10
+ - **UI Components** - BottomSheet, modals, and form elements
11
+ - **Animation Utilities** - Pre-built Framer Motion animations
12
+ - **Full TypeScript Support** - Complete type definitions
13
+
14
+ ## 🚀 Quick Start
15
+
16
+ ```tsx
17
+ import {
18
+ SectionRenderer,
19
+ BookingFlow,
20
+ Hero,
21
+ Gallery
22
+ } from '@oviah/booking-components';
23
+
24
+ // Render any section dynamically
25
+ <SectionRenderer
26
+ section={{
27
+ id: 'hero-1',
28
+ type: 'hero',
29
+ settings: {
30
+ headline: 'Welcome',
31
+ subheadline: 'Book your appointment today'
32
+ }
33
+ }}
34
+ theme={{
35
+ colors: { primary: '#D8C4FF', secondary: '#014421', text: '#000000' },
36
+ typography: { headingFont: 'Geist Sans' }
37
+ }}
38
+ />
39
+
40
+ // Complete booking flow
41
+ <BookingFlow
42
+ config={config}
43
+ colors={colors}
44
+ services={services}
45
+ onComplete={(bookingData) => {
46
+ console.log('Booking complete!', bookingData);
47
+ }}
48
+ />
49
+ ```
50
+
51
+ ## 📚 Documentation
52
+
53
+ - **[API Reference](./docs/API.md)** - Complete component API
54
+ - **[Data Shapes](./docs/DATA_SHAPES.md)** - Data structures and interfaces
55
+ - **[Callbacks](./docs/CALLBACKS.md)** - Event handling patterns
56
+ - **[Styling](./docs/STYLING.md)** - Theme customization guide
57
+ - **[Payment Integration](./docs/PAYMENT_INTEGRATION.md)** - Payment setup guide
58
+ - **[Migration Guide](./docs/MIGRATION.md)** - Migrate from inline components
59
+
60
+ ## 🎨 Components
61
+
62
+ ### Section Components (21 total)
63
+
64
+ All section components accept `colors` and `typography` props for theming:
65
+
66
+ - **Logo** - Logo/brand mark display
67
+ - **Header** - Text header with name, title, bio
68
+ - **FeaturedLink** - Large CTA button
69
+ - **LinkList** - List of clickable links
70
+ - **SocialBar** - Social media icons
71
+ - **InstagramFeed** - Instagram grid
72
+ - **MinimalHeader** - Sticky header
73
+ - **MinimalNavigation** - Navigation links
74
+ - **MinimalFooter** - Footer section
75
+ - **FeatureContent** - Feature with image/text
76
+ - **Hero** - Hero section with image
77
+ - **About** - About section
78
+ - **ServicesPreview** - Services grid/list
79
+ - **Gallery** - Image gallery
80
+ - **Testimonials** - Client testimonials
81
+ - **Team** - Team members
82
+ - **Contact** - Contact info/form
83
+ - **BeforeAfter** - Before/after comparisons
84
+ - **PricingTable** - Pricing plans
85
+ - **BookingSection** - Booking flow wrapper
86
+ - **FixedInfoCard** - Fixed corner card
87
+
88
+ ### Booking Flow Components
89
+
90
+ - **BookingFlow** - Main orchestrator
91
+ - **ServiceSelection** - Service picker
92
+ - **DateSelection** - Date picker
93
+ - **TimeSelection** - Time slot picker
94
+ - **AddonsSelection** - Add-ons picker
95
+ - **ContactForm** - Contact information
96
+ - **Confirmation** - Review and payment
97
+
98
+ ### UI Components
99
+
100
+ - **BottomSheet** - Slide-up modal
101
+ - **SectionRenderer** - Universal section renderer
102
+
103
+ ### Animation Utilities
104
+
105
+ - `createEntranceAnimation()` - Entry animations
106
+ - `createStaggerAnimation()` - Stagger lists
107
+ - `getSlideVariants()` - Slide transitions
108
+ - `getFadeVariants()` - Fade transitions
109
+
110
+ ## 🔧 Installation
111
+
112
+ ### For This Project (stylink-saas-dashboard)
113
+
114
+ This package is part of the workspace and is automatically linked:
115
+
116
+ ```bash
117
+ npm install
118
+ ```
119
+
120
+ ### For Your Tenant Template Project
121
+
122
+ You have **three options** to use this package in your other project:
123
+
124
+ #### Option 1: Local Link (Best for Active Development)
125
+
126
+ **Step 1 - In this project:**
127
+ ```bash
128
+ cd packages/booking-components
129
+ npm run build
130
+ npm link
131
+ ```
132
+
133
+ **Step 2 - In your tenant template project:**
134
+ ```bash
135
+ npm link @oviah/booking-components
136
+ ```
137
+
138
+ **To unlink later:**
139
+ ```bash
140
+ npm unlink @oviah/booking-components
141
+ npm install
142
+ ```
143
+
144
+ #### Option 2: File Path (Best for Local Development)
145
+
146
+ **In your tenant template's package.json:**
147
+ ```json
148
+ {
149
+ "dependencies": {
150
+ "@oviah/booking-components": "file:../stylink-saas-dashboard/packages/booking-components"
151
+ }
152
+ }
153
+ ```
154
+
155
+ Then run:
156
+ ```bash
157
+ npm install
158
+ ```
159
+
160
+ **Note:** Adjust the path based on where your projects are located relative to each other.
161
+
162
+ #### Option 3: GitHub Packages (Best for Production)
163
+
164
+ **Step 1 - Update this package's package.json:**
165
+ ```json
166
+ {
167
+ "repository": {
168
+ "type": "git",
169
+ "url": "https://github.com/YOUR_ORG/stylink-saas-dashboard.git",
170
+ "directory": "packages/booking-components"
171
+ },
172
+ "publishConfig": {
173
+ "registry": "https://npm.pkg.github.com"
174
+ }
175
+ }
176
+ ```
177
+
178
+ **Step 2 - Create .npmrc in packages/booking-components:**
179
+ ```
180
+ @oviah:registry=https://npm.pkg.github.com
181
+ //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
182
+ ```
183
+
184
+ **Step 3 - Build and publish:**
185
+ ```bash
186
+ cd packages/booking-components
187
+ npm run build
188
+ npm publish
189
+ ```
190
+
191
+ **Step 4 - In your tenant template, create .npmrc:**
192
+ ```
193
+ @oviah:registry=https://npm.pkg.github.com
194
+ //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
195
+ ```
196
+
197
+ **Step 5 - Install:**
198
+ ```bash
199
+ npm install @oviah/booking-components@1.0.0
200
+ ```
201
+
202
+ ## 💡 Usage Examples
203
+
204
+ ### Render Sections Dynamically
205
+
206
+ ```tsx
207
+ const sections = [
208
+ { id: '1', type: 'logo', settings: { logoUrl: '/logo.png' } },
209
+ { id: '2', type: 'hero', settings: { headline: 'Welcome' } },
210
+ { id: '3', type: 'gallery', settings: { images: [...] } }
211
+ ];
212
+
213
+ {sections.map(section => (
214
+ <SectionRenderer
215
+ key={section.id}
216
+ section={section}
217
+ theme={theme}
218
+ />
219
+ ))}
220
+ ```
221
+
222
+ ### Complete Booking Flow
223
+
224
+ ```tsx
225
+ <BookingFlow
226
+ config={{
227
+ steps: {
228
+ service_selection: { enabled: true, settings: {...} },
229
+ date_selection: { enabled: true, settings: {...} },
230
+ time_selection: { enabled: true, settings: {...} },
231
+ contact_form: { enabled: true, settings: {...} }
232
+ },
233
+ progressBar: { style: 'dots' },
234
+ transitions: { style: 'slide', speed: 'normal' }
235
+ }}
236
+ colors={{
237
+ primary: '#D8C4FF',
238
+ secondary: '#014421',
239
+ text: '#000000'
240
+ }}
241
+ services={services}
242
+ dates={availableDates}
243
+ times={availableTimes}
244
+ onComplete={(bookingData) => {
245
+ // Handle booking submission
246
+ }}
247
+ />
248
+ ```
249
+
250
+ ### Individual Components
251
+
252
+ ```tsx
253
+ import { Hero, Gallery, Testimonials } from '@oviah/booking-components';
254
+
255
+ <Hero
256
+ headline="Welcome to Our Salon"
257
+ subheadline="Professional beauty services"
258
+ heroImage="/hero.jpg"
259
+ ctaButton={{ text: 'Book Now', url: '/book' }}
260
+ layout="split"
261
+ colors={{ primary: '#D8C4FF', text: '#000000' }}
262
+ typography={{ headingFont: 'Geist Sans' }}
263
+ />
264
+
265
+ <Gallery
266
+ title="Our Work"
267
+ images={galleryImages}
268
+ columns={3}
269
+ colors={{ primary: '#D8C4FF', text: '#000000' }}
270
+ typography={{ headingFont: 'Geist Sans' }}
271
+ />
272
+
273
+ <Testimonials
274
+ title="What Clients Say"
275
+ testimonials={testimonials}
276
+ layout="grid"
277
+ colors={{ primary: '#D8C4FF', text: '#000000' }}
278
+ typography={{ headingFont: 'Geist Sans' }}
279
+ />
280
+ ```
281
+
282
+ ## 🎯 Key Features
283
+
284
+ ### ✅ Type-Safe
285
+
286
+ Full TypeScript support with complete type definitions:
287
+
288
+ ```typescript
289
+ import type {
290
+ Section,
291
+ BookingFlowConfig,
292
+ ColorScheme,
293
+ TypographyConfig
294
+ } from '@oviah/booking-components';
295
+ ```
296
+
297
+ ### ✅ Themeable
298
+
299
+ All components accept consistent color and typography props.
300
+
301
+ ### ✅ Responsive
302
+
303
+ Mobile-first design with automatic breakpoints.
304
+
305
+ ### ✅ Accessible
306
+
307
+ Semantic HTML, ARIA labels, keyboard navigation, screen reader support.
308
+
309
+ ### ✅ Animated
310
+
311
+ Smooth animations with Framer Motion that respect `prefers-reduced-motion`.
312
+
313
+ ## 🤝 Contributing
314
+
315
+ This is a private package for the OVIAH platform. For internal use only.
316
+
317
+ ## 📝 License
318
+
319
+ UNLICENSED - Private package for OVIAH
@@ -0,0 +1,402 @@
1
+ # Tenant Data Integration Guide
2
+
3
+ Complete guide for integrating the configuration data structure in your tenant template project.
4
+
5
+ ## 📊 Configuration Data Structure
6
+
7
+ ### Storage Location
8
+
9
+ **Database Table**: `business_configs`
10
+ **Column**: `page_builder` (JSONB)
11
+ **Access**: Via API endpoint `/api/studio/config/[businessId]`
12
+
13
+ The entire page configuration is stored as a JSON object in the `page_builder` column of the `business_configs` table.
14
+
15
+ ## 🗂️ Complete Config Object Structure
16
+
17
+ ```typescript
18
+ {
19
+ // Template metadata
20
+ template_id?: string;
21
+ version: string;
22
+
23
+ // Theme configuration
24
+ theme: {
25
+ colors: {
26
+ primary: string; // e.g., "#D8C4FF"
27
+ secondary: string; // e.g., "#014421"
28
+ text: string; // e.g., "#000000"
29
+ buttonText?: string; // e.g., "#FFFFFF"
30
+ linkBackground?: string;
31
+ linkText?: string;
32
+ bookingText?: string;
33
+ },
34
+ typography: {
35
+ headingFont: string; // e.g., "'Geist Sans', sans-serif"
36
+ bodyFont: string; // e.g., "'Inter', sans-serif"
37
+ bodySize: string; // e.g., "16px"
38
+ }
39
+ },
40
+
41
+ // Page background
42
+ background: {
43
+ type: 'color' | 'gradient' | 'image';
44
+ value: string; // Color hex, gradient CSS, or image URL
45
+ },
46
+
47
+ // Page sections array
48
+ sections: Array<{
49
+ id: string; // Unique identifier
50
+ type: string; // Section type (hero, about, etc.)
51
+ enabled: boolean; // Show/hide toggle
52
+ position: number; // Sort order
53
+ settings: {
54
+ // Type-specific settings
55
+ marginTop?: number;
56
+ marginBottom?: number;
57
+ paddingTop?: number;
58
+ paddingBottom?: number;
59
+ // ... section-specific props
60
+ }
61
+ }>,
62
+
63
+ // Booking flow configuration
64
+ booking_flow?: {
65
+ steps: {
66
+ service_selection: { enabled: boolean; settings: {...} },
67
+ date_selection: { enabled: boolean; settings: {...} },
68
+ time_selection: { enabled: boolean; settings: {...} },
69
+ addon_selection: { enabled: boolean; settings: {...} },
70
+ contact_form: { enabled: boolean; settings: {...} }
71
+ },
72
+ progressBar: {
73
+ type: 'stepped' | 'dots' | 'bar';
74
+ showStepNames?: boolean;
75
+ },
76
+ transitions: {
77
+ style: 'slide' | 'fade';
78
+ speed: 'fast' | 'normal' | 'slow';
79
+ },
80
+ background?: {
81
+ type: 'color' | 'gradient' | 'image';
82
+ value: string;
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ ## 🎨 How Background & Theme Are Handled
89
+
90
+ ### In the Studio
91
+
92
+ **Storage**: Config is saved to `business_configs.page_builder` as JSONB
93
+
94
+ **ThemeEditor Component** (`src/components/studio/editor/ThemeEditor.tsx`):
95
+ - Manages `config.theme.colors` (primary, secondary, text, buttonText)
96
+ - Manages `config.theme.typography` (headingFont, bodyFont, bodySize)
97
+ - Manages `config.background` (type, value)
98
+
99
+ **Auto-save**: Changes are debounced and saved automatically every 2 seconds
100
+
101
+ ### In the Preview/Tenant Page
102
+
103
+ **Fetching**: `GET /api/studio/config/[businessId]` returns the full config
104
+
105
+ **Application** (`src/app/[businessId]/page.tsx` lines 377-412):
106
+
107
+ ```typescript
108
+ // 1. Extract theme and background from config
109
+ const { theme, background } = config;
110
+ const themeColors = theme?.colors || {
111
+ primary: '#D8C4FF',
112
+ secondary: '#014421',
113
+ text: '#000000'
114
+ };
115
+ const themeTypography = theme?.typography || {
116
+ headingFont: 'Geist Sans',
117
+ bodyFont: 'Inter',
118
+ bodySize: '16px'
119
+ };
120
+
121
+ // 2. Calculate background style based on type
122
+ const backgroundStyle: React.CSSProperties =
123
+ background?.type === 'gradient'
124
+ ? { background: background.value }
125
+ : background?.type === 'image'
126
+ ? {
127
+ backgroundImage: `url(${background.value})`,
128
+ backgroundSize: 'cover',
129
+ backgroundPosition: 'center'
130
+ }
131
+ : { backgroundColor: background?.value || '#FFFFFF' };
132
+
133
+ // 3. Apply to root container
134
+ <div
135
+ className="min-h-screen"
136
+ style={{
137
+ ...backgroundStyle,
138
+ color: themeColors.text,
139
+ fontFamily: themeTypography.bodyFont,
140
+ fontSize: themeTypography.bodySize
141
+ }}
142
+ >
143
+ {/* Sections rendered here */}
144
+ </div>
145
+ ```
146
+
147
+ ## 🚀 Integration in Your Tenant Template
148
+
149
+ ### Step 1: Create API Endpoint
150
+
151
+ ```typescript
152
+ // app/api/config/[slug]/route.ts
153
+ import { createClient } from '@supabase/supabase-js';
154
+ import { NextRequest, NextResponse } from 'next/server';
155
+
156
+ const supabase = createClient(
157
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
158
+ process.env.SUPABASE_SERVICE_ROLE_KEY!
159
+ );
160
+
161
+ export async function GET(
162
+ request: NextRequest,
163
+ { params }: { params: Promise<{ slug: string }> }
164
+ ) {
165
+ const { slug } = await params;
166
+
167
+ const { data, error } = await supabase
168
+ .from('business_configs')
169
+ .select('page_builder, business_name, client_id')
170
+ .eq('client_id', slug)
171
+ .single();
172
+
173
+ if (error || !data) {
174
+ return NextResponse.json(
175
+ { error: 'Configuration not found' },
176
+ { status: 404 }
177
+ );
178
+ }
179
+
180
+ return NextResponse.json({
181
+ config: data.page_builder,
182
+ businessName: data.business_name,
183
+ clientId: data.client_id
184
+ });
185
+ }
186
+ ```
187
+
188
+ ### Step 2: Create Tenant Landing Page
189
+
190
+ ```typescript
191
+ // app/[slug]/page.tsx
192
+ 'use client';
193
+
194
+ import { use, useEffect, useState } from 'react';
195
+ import { SectionRenderer } from '@oviah/booking-components';
196
+
197
+ export default function TenantLandingPage({ params }) {
198
+ const { slug } = use(params);
199
+ const [config, setConfig] = useState(null);
200
+ const [loading, setLoading] = useState(true);
201
+
202
+ useEffect(() => {
203
+ async function loadConfig() {
204
+ try {
205
+ const res = await fetch(`/api/config/${slug}`);
206
+ if (!res.ok) throw new Error('Failed to load');
207
+
208
+ const data = await res.json();
209
+ setConfig(data.config);
210
+ } catch (error) {
211
+ console.error('Failed to load config:', error);
212
+ } finally {
213
+ setLoading(false);
214
+ }
215
+ }
216
+
217
+ loadConfig();
218
+ }, [slug]);
219
+
220
+ if (loading) return <div>Loading...</div>;
221
+ if (!config) return <div>Page not found</div>;
222
+
223
+ // Extract theme and background
224
+ const { theme, background, sections } = config;
225
+ const themeColors = theme?.colors || {
226
+ primary: '#D8C4FF',
227
+ secondary: '#014421',
228
+ text: '#000000'
229
+ };
230
+ const themeTypography = theme?.typography || {
231
+ headingFont: 'Geist Sans',
232
+ bodyFont: 'Inter',
233
+ bodySize: '16px'
234
+ };
235
+
236
+ // Calculate background style
237
+ const backgroundStyle =
238
+ background?.type === 'gradient'
239
+ ? { background: background.value }
240
+ : background?.type === 'image'
241
+ ? {
242
+ backgroundImage: `url(${background.value})`,
243
+ backgroundSize: 'cover',
244
+ backgroundPosition: 'center'
245
+ }
246
+ : { backgroundColor: background?.value || '#FFFFFF' };
247
+
248
+ // Filter and sort sections
249
+ const enabledSections = sections
250
+ .filter(s => s.enabled)
251
+ .sort((a, b) => a.position - b.position);
252
+
253
+ return (
254
+ <div
255
+ className="min-h-screen"
256
+ style={{
257
+ ...backgroundStyle,
258
+ color: themeColors.text,
259
+ fontFamily: themeTypography.bodyFont,
260
+ fontSize: themeTypography.bodySize
261
+ }}
262
+ >
263
+ {enabledSections.map((section) => {
264
+ const marginTop = section.settings?.marginTop || 0;
265
+ const marginBottom = section.settings?.marginBottom || 0;
266
+ const paddingTop = section.settings?.paddingTop || 0;
267
+ const paddingBottom = section.settings?.paddingBottom || 0;
268
+
269
+ return (
270
+ <div
271
+ key={section.id}
272
+ style={{
273
+ marginTop: `${marginTop}px`,
274
+ marginBottom: `${marginBottom}px`,
275
+ paddingTop: `${paddingTop}px`,
276
+ paddingBottom: `${paddingBottom}px`
277
+ }}
278
+ >
279
+ <SectionRenderer
280
+ section={section}
281
+ theme={theme}
282
+ enableInlineEditing={false}
283
+ />
284
+ </div>
285
+ );
286
+ })}
287
+ </div>
288
+ );
289
+ }
290
+ ```
291
+
292
+ ### Step 3: Create Booking Page
293
+
294
+ ```typescript
295
+ // app/[slug]/book/page.tsx
296
+ 'use client';
297
+
298
+ import { use, useEffect, useState } from 'react';
299
+ import { BookingFlow } from '@oviah/booking-components';
300
+
301
+ export default function BookingPage({ params }) {
302
+ const { slug } = use(params);
303
+ const [config, setConfig] = useState(null);
304
+
305
+ useEffect(() => {
306
+ async function loadConfig() {
307
+ const res = await fetch(`/api/config/${slug}`);
308
+ const data = await res.json();
309
+ setConfig(data.config);
310
+ }
311
+ loadConfig();
312
+ }, [slug]);
313
+
314
+ if (!config) return <div>Loading...</div>;
315
+
316
+ const themeColors = config.theme?.colors || {};
317
+
318
+ return (
319
+ <div className="container mx-auto px-4 py-16">
320
+ <BookingFlow
321
+ config={config.booking_flow || {}}
322
+ colors={themeColors}
323
+ services={[]} // Fetch from your API
324
+ dates={[]} // Fetch available dates
325
+ times={[]} // Fetch available times
326
+ addons={[]} // Fetch available addons
327
+ onComplete={(bookingData) => {
328
+ // Submit booking to your API
329
+ console.log('Booking submitted:', bookingData);
330
+ }}
331
+ />
332
+ </div>
333
+ );
334
+ }
335
+ ```
336
+
337
+ ## 📋 Background Type Examples
338
+
339
+ ### Solid Color
340
+ ```json
341
+ {
342
+ "background": {
343
+ "type": "color",
344
+ "value": "#FFFFFF"
345
+ }
346
+ }
347
+ ```
348
+
349
+ ### Gradient
350
+ ```json
351
+ {
352
+ "background": {
353
+ "type": "gradient",
354
+ "value": "linear-gradient(135deg, #D8C4FF 0%, #014421 100%)"
355
+ }
356
+ }
357
+ ```
358
+
359
+ ### Image
360
+ ```json
361
+ {
362
+ "background": {
363
+ "type": "image",
364
+ "value": "https://your-storage-url.com/backgrounds/image.jpg"
365
+ }
366
+ }
367
+ ```
368
+
369
+ ## 🎯 Key Points
370
+
371
+ 1. **All styling is centralized** in the `config` object
372
+ 2. **Background is separate** from theme (at `config.background`)
373
+ 3. **Theme contains** colors and typography (at `config.theme`)
374
+ 4. **Sections have individual spacing** (marginTop, marginBottom, paddingTop, paddingBottom)
375
+ 5. **Typography cascades** from the root container to all sections
376
+ 6. **Package components** automatically use theme colors and typography
377
+
378
+ ## 🔧 Environment Variables Needed
379
+
380
+ ```env
381
+ # Supabase
382
+ NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
383
+ SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
384
+
385
+ # App URL
386
+ NEXT_PUBLIC_APP_URL=https://your-domain.com
387
+ ```
388
+
389
+ ## 🚨 Common Gotchas
390
+
391
+ 1. **Don't forget defaults**: Always provide fallback values for theme colors and typography
392
+ 2. **Filter enabled sections**: Only render sections where `enabled: true`
393
+ 3. **Sort by position**: Always sort sections by the `position` field
394
+ 4. **Apply spacing correctly**: Margin/padding are stored in pixels (number), apply as `${value}px`
395
+ 5. **Background style calculation**: Handle all three types (color, gradient, image) differently
396
+
397
+ ## 📖 See Also
398
+
399
+ - [README.md](./README.md) - Package installation and usage
400
+ - [TENANT_SETUP.md](./TENANT_SETUP.md) - Step-by-step tenant setup
401
+ - [API.md](./docs/API.md) - Complete API reference
402
+ - [DATA_SHAPES.md](./docs/DATA_SHAPES.md) - Data structures reference