@riverbankcms/sdk 0.1.0 → 0.2.1
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/dist/cli/index.js +4840 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/client/bookings.d.mts +82 -2
- package/dist/client/bookings.d.ts +82 -2
- package/dist/client/bookings.js +1623 -3
- package/dist/client/bookings.js.map +1 -1
- package/dist/client/bookings.mjs +1610 -5
- package/dist/client/bookings.mjs.map +1 -1
- package/dist/client/client.d.mts +8 -5
- package/dist/client/client.d.ts +8 -5
- package/dist/client/client.js +16856 -322
- package/dist/client/client.js.map +1 -1
- package/dist/client/client.mjs +16838 -307
- package/dist/client/client.mjs.map +1 -1
- package/dist/client/hooks.d.mts +10 -7
- package/dist/client/hooks.d.ts +10 -7
- package/dist/client/hooks.js +5074 -4
- package/dist/client/hooks.js.map +1 -1
- package/dist/client/hooks.mjs +5074 -4
- package/dist/client/hooks.mjs.map +1 -1
- package/dist/client/rendering/client.d.mts +7 -1
- package/dist/client/rendering/client.d.ts +7 -1
- package/dist/client/rendering/client.js +17388 -2
- package/dist/client/rendering/client.js.map +1 -1
- package/dist/client/rendering/client.mjs +17382 -2
- package/dist/client/rendering/client.mjs.map +1 -1
- package/dist/client/resolver-BhueZVxZ.d.mts +61 -0
- package/dist/client/resolver-BhueZVxZ.d.ts +61 -0
- package/dist/client/usePage-BBcFCxOU.d.ts +6297 -0
- package/dist/client/usePage-BydHcMYB.d.mts +6297 -0
- package/dist/server/Layout-CLg8oH_S.d.ts +44 -0
- package/dist/server/Layout-DK_9OOgb.d.mts +44 -0
- package/dist/server/chunk-3J46ILMJ.mjs +2111 -0
- package/dist/server/chunk-3J46ILMJ.mjs.map +1 -0
- package/dist/server/{chunk-JB4LIEFS.js → chunk-5R4NMVXA.js} +15 -8
- package/dist/server/chunk-5R4NMVXA.js.map +1 -0
- package/dist/server/{chunk-ADREPXFU.js → chunk-62ZJI564.js} +3 -3
- package/dist/server/{chunk-ADREPXFU.js.map → chunk-62ZJI564.js.map} +1 -1
- package/dist/server/chunk-7DS4Q3GA.mjs +333 -0
- package/dist/server/chunk-7DS4Q3GA.mjs.map +1 -0
- package/dist/server/chunk-BJTO5JO5.mjs +11 -0
- package/dist/server/{chunk-4Z5FBFRL.mjs → chunk-BPKYRPCQ.mjs} +7 -3
- package/dist/server/{chunk-4Z5FBFRL.mjs.map → chunk-BPKYRPCQ.mjs.map} +1 -1
- package/dist/server/chunk-DGUM43GV.js +11 -0
- package/dist/server/chunk-DGUM43GV.js.map +1 -0
- package/dist/server/chunk-EGTDJ4PL.js +5461 -0
- package/dist/server/chunk-EGTDJ4PL.js.map +1 -0
- package/dist/server/chunk-FK64TZBT.mjs +831 -0
- package/dist/server/chunk-FK64TZBT.mjs.map +1 -0
- package/dist/server/chunk-GKYNDDJS.js +2111 -0
- package/dist/server/chunk-GKYNDDJS.js.map +1 -0
- package/dist/server/chunk-HOY77YBF.js +333 -0
- package/dist/server/chunk-HOY77YBF.js.map +1 -0
- package/dist/server/chunk-INWKF3IC.js +831 -0
- package/dist/server/chunk-INWKF3IC.js.map +1 -0
- package/dist/server/{chunk-2RW5HAQQ.mjs → chunk-JTAERCX2.mjs} +2 -2
- package/dist/server/chunk-O5DC7MYW.mjs +9606 -0
- package/dist/server/chunk-O5DC7MYW.mjs.map +1 -0
- package/dist/server/{chunk-PEAXKTDU.mjs → chunk-OP2GHK27.mjs} +2 -2
- package/dist/server/{chunk-WKG57P2H.mjs → chunk-PN3CHDVX.mjs} +10 -3
- package/dist/server/{chunk-WKG57P2H.mjs.map → chunk-PN3CHDVX.mjs.map} +1 -1
- package/dist/server/chunk-SF63XAX7.js +9606 -0
- package/dist/server/chunk-SF63XAX7.js.map +1 -0
- package/dist/server/{chunk-F472SMKX.js → chunk-TO7FD6TQ.js} +4 -4
- package/dist/server/{chunk-F472SMKX.js.map → chunk-TO7FD6TQ.js.map} +1 -1
- package/dist/server/chunk-USQF2XTU.mjs +5461 -0
- package/dist/server/chunk-USQF2XTU.mjs.map +1 -0
- package/dist/server/{chunk-SW7LE4M3.js → chunk-XLVL5WPH.js} +12 -8
- package/dist/server/chunk-XLVL5WPH.js.map +1 -0
- package/dist/server/components-BzdA6NAc.d.mts +305 -0
- package/dist/server/components-DhIcstww.d.ts +305 -0
- package/dist/server/components.d.mts +13 -49
- package/dist/server/components.d.ts +13 -49
- package/dist/server/components.js +7 -4
- package/dist/server/components.js.map +1 -1
- package/dist/server/components.mjs +9 -6
- package/dist/server/components.mjs.map +1 -1
- package/dist/server/config-validation.d.mts +2 -2
- package/dist/server/config-validation.d.ts +2 -2
- package/dist/server/config-validation.js +6 -3
- package/dist/server/config-validation.js.map +1 -1
- package/dist/server/config-validation.mjs +5 -2
- package/dist/server/config.d.mts +3 -3
- package/dist/server/config.d.ts +3 -3
- package/dist/server/config.js +6 -3
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +5 -2
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/data.d.mts +9 -8
- package/dist/server/data.d.ts +9 -8
- package/dist/server/data.js +4 -2
- package/dist/server/data.js.map +1 -1
- package/dist/server/data.mjs +3 -1
- package/dist/server/{index-C6M0Wfjq.d.ts → index-BB28KAui.d.ts} +1 -1
- package/dist/server/{index-B0yI_V6Z.d.mts → index-C_FVup_o.d.mts} +1 -1
- package/dist/server/index.d.mts +1554 -5
- package/dist/server/index.d.ts +1554 -5
- package/dist/server/index.js +4 -4
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +4 -4
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/{loadContent-CJcbYF3J.d.ts → loadContent-AQOBf_gP.d.ts} +4 -4
- package/dist/server/{loadContent-zhlL4YSE.d.mts → loadContent-DBmprsB4.d.mts} +4 -4
- package/dist/server/loadPage-3ECPF426.js +11 -0
- package/dist/server/loadPage-3ECPF426.js.map +1 -0
- package/dist/server/{loadPage-CCf15nt8.d.mts → loadPage-BMg8PJxJ.d.ts} +146 -5
- package/dist/server/loadPage-LW273NYO.mjs +11 -0
- package/dist/server/loadPage-LW273NYO.mjs.map +1 -0
- package/dist/server/{loadPage-BYmVMk0V.d.ts → loadPage-pg4HimlK.d.mts} +146 -5
- package/dist/server/metadata.d.mts +9 -6
- package/dist/server/metadata.d.ts +9 -6
- package/dist/server/metadata.js +3 -1
- package/dist/server/metadata.js.map +1 -1
- package/dist/server/metadata.mjs +2 -0
- package/dist/server/metadata.mjs.map +1 -1
- package/dist/server/rendering/server.d.mts +9 -7
- package/dist/server/rendering/server.d.ts +9 -7
- package/dist/server/rendering/server.js +7 -4
- package/dist/server/rendering/server.js.map +1 -1
- package/dist/server/rendering/server.mjs +6 -3
- package/dist/server/rendering.d.mts +172 -9
- package/dist/server/rendering.d.ts +172 -9
- package/dist/server/rendering.js +12 -9
- package/dist/server/rendering.js.map +1 -1
- package/dist/server/rendering.mjs +14 -11
- package/dist/server/rendering.mjs.map +1 -1
- package/dist/server/routing.d.mts +9 -6
- package/dist/server/routing.d.ts +9 -6
- package/dist/server/routing.js +4 -2
- package/dist/server/routing.js.map +1 -1
- package/dist/server/routing.mjs +3 -1
- package/dist/server/routing.mjs.map +1 -1
- package/dist/server/schema-Bpy9N5ZI.d.mts +1870 -0
- package/dist/server/schema-Bpy9N5ZI.d.ts +1870 -0
- package/dist/server/server.d.mts +11 -8
- package/dist/server/server.d.ts +11 -8
- package/dist/server/server.js +7 -5
- package/dist/server/server.js.map +1 -1
- package/dist/server/server.mjs +6 -4
- package/dist/server/theme-bridge.js +13 -10
- package/dist/server/theme-bridge.js.map +1 -1
- package/dist/server/theme-bridge.mjs +10 -7
- package/dist/server/theme-bridge.mjs.map +1 -1
- package/dist/server/theme.js +3 -1
- package/dist/server/theme.js.map +1 -1
- package/dist/server/theme.mjs +2 -0
- package/dist/server/theme.mjs.map +1 -1
- package/dist/server/{types-BCeqWtI2.d.ts → types--u4GLCAY.d.ts} +1 -1
- package/dist/server/types-BprgZt-t.d.ts +4149 -0
- package/dist/server/types-C0G9IxWO.d.mts +4149 -0
- package/dist/server/{types-Bbo01M7P.d.mts → types-_nDnPHpv.d.mts} +27 -1
- package/dist/server/{types-Bbo01M7P.d.ts → types-_nDnPHpv.d.ts} +27 -1
- package/dist/server/{types-BCeqWtI2.d.mts → types-_zWJTgv0.d.mts} +1 -1
- package/package.json +15 -15
- package/dist/server/chunk-3KKZVGH4.mjs +0 -179
- package/dist/server/chunk-3KKZVGH4.mjs.map +0 -1
- package/dist/server/chunk-4Z3GPTCS.js +0 -179
- package/dist/server/chunk-4Z3GPTCS.js.map +0 -1
- package/dist/server/chunk-JB4LIEFS.js.map +0 -1
- package/dist/server/chunk-QQ6U4QX6.js +0 -120
- package/dist/server/chunk-QQ6U4QX6.js.map +0 -1
- package/dist/server/chunk-R5YGLRUG.mjs +0 -122
- package/dist/server/chunk-R5YGLRUG.mjs.map +0 -1
- package/dist/server/chunk-SW7LE4M3.js.map +0 -1
- package/dist/server/chunk-W3K7LVPS.mjs +0 -120
- package/dist/server/chunk-W3K7LVPS.mjs.map +0 -1
- package/dist/server/chunk-YHEZMVTS.js +0 -122
- package/dist/server/chunk-YHEZMVTS.js.map +0 -1
- package/dist/server/loadPage-DVH3DW6E.js +0 -9
- package/dist/server/loadPage-DVH3DW6E.js.map +0 -1
- package/dist/server/loadPage-PHQZ6XQZ.mjs +0 -9
- package/dist/server/types-C6gmRHLe.d.mts +0 -150
- package/dist/server/types-C6gmRHLe.d.ts +0 -150
- /package/dist/server/{loadPage-PHQZ6XQZ.mjs.map → chunk-BJTO5JO5.mjs.map} +0 -0
- /package/dist/server/{chunk-2RW5HAQQ.mjs.map → chunk-JTAERCX2.mjs.map} +0 -0
- /package/dist/server/{chunk-PEAXKTDU.mjs.map → chunk-OP2GHK27.mjs.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bookings/index.ts"],"sourcesContent":["/**\n * Booking system exports for SDK consumers\n *\n * This module re-exports booking components and hooks from @riverbankcms/blocks.\n * SDK sites should use the same booking components as the main platform.\n *\n * @example Using the booking form\n * ```tsx\n * import { BookingFormClient, useBookingFormConfig } from '@riverbankcms/sdk/bookings';\n *\n * function BookingPage() {\n * const { formConfig, services, isLoading, error } = useBookingFormConfig(siteId, formId);\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error}</div>;\n *\n * return (\n * <BookingFormClient\n * siteId={siteId}\n * formId={formId}\n * form={formConfig}\n * services={services}\n * />\n * );\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n// Re-export components and hooks from @riverbankcms/blocks\nexport {\n BookingFormClient,\n useBookingFormConfig,\n} from '@riverbankcms/blocks/client';\n\n// Re-export types from @riverbankcms/blocks\nexport type {\n BookingService,\n BookingFormConfig,\n} from '@riverbankcms/blocks/client';\n\n// Re-export SDK-specific types that may still be useful\nexport type {\n Service,\n TimeSlot,\n BookingFormSettings,\n BookingFormSchema,\n BookingFormField,\n BookingFormData,\n BookingSubmissionData,\n BookingSubmissionResult,\n} from './types';\n"],"mappings":";AA+BA;AAAA,EACE;AAAA,EACA;AAAA,OACK;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../blocks/src/system/runtime/utils/api-url.ts","../../../blocks/src/system/runtime/nodes/booking-form.client.tsx","../../../blocks/src/system/runtime/components/multi-step/MultiStepForm.tsx","../../../blocks/src/system/runtime/components/multi-step/MultiStepContext.tsx","../../../blocks/src/system/runtime/components/multi-step/useMultiStep.ts","../../../blocks/src/system/runtime/components/booking/SuccessMessage.tsx","../../../blocks/src/system/runtime/hooks/useBookingSteps.ts","../../../blocks/src/system/runtime/components/booking/ServiceResourceSelector.tsx","../../../blocks/src/system/runtime/components/booking/ServiceSelectionStep.tsx","../../../blocks/src/system/runtime/components/booking/DateTimeSelectionStep.tsx","../../../blocks/src/utils/date-formatting.ts","../../../blocks/src/system/runtime/components/booking/DatePicker.tsx","../../../blocks/src/system/runtime/components/booking/TimeSlotSelector.tsx","../../../blocks/src/system/runtime/hooks/useAvailableSlots.ts","../../../blocks/src/system/runtime/hooks/useAvailableDates.ts","../../../blocks/src/system/runtime/components/multi-step/DynamicFormFields.tsx","../../../blocks/src/system/runtime/hooks/useBookingSubmission.ts","../../../blocks/src/system/runtime/hooks/useBookingFormConfig.ts"],"sourcesContent":["/**\n * Get the CMS API base URL\n *\n * Resolves the API URL from environment variables.\n * Priority: NEXT_PUBLIC_BUILDER_API_URL (SDK sites) > NEXT_PUBLIC_DASHBOARD_URL (frontend app)\n *\n * @returns The base API URL (e.g., \"http://dashboard.local:4000/api\")\n * @throws Error if no valid URL is configured\n */\nexport function getCmsApiUrl(): string {\n // SDK sites use this (explicit API URL, no /api suffix needed)\n const builderApiUrl = process.env.NEXT_PUBLIC_BUILDER_API_URL;\n if (builderApiUrl) {\n return builderApiUrl.replace(/\\/$/, '');\n }\n\n // Frontend app uses this (dashboard URL, append /api)\n const dashboardUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;\n if (dashboardUrl) {\n const base = dashboardUrl.replace(/\\/$/, '');\n return `${base}/api`;\n }\n\n // Legacy fallback\n const legacyApiUrl = process.env.NEXT_PUBLIC_CMS_API_URL;\n if (legacyApiUrl) {\n return legacyApiUrl.replace(/\\/$/, '');\n }\n\n throw new Error(\n 'No API URL configured. Set NEXT_PUBLIC_BUILDER_API_URL (SDK sites) ' +\n 'or NEXT_PUBLIC_DASHBOARD_URL (frontend app).'\n );\n}\n","\"use client\"\n\nimport React, { useState } from 'react';\nimport { MultiStepForm } from '../components/multi-step/MultiStepForm';\nimport { SuccessMessage } from '../components/booking/SuccessMessage';\nimport { useBookingSteps, type BookingFormData } from '../hooks/useBookingSteps';\nimport { useBookingSubmission } from '../hooks/useBookingSubmission';\n\nexport type Service = {\n id: string;\n siteId: string;\n title: string;\n description?: string;\n durationMinutes?: number;\n};\n\nexport type FormConfig = {\n id: string;\n siteId: string;\n userId: string;\n name: string;\n schemaJson?: any;\n settingsJson?: any;\n createdAt: string;\n updatedAt: string;\n};\n\ntype BookingFormProps = {\n siteId: string;\n formId: string;\n className?: string;\n // Data passed from server-side data loaders\n form?: FormConfig | null;\n services?: Service[];\n};\n\n/**\n * BookingFormClient Component\n *\n * Multi-step booking form that:\n * 1. Receives form configuration and services from server-side loaders\n * 2. Shows service/resource selection if needed\n * 3. Shows date/time slot selection (fetched dynamically based on user selection)\n * 4. Shows dynamic custom fields\n * 5. Submits booking\n */\nexport const BookingFormClient: React.FC<BookingFormProps> = ({\n siteId: siteIdProp,\n formId,\n className,\n form,\n services = [],\n}) => {\n const [isSuccess, setIsSuccess] = useState(false);\n\n // Fallback: if siteId isn't passed via binding, get it from form data\n const siteId = siteIdProp || form?.siteId || '';\n\n // Validate required props\n React.useEffect(() => {\n if (!siteId) {\n console.error('[BookingFormClient] ERROR: siteId is missing!');\n }\n if (!form) {\n console.warn('[BookingFormClient] Form data not loaded');\n }\n console.log('[BookingFormClient] Loaded with:', {\n siteId,\n formId,\n hasForm: !!form,\n servicesCount: Array.isArray(services) ? services.length : 'not an array',\n servicesData: services,\n });\n }, [siteId, formId, form, services]);\n\n // Normalize form config to expected shape\n const formConfig = form ? {\n id: form.id,\n name: form.name,\n slug: '', // Not needed for booking form\n settings: form.settingsJson,\n schema: form.schemaJson,\n } : null;\n\n // Normalize services to ensure it's always an array\n const normalizedServices = React.useMemo(() => {\n if (Array.isArray(services)) {\n return services;\n }\n if (services && typeof services === 'object') {\n // If it's an object with a services property, extract it\n if ('services' in services) {\n return (services as any).services || [];\n }\n // If it's an object with service objects as values, convert to array\n return Object.values(services);\n }\n return [];\n }, [services]);\n\n // Build step array based on configuration\n const steps = useBookingSteps(siteId, formConfig, normalizedServices);\n\n const { submit } = useBookingSubmission(siteId);\n\n // Show error if form data is missing\n if (!form) {\n return (\n <div className={`rounded-lg border border-destructive bg-destructive/10 p-4 ${className ?? ''}`}>\n <p className=\"text-sm text-destructive\">Booking form not found. Please check your configuration.</p>\n </div>\n );\n }\n\n const handleComplete = async (data: BookingFormData) => {\n try {\n // Extract booking data\n const serviceId = data.serviceId || formConfig?.settings?.serviceId;\n const resourceId = data.resourceId || formConfig?.settings?.resourceId;\n\n if (!serviceId || !data.selectedSlot) {\n throw new Error('Missing required booking information');\n }\n\n // Calculate endAt from service duration\n console.log('[BookingFormClient] Looking for service:', {\n serviceId,\n availableServices: normalizedServices,\n });\n const selectedService = normalizedServices.find((s: Service) => s.id === serviceId);\n console.log('[BookingFormClient] Selected service:', selectedService);\n\n if (!selectedService) {\n throw new Error(`Service not found: ${serviceId}`);\n }\n if (!selectedService.durationMinutes) {\n throw new Error(\n `Service \"${selectedService.title || serviceId}\" is missing duration. ` +\n `Please update the service in the dashboard to include a duration (e.g., 30 minutes).`\n );\n }\n\n // Calculate end time by adding duration to start time\n const startDate = new Date(data.selectedSlot);\n const endDate = new Date(startDate.getTime() + selectedService.durationMinutes * 60 * 1000);\n\n // Extract custom fields (everything except our known booking fields)\n const bookingFields = new Set(['serviceId', 'resourceId', 'selectedDate', 'selectedSlot']);\n const customFields: Record<string, any> = {};\n for (const [key, value] of Object.entries(data)) {\n if (!bookingFields.has(key)) {\n customFields[key] = value;\n }\n }\n\n // Submit booking with formId\n await submit({\n formId,\n serviceId,\n resourceId,\n startAt: data.selectedSlot,\n endAt: endDate.toISOString(),\n customFields,\n timezone: 'UTC', // TODO: Get from resource or user preference\n });\n\n setIsSuccess(true);\n } catch (err) {\n console.error('Booking submission failed:', err);\n throw err;\n }\n };\n\n // Success state\n if (isSuccess) {\n const successMessage = formConfig?.settings?.successMessage ||\n 'Your appointment has been booked! Check your email for confirmation.';\n return <SuccessMessage message={successMessage} className={className} />;\n }\n\n // Multi-step form\n return (\n <div className={className}>\n <MultiStepForm<BookingFormData>\n steps={steps}\n initialData={{\n serviceId: formConfig?.settings?.serviceId,\n resourceId: formConfig?.settings?.resourceId,\n }}\n onComplete={handleComplete}\n progressStyle=\"steps\"\n persistToUrl={false}\n allowSkip={false}\n />\n </div>\n );\n};\n","'use client';\n\nimport React, { cloneElement, isValidElement } from 'react';\nimport { MultiStepContext } from './MultiStepContext';\nimport { useMultiStep } from './useMultiStep';\nimport type { MultiStepFormProps } from './types';\n\n/**\n * MultiStepForm Component\n *\n * Generic orchestrator for multi-step forms. Handles step navigation,\n * data accumulation, validation, and progress indication.\n *\n * Usage:\n * ```tsx\n * <MultiStepForm\n * steps={[\n * { id: 'step1', title: 'Step 1', component: <Step1 /> },\n * { id: 'step2', title: 'Step 2', component: <Step2 /> },\n * ]}\n * onComplete={(data) => console.log('Done!', data)}\n * progressStyle=\"dots\"\n * />\n * ```\n */\nexport function MultiStepForm<TData = any>({\n steps,\n initialData,\n onComplete,\n onStepChange,\n onDataChange,\n progressStyle = 'dots',\n className = '',\n persistToUrl = false,\n allowSkip = false,\n}: MultiStepFormProps<TData>): React.ReactElement {\n const context = useMultiStep<TData>({\n steps,\n initialData,\n onStepChange,\n onDataChange,\n onComplete,\n persistToUrl,\n });\n\n const {\n visibleSteps,\n currentStepIndex,\n goToNext,\n goToPrevious,\n goToStep,\n canGoNext,\n canGoBack,\n isFirstStep,\n isLastStep,\n errors,\n isValidating,\n isSubmitting,\n } = context;\n\n const currentStep = visibleSteps[currentStepIndex];\n\n if (!currentStep) {\n return (\n <div className=\"text-center py-12\">\n <p className=\"text-muted-foreground\">No steps available</p>\n </div>\n );\n }\n\n // Clone the step component and inject context if it's a React element\n const stepComponent = isValidElement(currentStep.component)\n ? cloneElement(currentStep.component as React.ReactElement<any>, {\n // Step components can access context via hooks, but we also pass key props\n stepId: currentStep.id,\n stepIndex: currentStepIndex,\n } as any) // Type assertion needed for dynamic props\n : currentStep.component;\n\n const showBackButton = !isFirstStep && !currentStep.hideBack && canGoBack;\n const showNextButton = !currentStep.isTerminal;\n const nextButtonLabel = isLastStep\n ? (currentStep.nextLabel || 'Complete')\n : (currentStep.nextLabel || 'Continue');\n const backButtonLabel = currentStep.backLabel || 'Back';\n\n return (\n <MultiStepContext.Provider value={context}>\n <div className={`multi-step-form ${className}`}>\n {/* Progress Indicator */}\n {progressStyle !== 'none' && (\n <div className=\"mb-8\">\n <ProgressIndicator\n steps={visibleSteps}\n currentIndex={currentStepIndex}\n style={progressStyle}\n onStepClick={allowSkip ? goToStep : undefined}\n />\n </div>\n )}\n\n {/* Step Content */}\n <div className=\"step-content\">{stepComponent}</div>\n\n {/* Error Display */}\n {Object.keys(errors).length > 0 && (\n <div className=\"mt-6 alert alert-error\">\n {errors._form && (\n <p className=\"text-sm font-medium\">{errors._form}</p>\n )}\n {Object.entries(errors)\n .filter(([key]) => key !== '_form')\n .map(([key, message]) => (\n <p key={key} className=\"text-sm\">\n {message}\n </p>\n ))}\n </div>\n )}\n\n {/* Navigation Buttons */}\n {(showBackButton || showNextButton) && (\n <div className=\"flex gap-3 mt-8\">\n {showBackButton && (\n <button\n type=\"button\"\n onClick={goToPrevious}\n disabled={!canGoBack}\n className=\"outline btn-md\"\n >\n {backButtonLabel}\n </button>\n )}\n\n {showNextButton && (\n <button\n type=\"button\"\n onClick={goToNext}\n disabled={!canGoNext}\n className=\"primary btn-md flex-1\"\n >\n {isValidating && (\n <span className=\"inline-block animate-spin rounded-full h-4 w-4 border-b-2 border-current\"></span>\n )}\n {isSubmitting && (\n <span className=\"inline-block animate-spin rounded-full h-4 w-4 border-b-2 border-current\"></span>\n )}\n {!isValidating && !isSubmitting && nextButtonLabel}\n {isValidating && 'Validating...'}\n {isSubmitting && 'Submitting...'}\n </button>\n )}\n </div>\n )}\n </div>\n </MultiStepContext.Provider>\n );\n}\n\n/**\n * ProgressIndicator Component\n *\n * Visual indicator of progress through the steps.\n * Supports dots, steps, and bar styles.\n */\nfunction ProgressIndicator({\n steps,\n currentIndex,\n style,\n onStepClick,\n}: {\n steps: Array<{ id: string; title: string }>;\n currentIndex: number;\n style: 'dots' | 'steps' | 'bar';\n onStepClick?: (index: number) => void;\n}) {\n if (style === 'dots') {\n return (\n <div className=\"flex items-center justify-center gap-2\">\n {steps.map((step, index) => {\n const isActive = index === currentIndex;\n const isCompleted = index < currentIndex;\n const isClickable = onStepClick && index <= currentIndex;\n\n return (\n <button\n key={step.id}\n type=\"button\"\n onClick={isClickable ? () => onStepClick(index) : undefined}\n disabled={!isClickable}\n className={`\n step-dot transition-all\n ${isActive ? 'step-dot-active' : ''}\n ${isCompleted ? 'step-dot-complete' : ''}\n ${isClickable ? 'cursor-pointer hover:scale-125' : 'cursor-default'}\n `}\n aria-label={step.title}\n />\n );\n })}\n </div>\n );\n }\n\n if (style === 'steps') {\n return (\n <div className=\"flex items-center justify-between\">\n {steps.map((step, index) => {\n const isActive = index === currentIndex;\n const isCompleted = index < currentIndex;\n const isClickable = onStepClick && index <= currentIndex;\n const isLast = index === steps.length - 1;\n\n return (\n <div key={step.id} className=\"flex items-center flex-1\">\n <button\n type=\"button\"\n onClick={isClickable ? () => onStepClick(index) : undefined}\n disabled={!isClickable}\n className={`\n flex items-center gap-2\n ${isClickable ? 'cursor-pointer' : 'cursor-default'}\n `}\n >\n <div\n className={`\n step-circle transition-colors\n ${isActive ? 'step-circle-active' : ''}\n ${isCompleted ? 'step-circle-complete' : ''}\n `}\n >\n {isCompleted ? '✓' : index + 1}\n </div>\n <span\n className={`\n text-sm hidden sm:inline\n ${isActive ? 'font-medium' : ''}\n ${isCompleted || !isActive ? 'status-muted' : ''}\n `}\n >\n {step.title}\n </span>\n </button>\n\n {!isLast && (\n <div className=\"step-connector mx-2 hidden sm:block\" />\n )}\n </div>\n );\n })}\n </div>\n );\n }\n\n // Bar style\n const progress = ((currentIndex + 1) / steps.length) * 100;\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex justify-between text-sm status-muted\">\n <span>\n Step {currentIndex + 1} of {steps.length}\n </span>\n <span>{Math.round(progress)}%</span>\n </div>\n <div className=\"progress-bar\">\n <div\n className=\"progress-fill\"\n style={{ width: `${progress}%` }}\n />\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { createContext, useContext } from 'react';\nimport type { MultiStepContextValue } from './types';\n\n/**\n * React Context for Multi-Step Form State\n *\n * Provides step navigation, data management, and validation state\n * to all child components within a multi-step form.\n */\nexport const MultiStepContext = createContext<MultiStepContextValue | null>(null);\n\n/**\n * Hook to access multi-step form context\n *\n * Must be used within a MultiStepForm component.\n *\n * @throws Error if used outside of MultiStepForm\n * @returns The multi-step context value with full state and navigation\n */\nexport function useMultiStepContext<TData = any>(): MultiStepContextValue<TData> {\n const context = useContext(MultiStepContext);\n\n if (!context) {\n throw new Error(\n 'useMultiStepContext must be used within a MultiStepForm component. ' +\n 'Make sure your component is wrapped in <MultiStepForm>.'\n );\n }\n\n return context as MultiStepContextValue<TData>;\n}\n\n/**\n * Hook to access multi-step form data\n *\n * Convenience hook that returns just the data portion of the context.\n * Useful for components that only need to read/write data.\n *\n * @returns Object with data and updateData function\n */\nexport function useMultiStepData<TData = any>(): {\n data: Partial<TData>;\n updateData: (updates: Partial<TData>) => void;\n} {\n const { data, updateData } = useMultiStepContext<TData>();\n return { data, updateData };\n}\n\n/**\n * Hook to access multi-step navigation\n *\n * Convenience hook that returns just the navigation functions.\n * Useful for custom step components that need to control navigation.\n *\n * @returns Object with navigation functions and state\n */\nexport function useMultiStepNavigation(): {\n goToNext: () => Promise<void>;\n goToPrevious: () => void;\n goToStep: (stepIndex: number) => void;\n goToStepById: (stepId: string) => void;\n canGoNext: boolean;\n canGoBack: boolean;\n isFirstStep: boolean;\n isLastStep: boolean;\n currentStepIndex: number;\n currentStepId: string;\n} {\n const {\n goToNext,\n goToPrevious,\n goToStep,\n goToStepById,\n canGoNext,\n canGoBack,\n isFirstStep,\n isLastStep,\n currentStepIndex,\n currentStepId,\n } = useMultiStepContext();\n\n return {\n goToNext,\n goToPrevious,\n goToStep,\n goToStepById,\n canGoNext,\n canGoBack,\n isFirstStep,\n isLastStep,\n currentStepIndex,\n currentStepId,\n };\n}\n","'use client';\n\nimport { useState, useCallback, useMemo, useEffect } from 'react';\nimport type { Step, MultiStepContextValue, StepValidationResult } from './types';\n\n/**\n * Core hook for multi-step form logic\n *\n * Manages step navigation, data accumulation, and validation.\n * This is the engine that powers the MultiStepForm component.\n */\nexport function useMultiStep<TData = any>({\n steps,\n initialData = {},\n onStepChange,\n onDataChange,\n onComplete,\n persistToUrl = false,\n}: {\n steps: Step<TData>[];\n initialData?: Partial<TData>;\n onStepChange?: (stepId: string, stepIndex: number) => void;\n onDataChange?: (data: Partial<TData>) => void;\n onComplete?: (data: TData) => void | Promise<void>;\n persistToUrl?: boolean;\n}): MultiStepContextValue<TData> {\n // State\n const [data, setData] = useState<Partial<TData>>(initialData);\n const [currentStepIndex, setCurrentStepIndex] = useState(0);\n const [errors, setErrors] = useState<Record<string, string>>({});\n const [isValidating, setIsValidating] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n // Filter steps based on conditions\n const visibleSteps = useMemo(() => {\n return steps.filter((step) => {\n if (!step.condition) return true;\n return step.condition(data);\n });\n }, [steps, data]);\n\n const currentStep = visibleSteps[currentStepIndex];\n const currentStepId = currentStep?.id || '';\n\n // Sync step to URL if enabled\n useEffect(() => {\n if (persistToUrl && currentStep) {\n const url = new URL(window.location.href);\n url.searchParams.set('step', currentStep.id);\n window.history.replaceState({}, '', url.toString());\n }\n }, [currentStepIndex, currentStep, persistToUrl]);\n\n // Read step from URL on mount\n useEffect(() => {\n if (persistToUrl) {\n const url = new URL(window.location.href);\n const stepId = url.searchParams.get('step');\n if (stepId) {\n const stepIndex = visibleSteps.findIndex((s) => s.id === stepId);\n if (stepIndex !== -1) {\n setCurrentStepIndex(stepIndex);\n }\n }\n }\n // Only run on mount - empty deps array is intentional\n }, []);\n\n // Notify on step change\n useEffect(() => {\n if (onStepChange && currentStep) {\n onStepChange(currentStep.id, currentStepIndex);\n }\n }, [currentStepIndex, currentStep, onStepChange]);\n\n // Update data\n const updateData = useCallback(\n (updates: Partial<TData>) => {\n setData((prev) => {\n const newData = { ...prev, ...updates };\n onDataChange?.(newData);\n return newData;\n });\n // Clear errors when data changes\n setErrors({});\n },\n [onDataChange]\n );\n\n // Validate current step\n const validateCurrentStep = useCallback(async (): Promise<boolean> => {\n if (!currentStep?.validate) return true;\n\n setIsValidating(true);\n setErrors({});\n\n try {\n const result: StepValidationResult = await currentStep.validate(data);\n\n if (result.valid) {\n return true;\n } else {\n setErrors(result.errors);\n return false;\n }\n } catch (error) {\n console.error('Step validation error:', error);\n setErrors({ _form: 'Validation failed. Please try again.' });\n return false;\n } finally {\n setIsValidating(false);\n }\n }, [currentStep, data]);\n\n // Navigate to next step\n const goToNext = useCallback(async () => {\n // Validate current step\n const isValid = await validateCurrentStep();\n if (!isValid) return;\n\n // Check if this is the last step\n if (currentStepIndex === visibleSteps.length - 1) {\n // Complete the form\n if (onComplete) {\n setIsSubmitting(true);\n try {\n await onComplete(data as TData);\n } catch (error) {\n console.error('Form submission error:', error);\n setErrors({ _form: 'Submission failed. Please try again.' });\n } finally {\n setIsSubmitting(false);\n }\n }\n return;\n }\n\n // Move to next step\n setCurrentStepIndex((prev) => Math.min(prev + 1, visibleSteps.length - 1));\n setErrors({});\n }, [currentStepIndex, visibleSteps.length, validateCurrentStep, onComplete, data]);\n\n // Navigate to previous step\n const goToPrevious = useCallback(() => {\n setCurrentStepIndex((prev) => Math.max(prev - 1, 0));\n setErrors({});\n }, []);\n\n // Navigate to specific step by index\n const goToStep = useCallback(\n (stepIndex: number) => {\n if (stepIndex >= 0 && stepIndex < visibleSteps.length) {\n setCurrentStepIndex(stepIndex);\n setErrors({});\n }\n },\n [visibleSteps.length]\n );\n\n // Navigate to specific step by ID\n const goToStepById = useCallback(\n (stepId: string) => {\n const stepIndex = visibleSteps.findIndex((s) => s.id === stepId);\n if (stepIndex !== -1) {\n goToStep(stepIndex);\n }\n },\n [visibleSteps, goToStep]\n );\n\n // Reset form\n const reset = useCallback(() => {\n setData(initialData);\n setCurrentStepIndex(0);\n setErrors({});\n setIsValidating(false);\n setIsSubmitting(false);\n }, [initialData]);\n\n // Computed properties\n const canGoNext = !isValidating && !isSubmitting;\n const canGoBack = currentStepIndex > 0 && !isValidating && !isSubmitting;\n const isFirstStep = currentStepIndex === 0;\n const isLastStep = currentStepIndex === visibleSteps.length - 1;\n\n return {\n currentStepIndex,\n currentStepId,\n visibleSteps,\n data,\n errors,\n isValidating,\n isSubmitting,\n goToNext,\n goToPrevious,\n goToStep,\n goToStepById,\n updateData,\n canGoNext,\n canGoBack,\n isFirstStep,\n isLastStep,\n reset,\n };\n}\n","/**\n * SuccessMessage Component\n *\n * Displays success message after successful appointment booking.\n */\n\nimport React from 'react';\n\ntype SuccessMessageProps = {\n message: string;\n className?: string;\n};\n\nexport const SuccessMessage: React.FC<SuccessMessageProps> = ({ message, className }) => {\n return (\n <div\n className={`alert alert-success text-sm ${className ?? ''}`}\n role=\"alert\"\n aria-live=\"polite\"\n >\n {message}\n </div>\n );\n};\n","/**\n * Hook to build multi-step booking flow\n */\n\nimport React, { useMemo } from 'react';\nimport type { Step } from '../components/multi-step/types';\nimport type { BookingFormConfig, Service } from './useBookingFormConfig';\nimport { ServiceSelectionStep } from '../components/booking/ServiceSelectionStep';\nimport { DateTimeSelectionStep } from '../components/booking/DateTimeSelectionStep';\nimport { DynamicFormFields } from '../components/multi-step/DynamicFormFields';\n\nexport type BookingFormData = {\n serviceId?: string;\n resourceId?: string;\n selectedDate?: string;\n selectedSlot?: string;\n [key: string]: any; // Dynamic form fields\n};\n\n/**\n * Build the array of steps for the booking flow\n *\n * Steps are conditionally included based on form configuration:\n * - Service selection: Only if multiple services available\n * - Date/time selection: Always included\n * - Custom fields: Only if form has fields defined\n */\nexport function useBookingSteps(\n siteId: string,\n formConfig: BookingFormConfig | null,\n services: Service[]\n): Step<BookingFormData>[] {\n return useMemo<Step<BookingFormData>[]>(() => {\n if (!formConfig) return [];\n\n const stepsArray: Step<BookingFormData>[] = [];\n\n // Determine the service ID to use\n // Priority: form settings > single available service\n const effectiveServiceId = formConfig.settings?.serviceId ||\n (services.length === 1 ? services[0].id : undefined);\n\n // Step 1: Service/Resource Selection (conditional)\n const needsServiceSelection =\n (!formConfig.settings?.serviceId && services.length > 1) ||\n (formConfig.settings?.serviceIds && formConfig.settings.serviceIds.length > 1);\n\n if (needsServiceSelection) {\n stepsArray.push({\n id: 'service-selection',\n title: 'Select Service',\n component: React.createElement(ServiceSelectionStep, { siteId, services }),\n condition: () => needsServiceSelection,\n validate: (data) => {\n if (!data.serviceId) {\n return { valid: false, errors: { _form: 'Please select a service' } };\n }\n return { valid: true };\n },\n });\n }\n\n // Step 2: Date/Time Selection\n // Pass the single service info to display when there's only one service\n const singleService = services.length === 1 ? services[0] : undefined;\n stepsArray.push({\n id: 'datetime-selection',\n title: 'Select Date & Time',\n component: React.createElement(DateTimeSelectionStep, {\n siteId,\n preSelectedServiceId: effectiveServiceId,\n preSelectedResourceId: formConfig.settings?.resourceId,\n singleService,\n }),\n validate: (data) => {\n if (!data.selectedSlot) {\n return { valid: false, errors: { _form: 'Please select a date and time' } };\n }\n return { valid: true };\n },\n });\n\n // Step 3: Custom Fields (if any)\n if (formConfig.schema?.fields && formConfig.schema.fields.length > 0) {\n stepsArray.push({\n id: 'custom-fields',\n title: 'Your Information',\n component: React.createElement(DynamicFormFields, { fields: formConfig.schema.fields }),\n validate: (data) => {\n const errors: Record<string, string> = {};\n\n for (const field of formConfig.schema!.fields) {\n if (field.required && !data[field.id]) {\n errors[field.id] = `${field.label} is required`;\n }\n }\n\n if (Object.keys(errors).length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true };\n },\n });\n }\n\n return stepsArray;\n }, [formConfig, services, siteId]);\n}\n","'use client';\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { getCmsApiUrl } from '../../utils/api-url';\n\nexport interface Service {\n id: string;\n title: string;\n description?: string;\n durationMinutes?: number;\n}\n\nexport interface Resource {\n id: string;\n displayName: string;\n title?: string;\n}\n\nexport interface ServiceResourceSelectorProps {\n siteId: string;\n services: Service[];\n preSelectedServiceId?: string;\n preSelectedResourceId?: string;\n onSelect: (selection: { serviceId: string; resourceId?: string }) => void;\n onBack?: () => void;\n heading?: string;\n description?: string;\n}\n\n/**\n * ServiceResourceSelector Component\n *\n * Handles Step 1 of the booking flow: service and resource selection.\n * Only shown when the booking form allows multiple services or when\n * resource selection is needed.\n *\n * Features:\n * - Service selection (if multiple services available)\n * - Resource selection (if multiple resources available for selected service)\n * - Auto-skips if only one option available\n * - Fetches resources dynamically when service is selected\n */\nexport function ServiceResourceSelector({\n siteId,\n services,\n preSelectedServiceId,\n preSelectedResourceId,\n onSelect,\n onBack,\n heading = 'Select Service',\n description = 'Choose the service you\\'d like to book',\n}: ServiceResourceSelectorProps): React.ReactElement {\n const [selectedServiceId, setSelectedServiceId] = useState<string | undefined>(\n preSelectedServiceId\n );\n const [selectedResourceId, setSelectedResourceId] = useState<string | undefined>(\n preSelectedResourceId\n );\n const [resources, setResources] = useState<Resource[]>([]);\n const [isLoadingResources, setIsLoadingResources] = useState(false);\n const [resourceError, setResourceError] = useState<string | null>(null);\n\n const showServiceSelect = !preSelectedServiceId && services.length > 1;\n const showResourceSelect = resources.length > 1 && !preSelectedResourceId;\n\n // Load resources when service is selected\n const handleServiceChange = useCallback(async (serviceId: string) => {\n setSelectedServiceId(serviceId);\n setSelectedResourceId(undefined);\n setResourceError(null);\n\n // Fetch resources for this service\n try {\n setIsLoadingResources(true);\n const apiUrl = getCmsApiUrl();\n const response = await fetch(\n `${apiUrl}/sites/${siteId}/bookings/resources/reference?serviceId=${serviceId}`\n );\n\n if (!response.ok) {\n throw new Error('Failed to load resources');\n }\n\n const data = await response.json();\n const loadedResources = data.options?.map((opt: any) => ({\n id: opt.id,\n displayName: opt.label,\n })) || [];\n\n setResources(loadedResources);\n } catch (err) {\n console.error('Failed to load resources:', err);\n setResourceError('Failed to load practitioners. Please try again.');\n setResources([]);\n } finally {\n setIsLoadingResources(false);\n }\n }, [siteId]);\n\n const handleContinue = () => {\n if (selectedServiceId) {\n onSelect({\n serviceId: selectedServiceId,\n resourceId: selectedResourceId === '__any__' ? undefined : selectedResourceId,\n });\n }\n };\n\n const canContinue = selectedServiceId && !isLoadingResources;\n\n // Auto-select if only one service\n useEffect(() => {\n if (services.length === 1 && !selectedServiceId) {\n handleServiceChange(services[0].id);\n }\n }, [services, selectedServiceId, handleServiceChange]);\n\n return (\n <div className=\"space-y-6 max-w-2xl mx-auto\">\n {/* Header */}\n <div>\n <h2 className=\"text-2xl font-bold\">{heading}</h2>\n {description && <p className=\"text-muted-foreground mt-2\">{description}</p>}\n </div>\n\n {/* Service Selection */}\n {showServiceSelect && (\n <div className=\"space-y-3\">\n <label className=\"text-sm font-medium\">Service</label>\n <div className=\"grid gap-3\">\n {services.map((service) => (\n <button\n key={service.id}\n type=\"button\"\n onClick={() => handleServiceChange(service.id)}\n className={`\n relative p-4 rounded-lg border-2 text-left transition-all\n ${\n selectedServiceId === service.id\n ? 'border-primary bg-primary/5'\n : 'border-border hover:border-primary/50'\n }\n `}\n >\n <div className=\"flex items-start justify-between\">\n <div>\n <div className=\"font-medium\">{service.title}</div>\n {service.description && (\n <div className=\"text-sm text-muted-foreground mt-1\">\n {service.description}\n </div>\n )}\n {service.durationMinutes && (\n <div className=\"text-sm text-muted-foreground mt-1\">\n {service.durationMinutes} minutes\n </div>\n )}\n </div>\n {selectedServiceId === service.id && (\n <div className=\"flex-shrink-0 w-5 h-5 rounded-full bg-primary flex items-center justify-center\">\n <svg\n className=\"w-3 h-3 text-primary-foreground\"\n fill=\"none\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path d=\"M5 13l4 4L19 7\"></path>\n </svg>\n </div>\n )}\n </div>\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/* Resource Selection */}\n {showResourceSelect && selectedServiceId && !isLoadingResources && (\n <div className=\"space-y-3\">\n <label className=\"text-sm font-medium\">Practitioner (Optional)</label>\n <p className=\"text-sm text-muted-foreground\">\n Choose a specific practitioner or select \"Any Available\"\n </p>\n <div className=\"grid gap-3\">\n <button\n type=\"button\"\n onClick={() => setSelectedResourceId('__any__')}\n className={`\n relative p-4 rounded-lg border-2 text-left transition-all\n ${\n selectedResourceId === '__any__'\n ? 'border-primary bg-primary/5'\n : 'border-border hover:border-primary/50'\n }\n `}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"font-medium\">Any Available</div>\n {selectedResourceId === '__any__' && (\n <div className=\"flex-shrink-0 w-5 h-5 rounded-full bg-primary flex items-center justify-center\">\n <svg\n className=\"w-3 h-3 text-primary-foreground\"\n fill=\"none\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path d=\"M5 13l4 4L19 7\"></path>\n </svg>\n </div>\n )}\n </div>\n </button>\n {resources.map((resource) => (\n <button\n key={resource.id}\n type=\"button\"\n onClick={() => setSelectedResourceId(resource.id)}\n className={`\n relative p-4 rounded-lg border-2 text-left transition-all\n ${\n selectedResourceId === resource.id\n ? 'border-primary bg-primary/5'\n : 'border-border hover:border-primary/50'\n }\n `}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"font-medium\">{resource.displayName}</div>\n {selectedResourceId === resource.id && (\n <div className=\"flex-shrink-0 w-5 h-5 rounded-full bg-primary flex items-center justify-center\">\n <svg\n className=\"w-3 h-3 text-primary-foreground\"\n fill=\"none\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path d=\"M5 13l4 4L19 7\"></path>\n </svg>\n </div>\n )}\n </div>\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/* Loading State */}\n {isLoadingResources && (\n <div className=\"text-center py-8\">\n <div className=\"inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-primary\"></div>\n <p className=\"text-sm text-muted-foreground mt-2\">Loading practitioners...</p>\n </div>\n )}\n\n {/* Error State */}\n {resourceError && (\n <div className=\"alert alert-error text-sm\">\n {resourceError}\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex gap-3\">\n {onBack && (\n <button\n type=\"button\"\n onClick={onBack}\n className=\"px-6 py-2 rounded-lg border border-border hover:bg-muted transition-colors\"\n >\n Back\n </button>\n )}\n <button\n type=\"button\"\n onClick={handleContinue}\n disabled={!canContinue}\n className=\"flex-1 px-6 py-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n Continue to Date Selection\n </button>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport React from 'react';\nimport { useMultiStepData } from '../multi-step/MultiStepContext';\nimport { ServiceResourceSelector } from './ServiceResourceSelector';\nimport type { Service } from '../../hooks/useBookingFormConfig';\n\ninterface ServiceSelectionStepProps {\n siteId: string;\n services: Service[];\n}\n\n/**\n * ServiceSelectionStep Component\n *\n * Step 1: Service and optionally resource selection\n * Uses multi-step context to update booking data\n */\nexport function ServiceSelectionStep({\n siteId,\n services,\n}: ServiceSelectionStepProps): React.ReactElement {\n const { updateData } = useMultiStepData();\n\n return (\n <ServiceResourceSelector\n siteId={siteId}\n services={services}\n onSelect={({ serviceId, resourceId }) => {\n updateData({ serviceId, resourceId });\n }}\n />\n );\n}\n","'use client';\n\nimport React, { useEffect, useMemo } from 'react';\nimport { useMultiStepData } from '../multi-step/MultiStepContext';\nimport { DatePicker } from './DatePicker';\nimport { TimeSlotSelector } from './TimeSlotSelector';\nimport { useAvailableSlots } from '../../hooks/useAvailableSlots';\nimport { useAvailableDates } from '../../hooks/useAvailableDates';\nimport type { BookingFormData } from '../../hooks/useBookingSteps';\nimport type { Service } from '../../hooks/useBookingFormConfig';\n\ninterface DateTimeSelectionStepProps {\n siteId: string;\n preSelectedServiceId?: string;\n preSelectedResourceId?: string;\n /** When there's only one service, pass it here to display info and auto-select */\n singleService?: Service;\n}\n\n/**\n * DateTimeSelectionStep Component\n *\n * Step 2: Date and time slot selection\n * Integrates with multi-step context and fetches available slots.\n * Prefetches available dates to filter the date picker.\n */\nexport function DateTimeSelectionStep({\n siteId,\n preSelectedServiceId,\n preSelectedResourceId,\n singleService,\n}: DateTimeSelectionStepProps): React.ReactElement {\n const { data, updateData } = useMultiStepData<BookingFormData>();\n\n // Get serviceId/resourceId from context if available, otherwise use preselected\n const serviceId = data.serviceId || preSelectedServiceId;\n const resourceId = data.resourceId || preSelectedResourceId;\n const selectedDate = data.selectedDate || '';\n const selectedSlot = data.selectedSlot || '';\n\n // Auto-populate serviceId in form data if we have a preselected service\n // This ensures the submission has the serviceId even when service selection step is skipped\n useEffect(() => {\n if (preSelectedServiceId && !data.serviceId) {\n updateData({ serviceId: preSelectedServiceId });\n }\n }, [preSelectedServiceId, data.serviceId, updateData]);\n\n // Prefetch available dates for filtering the date picker\n const {\n availableDates,\n isLoading: isLoadingDates,\n error: datesError,\n hasMore,\n loadMore,\n } = useAvailableDates({\n siteId,\n serviceId,\n resourceId,\n timezone: 'UTC',\n initialDays: 30,\n });\n\n // Fetch slots for the selected date\n const { slots, isLoading: isLoadingSlots, error: slotsError } = useAvailableSlots({\n siteId,\n serviceId,\n resourceId,\n selectedDate,\n timezone: 'UTC',\n });\n\n // Convert available dates Set to sorted array for DatePicker\n const filteredDateOptions = useMemo(() => {\n if (isLoadingDates || availableDates.size === 0) {\n return []; // Will show loading or empty state\n }\n return [...availableDates].sort();\n }, [availableDates, isLoadingDates]);\n\n const handleDateChange = (date: string) => {\n updateData({ selectedDate: date, selectedSlot: '' }); // Reset slot when date changes\n };\n\n const handleSlotChange = (slot: string) => {\n updateData({ selectedSlot: slot });\n };\n\n // Combine errors for display\n const error = datesError || slotsError;\n\n return (\n <div className=\"space-y-6\">\n {/* Show service info when there's only one service */}\n {singleService && (\n <div className=\"rounded-lg border border-border bg-muted/30 p-4\">\n <h3 className=\"font-medium text-foreground\">{singleService.title}</h3>\n {singleService.description && (\n <p className=\"mt-1 text-sm text-muted-foreground\">{singleService.description}</p>\n )}\n {singleService.durationMinutes && (\n <p className=\"mt-1 text-sm text-muted-foreground\">\n Duration: {singleService.durationMinutes} minutes\n </p>\n )}\n </div>\n )}\n\n {error && (\n <div className=\"alert alert-error text-sm\">\n {error}\n </div>\n )}\n\n <DatePicker\n value={selectedDate}\n onChange={handleDateChange}\n dateOptions={filteredDateOptions}\n isLoading={isLoadingDates}\n isEmpty={!isLoadingDates && filteredDateOptions.length === 0}\n hasMore={hasMore}\n onLoadMore={loadMore}\n />\n\n {selectedDate && (\n <TimeSlotSelector\n value={selectedSlot}\n onChange={handleSlotChange}\n slots={slots}\n isLoading={isLoadingSlots}\n />\n )}\n </div>\n );\n}\n","/**\n * Date and time formatting utilities for blocks\n */\n\n/**\n * Maximum number of days to show in booking date picker.\n * Supports 90+ day visibility with progressive loading.\n */\nexport const BOOKING_DATE_RANGE_DAYS = 90;\n\n/**\n * Number of days to fetch per chunk when loading available dates.\n * Used by useAvailableDates hook for pagination.\n */\nexport const BOOKING_FETCH_CHUNK_DAYS = 30;\n\n/**\n * Generates an array of ISO date strings (YYYY-MM-DD) starting from today\n * @param days - Number of days to generate\n * @returns Array of date strings\n */\nexport function generateDateRange(days: number): string[] {\n const dates: string[] = [];\n const today = new Date();\n\n for (let i = 0; i < days; i++) {\n const date = new Date(today);\n date.setDate(date.getDate() + i);\n dates.push(date.toISOString().split('T')[0]);\n }\n\n return dates;\n}\n\n/**\n * Formats an ISO date string (YYYY-MM-DD) to a human-readable format\n * @param dateStr - ISO date string (e.g., \"2025-03-15\")\n * @returns Formatted date (e.g., \"Friday, March 15, 2025\")\n */\nexport function formatDate(dateStr: string): string {\n const date = new Date(dateStr + 'T00:00:00');\n return date.toLocaleDateString(undefined, {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n}\n\n/**\n * Formats an ISO datetime string to a human-readable time\n * @param isoString - ISO datetime string (e.g., \"2025-03-15T14:30:00Z\")\n * @returns Formatted time (e.g., \"2:30 PM EST\")\n */\nexport function formatTime(isoString: string): string {\n const date = new Date(isoString);\n return date.toLocaleTimeString(undefined, {\n hour: 'numeric',\n minute: '2-digit',\n timeZoneName: 'short',\n });\n}\n","/**\n * DatePicker Component\n *\n * Displays a dropdown for selecting an appointment date from available dates.\n * Supports loading states, empty states, and progressive loading.\n */\n\nimport React from 'react';\nimport { formatDate } from '../../../../utils/date-formatting';\n\ntype DatePickerProps = {\n value: string;\n onChange: (date: string) => void;\n dateOptions: string[];\n required?: boolean;\n isLoading?: boolean;\n isEmpty?: boolean;\n hasMore?: boolean;\n onLoadMore?: () => void;\n};\n\nexport const DatePicker: React.FC<DatePickerProps> = ({\n value,\n onChange,\n dateOptions,\n required = true,\n isLoading = false,\n isEmpty = false,\n hasMore = false,\n onLoadMore,\n}) => {\n // Loading state - show skeleton\n if (isLoading) {\n return (\n <div className=\"space-y-2\">\n <label className=\"form-label\">\n Select Date{required && <span className=\"required-marker\">*</span>}\n </label>\n <div className=\"h-10 w-full animate-pulse rounded-control card-surface\" />\n <p className=\"text-xs status-muted\">Loading available dates...</p>\n </div>\n );\n }\n\n // Empty state - no dates available\n if (isEmpty) {\n return (\n <div className=\"space-y-2\">\n <label className=\"form-label\">\n Select Date{required && <span className=\"required-marker\">*</span>}\n </label>\n <div className=\"alert alert-warning\">\n <p className=\"text-sm\">\n No available dates in this period.\n {hasMore && onLoadMore && (\n <button\n type=\"button\"\n onClick={onLoadMore}\n className=\"ml-2 underline hover:no-underline\"\n >\n Check later dates\n </button>\n )}\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2\">\n <label htmlFor=\"booking-date\" className=\"form-label\">\n Select Date{required && <span className=\"required-marker\">*</span>}\n </label>\n <select\n id=\"booking-date\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n required={required}\n className=\"form-select\"\n >\n <option value=\"\">Choose a date...</option>\n {dateOptions.map((date: string) => (\n <option key={date} value={date}>\n {formatDate(date)}\n </option>\n ))}\n </select>\n {hasMore && onLoadMore && (\n <button\n type=\"button\"\n onClick={onLoadMore}\n className=\"button-link text-sm\"\n >\n Load more dates →\n </button>\n )}\n </div>\n );\n};\n","/**\n * TimeSlotSelector Component\n *\n * Displays available time slots for the selected date with loading and empty states.\n */\n\nimport React from 'react';\nimport { formatTime } from '../../../../utils/date-formatting';\nimport type { TimeSlot } from '../../hooks/useAvailableSlots';\n\ntype TimeSlotSelectorProps = {\n value: string;\n onChange: (slotStartTime: string) => void;\n slots: TimeSlot[];\n isLoading: boolean;\n required?: boolean;\n};\n\nexport const TimeSlotSelector: React.FC<TimeSlotSelectorProps> = ({\n value,\n onChange,\n slots,\n isLoading,\n required = true,\n}) => {\n return (\n <div className=\"space-y-2\">\n <label htmlFor=\"booking-slot\" className=\"form-label\">\n Select Time{required && <span className=\"required-marker\">*</span>}\n </label>\n {isLoading ? (\n <div className=\"alert alert-info text-sm text-center\">\n Loading available times...\n </div>\n ) : slots.length === 0 ? (\n <div className=\"alert text-sm text-center status-muted\">\n No available times for this date\n </div>\n ) : (\n <select\n id=\"booking-slot\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n required={required}\n className=\"form-select\"\n >\n <option value=\"\">Choose a time...</option>\n {slots.map((slot) => (\n <option key={slot.startAt} value={slot.startAt}>\n {formatTime(slot.startAt)}\n </option>\n ))}\n </select>\n )}\n </div>\n );\n};\n","/**\n * Custom hook for fetching available appointment slots\n */\n\nimport { useState, useEffect } from 'react';\nimport { getCmsApiUrl } from '../utils/api-url';\n\nexport type TimeSlot = {\n startAt: string;\n endAt: string;\n resourceId: string;\n};\n\ntype UseAvailableSlotsOptions = {\n siteId: string;\n serviceId: string | undefined;\n resourceId: string | undefined;\n selectedDate: string;\n timezone: string;\n};\n\ntype UseAvailableSlotsResult = {\n slots: TimeSlot[];\n isLoading: boolean;\n error: string | null;\n};\n\n/**\n * Fetches available appointment slots for a given date\n *\n * Automatically refetches when dependencies change.\n * Returns empty slots array until a date is selected.\n */\nexport function useAvailableSlots({\n siteId,\n serviceId,\n resourceId,\n selectedDate,\n timezone,\n}: UseAvailableSlotsOptions): UseAvailableSlotsResult {\n const [slots, setSlots] = useState<TimeSlot[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n // Don't fetch if required params are missing\n if (!selectedDate || !serviceId) {\n setSlots([]);\n return;\n }\n\n const fetchSlots = async () => {\n setIsLoading(true);\n setError(null);\n setSlots([]);\n\n try {\n const params = new URLSearchParams({\n siteId,\n serviceId,\n startDate: selectedDate,\n endDate: selectedDate,\n timezone,\n });\n\n if (resourceId) {\n params.append('resourceId', resourceId);\n }\n\n const apiUrl = getCmsApiUrl();\n // Use public endpoint - no authentication required\n const response = await fetch(`${apiUrl}/public/bookings/availability/slots?${params}`, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || 'Failed to load available times');\n }\n\n const data = await response.json();\n setSlots(data.slots);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load available times');\n } finally {\n setIsLoading(false);\n }\n };\n\n fetchSlots();\n }, [selectedDate, serviceId, resourceId, timezone, siteId]);\n\n return { slots, isLoading, error };\n}\n","/**\n * Custom hook for fetching dates with available appointment slots\n *\n * Prefetches available dates for a date range with support for progressive loading.\n * Returns a Set for O(1) lookup when filtering DatePicker options.\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { getCmsApiUrl } from '../utils/api-url';\nimport { BOOKING_FETCH_CHUNK_DAYS } from '../../../utils/date-formatting';\n\nexport type UseAvailableDatesOptions = {\n siteId: string;\n serviceId: string | undefined;\n resourceId?: string;\n timezone?: string;\n initialDays?: number; // Default: 30\n};\n\nexport type UseAvailableDatesResult = {\n availableDates: Set<string>; // O(1) lookup by date (YYYY-MM-DD)\n isLoading: boolean;\n error: string | null;\n hasMore: boolean;\n loadMore: () => void;\n loadedRange: { start: string; end: string } | null;\n};\n\n/**\n * Fetches dates with availability for a service\n *\n * On mount, fetches the first `initialDays` days.\n * Call `loadMore()` to fetch the next chunk of dates.\n * Uses requestId pattern to handle race conditions.\n */\nexport function useAvailableDates({\n siteId,\n serviceId,\n resourceId,\n timezone = 'UTC',\n initialDays = 30,\n}: UseAvailableDatesOptions): UseAvailableDatesResult {\n const [availableDates, setAvailableDates] = useState<Set<string>>(new Set());\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [hasMore, setHasMore] = useState(false);\n const [loadedRange, setLoadedRange] = useState<{ start: string; end: string } | null>(null);\n\n const nextStartDateRef = useRef<string | null>(null);\n const requestIdRef = useRef(0);\n\n const fetchDates = useCallback(\n async (startDate: string, endDate: string, append = false) => {\n if (!serviceId) {\n console.log('[useAvailableDates] No serviceId, skipping fetch');\n return;\n }\n\n const requestId = ++requestIdRef.current;\n setIsLoading(true);\n setError(null);\n\n try {\n const apiUrl = getCmsApiUrl();\n const params = new URLSearchParams({\n siteId,\n serviceId,\n startDate,\n endDate,\n timezone,\n });\n if (resourceId) {\n params.append('resourceId', resourceId);\n }\n\n const url = `${apiUrl}/public/bookings/availability/dates?${params}`;\n console.log('[useAvailableDates] Fetching:', url);\n\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n console.log('[useAvailableDates] Response status:', res.status);\n\n // Check for stale request\n if (requestId !== requestIdRef.current) return;\n\n if (!res.ok) {\n const errorData = await res.json().catch(() => ({}));\n console.log('[useAvailableDates] Error response:', errorData);\n throw new Error(errorData.error || 'Failed to fetch available dates');\n }\n\n const data = await res.json();\n console.log('[useAvailableDates] Received dates:', data);\n\n setAvailableDates((prev) => {\n const newSet = append ? new Set(prev) : new Set<string>();\n (data.dates as string[]).forEach((d) => newSet.add(d));\n console.log('[useAvailableDates] Updated availableDates Set size:', newSet.size);\n return newSet;\n });\n\n setHasMore(data.hasMore);\n nextStartDateRef.current = data.nextStartDate || null;\n setLoadedRange((prev) => ({\n start: append && prev ? prev.start : data.startDate,\n end: data.endDate,\n }));\n } catch (err) {\n // Check for stale request\n if (requestId !== requestIdRef.current) return;\n setError(err instanceof Error ? err.message : 'Failed to load available dates');\n } finally {\n // Check for stale request\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n },\n [siteId, serviceId, resourceId, timezone]\n );\n\n // Initial fetch when serviceId becomes available\n useEffect(() => {\n if (!serviceId) {\n // Reset state when serviceId is cleared\n setAvailableDates(new Set());\n setLoadedRange(null);\n setHasMore(false);\n return;\n }\n\n const today = new Date().toISOString().split('T')[0];\n const endDate = new Date(Date.now() + initialDays * 24 * 60 * 60 * 1000)\n .toISOString()\n .split('T')[0];\n\n fetchDates(today, endDate, false);\n }, [serviceId, fetchDates, initialDays]);\n\n const loadMore = useCallback(() => {\n if (!nextStartDateRef.current || isLoading) return;\n\n const start = nextStartDateRef.current;\n const msPerDay = 24 * 60 * 60 * 1000;\n const end = new Date(new Date(start).getTime() + BOOKING_FETCH_CHUNK_DAYS * msPerDay)\n .toISOString()\n .split('T')[0];\n\n fetchDates(start, end, true);\n }, [fetchDates, isLoading]);\n\n return {\n availableDates,\n isLoading,\n error,\n hasMore,\n loadMore,\n loadedRange,\n };\n}\n","'use client';\n\nimport React, { useState, useCallback } from 'react';\nimport { useMultiStepData } from './MultiStepContext';\n\n/**\n * Form field option\n */\nexport interface FormFieldOption {\n value: string;\n label: string;\n}\n\n/**\n * Form field definition (matches packages/db/src/schemas/forms.ts)\n */\nexport interface FormField {\n id: string;\n label: string;\n type:\n | 'text'\n | 'email'\n | 'textarea'\n | 'select'\n | 'radio'\n | 'checkbox'\n | 'consent'\n | 'tel'\n | 'url'\n | 'number'\n | 'date'\n | 'time';\n required?: boolean;\n placeholder?: string;\n helpText?: string;\n options?: FormFieldOption[];\n multiple?: boolean;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n min?: number;\n max?: number;\n}\n\n/**\n * DynamicFormFields Component Props\n */\nexport interface DynamicFormFieldsProps {\n fields: FormField[];\n showLabels?: boolean;\n className?: string;\n}\n\n/**\n * DynamicFormFields Component\n *\n * Renders form fields dynamically based on FormField definitions.\n * Integrates with multi-step context for data management.\n *\n * Features:\n * - Supports all field types from form schema\n * - Client-side validation\n * - Accessible form controls\n * - Integrates with multi-step context\n *\n * Usage:\n * ```tsx\n * <DynamicFormFields\n * fields={formSchema.fields}\n * showLabels={true}\n * />\n * ```\n */\nexport function DynamicFormFields({\n fields,\n showLabels = true,\n className = '',\n}: DynamicFormFieldsProps): React.ReactElement {\n const { data, updateData } = useMultiStepData<Record<string, any>>();\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n const handleChange = useCallback(\n (fieldId: string, value: any) => {\n updateData({ [fieldId]: value });\n },\n [updateData]\n );\n\n const handleBlur = useCallback((fieldId: string) => {\n setTouched((prev) => ({ ...prev, [fieldId]: true }));\n }, []);\n\n const getFieldError = useCallback(\n (field: FormField): string | null => {\n const value = data[field.id];\n const isTouched = touched[field.id];\n\n if (!isTouched) return null;\n\n // Required validation\n if (field.required && !value) {\n return `${field.label} is required`;\n }\n\n // Type-specific validation\n if (value) {\n switch (field.type) {\n case 'email':\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)) {\n return 'Please enter a valid email address';\n }\n break;\n case 'url':\n try {\n new URL(value);\n } catch {\n return 'Please enter a valid URL';\n }\n break;\n case 'tel':\n if (!/^[+\\d\\s\\-()]+$/.test(value)) {\n return 'Please enter a valid phone number';\n }\n break;\n case 'number':\n const num = Number(value);\n if (isNaN(num)) {\n return 'Please enter a valid number';\n }\n if (field.min !== undefined && num < field.min) {\n return `Value must be at least ${field.min}`;\n }\n if (field.max !== undefined && num > field.max) {\n return `Value must be at most ${field.max}`;\n }\n break;\n }\n\n // Length validation\n if (typeof value === 'string') {\n if (field.minLength && value.length < field.minLength) {\n return `Must be at least ${field.minLength} characters`;\n }\n if (field.maxLength && value.length > field.maxLength) {\n return `Must be at most ${field.maxLength} characters`;\n }\n }\n\n // Pattern validation\n if (field.pattern && typeof value === 'string') {\n const regex = new RegExp(field.pattern);\n if (!regex.test(value)) {\n return 'Please match the required format';\n }\n }\n }\n\n return null;\n },\n [data, touched]\n );\n\n return (\n <div className={`space-y-6 ${className}`}>\n {fields.map((field) => {\n const error = getFieldError(field);\n const value = data[field.id] ?? '';\n\n return (\n <div key={field.id} className=\"space-y-2\">\n {showLabels && (\n <label htmlFor={field.id} className=\"form-label\">\n {field.label}\n {field.required && <span className=\"required-marker\">*</span>}\n </label>\n )}\n\n {field.helpText && (\n <p className=\"text-sm status-muted\">{field.helpText}</p>\n )}\n\n <FieldInput\n field={field}\n value={value}\n onChange={(val) => handleChange(field.id, val)}\n onBlur={() => handleBlur(field.id)}\n error={error}\n />\n\n {error && <p className=\"text-sm status-error\">{error}</p>}\n </div>\n );\n })}\n </div>\n );\n}\n\n/**\n * FieldInput Component\n *\n * Renders the appropriate input component based on field type\n */\nfunction FieldInput({\n field,\n value,\n onChange,\n onBlur,\n error,\n}: {\n field: FormField;\n value: any;\n onChange: (value: any) => void;\n onBlur: () => void;\n error: string | null;\n}) {\n // Use generated form classes from theme\n // Error state is handled via aria-invalid attribute in the generated CSS\n const inputClass = 'form-input';\n const textareaClass = 'form-textarea';\n const selectClass = 'form-select';\n const checkboxClass = 'form-checkbox';\n const radioClass = 'form-radio';\n\n switch (field.type) {\n case 'textarea':\n return (\n <textarea\n id={field.id}\n name={field.id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onBlur={onBlur}\n placeholder={field.placeholder}\n required={field.required}\n minLength={field.minLength}\n maxLength={field.maxLength}\n rows={4}\n aria-invalid={error ? 'true' : undefined}\n className={textareaClass}\n />\n );\n\n case 'select':\n if (field.multiple) {\n return (\n <select\n id={field.id}\n name={field.id}\n value={Array.isArray(value) ? value : []}\n onChange={(e) => {\n const selected = Array.from(e.target.selectedOptions, (opt) => opt.value);\n onChange(selected);\n }}\n onBlur={onBlur}\n required={field.required}\n multiple\n aria-invalid={error ? 'true' : undefined}\n className={`${selectClass} h-32`}\n >\n {field.options?.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n );\n }\n\n return (\n <select\n id={field.id}\n name={field.id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onBlur={onBlur}\n required={field.required}\n aria-invalid={error ? 'true' : undefined}\n className={selectClass}\n >\n <option value=\"\">Select an option...</option>\n {field.options?.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n );\n\n case 'radio':\n return (\n <div className=\"space-y-2\">\n {field.options?.map((opt) => (\n <label key={opt.value} className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"radio\"\n name={field.id}\n value={opt.value}\n checked={value === opt.value}\n onChange={(e) => onChange(e.target.value)}\n onBlur={onBlur}\n required={field.required}\n className={radioClass}\n />\n <span className=\"text-sm\">{opt.label}</span>\n </label>\n ))}\n </div>\n );\n\n case 'checkbox':\n if (field.options && field.options.length > 1) {\n // Multiple checkboxes\n const checkedValues = Array.isArray(value) ? value : [];\n return (\n <div className=\"space-y-2\">\n {field.options.map((opt) => (\n <label key={opt.value} className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n name={field.id}\n value={opt.value}\n checked={checkedValues.includes(opt.value)}\n onChange={(e) => {\n const newValues = e.target.checked\n ? [...checkedValues, opt.value]\n : checkedValues.filter((v) => v !== opt.value);\n onChange(newValues);\n }}\n onBlur={onBlur}\n className={checkboxClass}\n />\n <span className=\"text-sm\">{opt.label}</span>\n </label>\n ))}\n </div>\n );\n }\n\n // Single checkbox\n return (\n <label className=\"flex items-center gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n id={field.id}\n name={field.id}\n checked={!!value}\n onChange={(e) => onChange(e.target.checked)}\n onBlur={onBlur}\n required={field.required}\n className={checkboxClass}\n />\n <span className=\"text-sm\">{field.placeholder || field.label}</span>\n </label>\n );\n\n case 'consent':\n return (\n <label className=\"flex items-start gap-2 cursor-pointer\">\n <input\n type=\"checkbox\"\n id={field.id}\n name={field.id}\n checked={!!value}\n onChange={(e) => onChange(e.target.checked)}\n onBlur={onBlur}\n required={field.required}\n className={`${checkboxClass} mt-0.5`}\n />\n <span className=\"text-sm\">{field.placeholder || field.label}</span>\n </label>\n );\n\n case 'number':\n return (\n <input\n type=\"number\"\n id={field.id}\n name={field.id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onBlur={onBlur}\n placeholder={field.placeholder}\n required={field.required}\n min={field.min}\n max={field.max}\n aria-invalid={error ? 'true' : undefined}\n className={inputClass}\n />\n );\n\n case 'date':\n return (\n <input\n type=\"date\"\n id={field.id}\n name={field.id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onBlur={onBlur}\n required={field.required}\n min={field.min ? String(field.min) : undefined}\n max={field.max ? String(field.max) : undefined}\n aria-invalid={error ? 'true' : undefined}\n className={inputClass}\n />\n );\n\n case 'time':\n return (\n <input\n type=\"time\"\n id={field.id}\n name={field.id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onBlur={onBlur}\n required={field.required}\n aria-invalid={error ? 'true' : undefined}\n className={inputClass}\n />\n );\n\n // text, email, tel, url\n default:\n return (\n <input\n type={field.type}\n id={field.id}\n name={field.id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n onBlur={onBlur}\n placeholder={field.placeholder}\n required={field.required}\n minLength={field.minLength}\n maxLength={field.maxLength}\n pattern={field.pattern}\n aria-invalid={error ? 'true' : undefined}\n className={inputClass}\n />\n );\n }\n}\n","/**\n * Custom hook for submitting appointment bookings\n */\n\nimport { useState } from 'react';\nimport { getCmsApiUrl } from '../utils/api-url';\n\nexport type BookingSubmissionData = {\n formId: string; // NEW - references the booking form\n serviceId: string;\n resourceId?: string; // Optional - may be undefined if \"any available\"\n startAt: string;\n endAt: string;\n customFields: Record<string, any>; // NEW - dynamic fields from form schema\n timezone: string;\n};\n\ntype UseBookingSubmissionResult = {\n submit: (data: BookingSubmissionData) => Promise<void>;\n isSubmitting: boolean;\n error: string | null;\n isSuccess: boolean;\n};\n\n/**\n * Hook for submitting appointment bookings\n *\n * Handles API call, loading state, and error handling.\n * Returns isSuccess=true after successful submission.\n */\nexport function useBookingSubmission(siteId: string): UseBookingSubmissionResult {\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [isSuccess, setIsSuccess] = useState(false);\n\n const submit = async (data: BookingSubmissionData) => {\n setIsSubmitting(true);\n setError(null);\n\n try {\n const apiUrl = getCmsApiUrl();\n // Use public endpoint - no authentication required\n const response = await fetch(`${apiUrl}/public/bookings/appointments`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n formId: data.formId,\n serviceId: data.serviceId,\n resourceId: data.resourceId || null,\n startAt: data.startAt,\n endAt: data.endAt,\n customFields: data.customFields,\n timezone: data.timezone,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || 'Failed to book appointment');\n }\n\n setIsSuccess(true);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to book appointment');\n throw err; // Re-throw so caller can handle if needed\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return { submit, isSubmitting, error, isSuccess };\n}\n","/**\n * Hook to load booking form configuration and services\n */\n\nimport { useState, useEffect } from 'react';\nimport { getCmsApiUrl } from '../utils/api-url';\n\nexport interface Service {\n id: string;\n title: string;\n description?: string;\n durationMinutes?: number;\n}\n\nexport interface BookingFormConfig {\n id: string;\n name: string;\n slug: string;\n settings?: {\n type: 'booking';\n serviceId?: string;\n serviceIds?: string[];\n resourceId?: string;\n requiresApproval?: boolean;\n successMessage?: string;\n };\n schema?: {\n version: string;\n fields: any[];\n };\n}\n\ninterface UseBookingFormConfigResult {\n formConfig: BookingFormConfig | null;\n services: Service[];\n isLoading: boolean;\n error: string | null;\n}\n\n// UUID regex pattern\nconst UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Load booking form configuration and associated services\n *\n * Fetches the form definition and determines which services to load based on:\n * - Single service (serviceId)\n * - Multiple services (serviceIds array)\n * - All site services (no serviceId/serviceIds)\n *\n * Supports both UUID and slug for formId. When using a slug, siteId is required.\n */\nexport function useBookingFormConfig(\n siteId: string,\n formId: string\n): UseBookingFormConfigResult {\n const [formConfig, setFormConfig] = useState<BookingFormConfig | null>(null);\n const [services, setServices] = useState<Service[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let mounted = true;\n\n async function loadFormAndServices() {\n try {\n setIsLoading(true);\n setError(null);\n\n const apiUrl = getCmsApiUrl();\n // Support both UUID and slug lookup\n // For slug lookup, pass siteId as query param (required by API)\n const isUUID = UUID_REGEX.test(formId);\n const formUrl = isUUID\n ? `${apiUrl}/public/forms/${formId}`\n : `${apiUrl}/public/forms/${formId}?siteId=${encodeURIComponent(siteId)}`;\n const response = await fetch(formUrl);\n\n if (!response.ok) {\n throw new Error('Failed to load booking form');\n }\n\n const { form: rawData } = await response.json();\n\n if (!mounted) return;\n\n // Normalize API response to match BookingFormConfig interface\n const normalizedForm: BookingFormConfig = {\n id: rawData.id,\n name: rawData.name,\n slug: rawData.slug,\n settings: rawData.settingsJson ?? rawData.settings,\n schema: rawData.schemaJson ?? rawData.schema,\n };\n\n setFormConfig(normalizedForm);\n\n // Load services based on form configuration\n // Use public endpoints (no authentication required)\n if (!normalizedForm.settings?.serviceId && !normalizedForm.settings?.serviceIds) {\n // Load all services for the site\n const servicesResponse = await fetch(\n `${apiUrl}/public/bookings/services?siteId=${encodeURIComponent(siteId)}`\n );\n if (servicesResponse.ok) {\n const servicesData = await servicesResponse.json();\n if (mounted) {\n setServices(servicesData.services || []);\n }\n }\n } else if (normalizedForm.settings?.serviceIds && normalizedForm.settings.serviceIds.length > 0) {\n // Load specific services\n const servicesResponse = await fetch(\n `${apiUrl}/public/bookings/services?siteId=${encodeURIComponent(siteId)}&ids=${normalizedForm.settings.serviceIds.join(',')}`\n );\n if (servicesResponse.ok) {\n const servicesData = await servicesResponse.json();\n if (mounted) {\n setServices(servicesData.services || []);\n }\n }\n } else if (normalizedForm.settings?.serviceId) {\n // Single service - load it\n const serviceResponse = await fetch(\n `${apiUrl}/public/bookings/services/${normalizedForm.settings.serviceId}?siteId=${encodeURIComponent(siteId)}`\n );\n if (serviceResponse.ok) {\n const serviceData = await serviceResponse.json();\n if (mounted) {\n setServices([serviceData.service || serviceData]);\n }\n }\n }\n } catch (err) {\n console.error('Failed to load form:', err);\n if (mounted) {\n setError('Failed to load booking form. Please try again later.');\n }\n } finally {\n if (mounted) {\n setIsLoading(false);\n }\n }\n }\n\n loadFormAndServices();\n\n return () => {\n mounted = false;\n };\n }, [siteId, formId]);\n\n return { formConfig, services, isLoading, error };\n}\n"],"mappings":"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","names":["React","useState","jsx","React","useMemo","useState","useEffect","useCallback","jsx","jsxs","useState","useCallback","useEffect","jsx","useEffect","useMemo","jsx","jsxs","jsx","jsxs","useState","useEffect","useState","useEffect","useState","useEffect","useCallback","useState","useCallback","useEffect","jsx","jsxs","useEffect","useMemo","useState","useCallback","jsx","jsxs","useState","useCallback","useMemo","React","useState","useState","jsx","useState","React","useState","useEffect","useState","useEffect"]}
|
package/dist/client/client.d.mts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { R as RiverbankClient,
|
|
2
|
-
export { d as Page, U as UsePageParams,
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import '@riverbankcms/
|
|
1
|
+
import { R as RiverbankClient, P as PageProps, T as Theme, a as ResolvedBlockData, b as RiverbankClientConfig } from './usePage-BydHcMYB.mjs';
|
|
2
|
+
export { d as Page, U as UsePageParams, c as UsePageResult, u as usePage } from './usePage-BydHcMYB.mjs';
|
|
3
|
+
import '@riverbankcms/ai';
|
|
4
|
+
import 'zod';
|
|
5
|
+
import '@riverbankcms/media-storage-supabase';
|
|
6
|
+
import '@riverbankcms/db';
|
|
6
7
|
import 'react/jsx-runtime';
|
|
8
|
+
import 'react';
|
|
9
|
+
import './resolver-BhueZVxZ.mjs';
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* Server-side helper to fetch content (page or entry) by path.
|
package/dist/client/client.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { R as RiverbankClient,
|
|
2
|
-
export { d as Page, U as UsePageParams,
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import '@riverbankcms/
|
|
1
|
+
import { R as RiverbankClient, P as PageProps, T as Theme, a as ResolvedBlockData, b as RiverbankClientConfig } from './usePage-BBcFCxOU.js';
|
|
2
|
+
export { d as Page, U as UsePageParams, c as UsePageResult, u as usePage } from './usePage-BBcFCxOU.js';
|
|
3
|
+
import '@riverbankcms/ai';
|
|
4
|
+
import 'zod';
|
|
5
|
+
import '@riverbankcms/media-storage-supabase';
|
|
6
|
+
import '@riverbankcms/db';
|
|
6
7
|
import 'react/jsx-runtime';
|
|
8
|
+
import 'react';
|
|
9
|
+
import './resolver-BhueZVxZ.js';
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* Server-side helper to fetch content (page or entry) by path.
|