@riverbankcms/sdk 0.4.3 → 0.5.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/README.md +84 -0
- package/dist/cli/index.js +3463 -120
- package/dist/cli/index.js.map +1 -1
- package/dist/client/analytics.js +1 -1
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/analytics.mjs +1 -1
- package/dist/client/analytics.mjs.map +1 -1
- package/dist/client/bookings.js +6 -6
- package/dist/client/bookings.js.map +1 -1
- package/dist/client/bookings.mjs +6 -6
- package/dist/client/bookings.mjs.map +1 -1
- package/dist/client/client.d.mts +2 -2
- package/dist/client/client.d.ts +2 -2
- package/dist/client/client.js +1379 -519
- package/dist/client/client.js.map +1 -1
- package/dist/client/client.mjs +1379 -519
- package/dist/client/client.mjs.map +1 -1
- package/dist/client/hooks.d.mts +2 -2
- package/dist/client/hooks.d.ts +2 -2
- package/dist/client/hooks.js +26 -11
- package/dist/client/hooks.js.map +1 -1
- package/dist/client/hooks.mjs +26 -11
- package/dist/client/hooks.mjs.map +1 -1
- package/dist/client/rendering/client.js +20 -14
- package/dist/client/rendering/client.js.map +1 -1
- package/dist/client/rendering/client.mjs +20 -14
- package/dist/client/rendering/client.mjs.map +1 -1
- package/dist/client/usePage-BTPnCuWC.d.mts +6511 -0
- package/dist/client/usePage-BXjk8BhD.d.mts +6704 -0
- package/dist/client/usePage-BafOS9UT.d.mts +6512 -0
- package/dist/client/usePage-BiOReg0_.d.ts +6704 -0
- package/dist/client/usePage-Bnx-kA6x.d.mts +6670 -0
- package/dist/client/usePage-DoPI6b8V.d.ts +6511 -0
- package/dist/client/usePage-QNWArrVO.d.ts +6670 -0
- package/dist/client/usePage-fBgPB6Oq.d.ts +6512 -0
- package/dist/server/{Layout-CXI_VkhN.d.ts → Layout-BClXUTsd.d.mts} +4 -4
- package/dist/server/{Layout-p6f3TLw9.d.mts → Layout-UXGjXv8M.d.ts} +4 -4
- package/dist/server/{chunk-6JBKKV3G.js → chunk-2KCF2DNK.js} +30 -10
- package/dist/server/chunk-2KCF2DNK.js.map +1 -0
- package/dist/server/chunk-5STV4MWD.js +189 -0
- package/dist/server/chunk-5STV4MWD.js.map +1 -0
- package/dist/server/{chunk-VHDDXCK6.js → chunk-7UPVCT3K.js} +1206 -496
- package/dist/server/chunk-7UPVCT3K.js.map +1 -0
- package/dist/server/{chunk-7DS4Q3GA.mjs → chunk-AEFWG657.mjs} +3 -3
- package/dist/server/chunk-AEFWG657.mjs.map +1 -0
- package/dist/server/{chunk-USQF2XTU.mjs → chunk-BYBJA6SP.mjs} +26 -11
- package/dist/server/chunk-BYBJA6SP.mjs.map +1 -0
- package/dist/server/{chunk-ES6QDZUX.mjs → chunk-C6FIJC7T.mjs} +2 -2
- package/dist/server/{chunk-N3PX76AP.mjs → chunk-CMABGYGI.mjs} +269 -135
- package/dist/server/chunk-CMABGYGI.mjs.map +1 -0
- package/dist/server/{chunk-TO7FD6TQ.js → chunk-I2D7KOEA.js} +4 -4
- package/dist/server/{chunk-TO7FD6TQ.js.map → chunk-I2D7KOEA.js.map} +1 -1
- package/dist/server/{chunk-R5B6IOFQ.js → chunk-KA74YRK6.js} +269 -135
- package/dist/server/chunk-KA74YRK6.js.map +1 -0
- package/dist/server/chunk-KFLZGNPO.mjs +189 -0
- package/dist/server/chunk-KFLZGNPO.mjs.map +1 -0
- package/dist/server/chunk-L5EA4FXU.mjs +134 -0
- package/dist/server/chunk-L5EA4FXU.mjs.map +1 -0
- package/dist/server/{chunk-U2NI3TS3.mjs → chunk-LNOUXALA.mjs} +1135 -425
- package/dist/server/chunk-LNOUXALA.mjs.map +1 -0
- package/dist/server/{chunk-24F6FTCI.mjs → chunk-OSF34JTQ.mjs} +4 -4
- package/dist/server/{chunk-G35R7N7B.js → chunk-P3NNN73G.js} +3 -3
- package/dist/server/{chunk-G35R7N7B.js.map → chunk-P3NNN73G.js.map} +1 -1
- package/dist/server/{chunk-I6K5REFT.mjs → chunk-P4K63SBZ.mjs} +24 -4
- package/dist/server/chunk-P4K63SBZ.mjs.map +1 -0
- package/dist/server/{chunk-HOY77YBF.js → chunk-RVDS7VSP.js} +5 -5
- package/dist/server/chunk-RVDS7VSP.js.map +1 -0
- package/dist/server/{chunk-2SSEBAHC.js → chunk-TT5JWA4X.js} +9 -9
- package/dist/server/{chunk-2SSEBAHC.js.map → chunk-TT5JWA4X.js.map} +1 -1
- package/dist/server/chunk-VSFQRHYZ.js +134 -0
- package/dist/server/chunk-VSFQRHYZ.js.map +1 -0
- package/dist/server/{chunk-EGTDJ4PL.js → chunk-YYO3RIFO.js} +26 -11
- package/dist/server/chunk-YYO3RIFO.js.map +1 -0
- package/dist/server/{chunk-OP2GHK27.mjs → chunk-Z5ZA6Q4D.mjs} +2 -2
- package/dist/server/{components-Dhiemsjd.d.ts → components-BmaJxgCV.d.mts} +20 -75
- package/dist/server/{components-C75e4poV.d.mts → components-DppHY5oD.d.ts} +20 -75
- package/dist/server/components.d.mts +11 -8
- package/dist/server/components.d.ts +11 -8
- package/dist/server/components.js +5 -4
- package/dist/server/components.js.map +1 -1
- package/dist/server/components.mjs +4 -3
- package/dist/server/config-validation.d.mts +3 -3
- package/dist/server/config-validation.d.ts +3 -3
- package/dist/server/config-validation.js +9 -5
- package/dist/server/config-validation.js.map +1 -1
- package/dist/server/config-validation.mjs +8 -4
- package/dist/server/config.d.mts +243 -5
- package/dist/server/config.d.ts +243 -5
- package/dist/server/config.js +72 -5
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +72 -5
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/core-DsNWrl3o.d.mts +44 -0
- package/dist/server/core-DsNWrl3o.d.ts +44 -0
- package/dist/server/data.d.mts +4 -3
- package/dist/server/data.d.ts +4 -3
- package/dist/server/data.js +3 -3
- package/dist/server/data.mjs +2 -2
- package/dist/server/{index-CAwBj3-A.d.ts → index-Bucs6UqG.d.mts} +2 -1
- package/dist/server/{index-C6o9LPvq.d.mts → index-Cp7tJuRt.d.ts} +2 -1
- package/dist/server/index.d.mts +84 -6
- package/dist/server/index.d.ts +84 -6
- package/dist/server/index.js +91 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +90 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/link-DjxLyC82.d.mts +23 -0
- package/dist/server/link-DjxLyC82.d.ts +23 -0
- package/dist/server/{loadContent-CdXfuCuE.d.mts → loadContent-BS-3wesN.d.mts} +4 -4
- package/dist/server/{loadContent-CsvQRoxb.d.ts → loadContent-Buvmudee.d.ts} +4 -4
- package/dist/server/{loadPage-p3AWwwrd.d.mts → loadPage-B8mQUUSo.d.mts} +5 -46
- package/dist/server/loadPage-DNQTTRHL.mjs +11 -0
- package/dist/server/{loadPage-BA0HiT-6.d.ts → loadPage-DP3nrHBi.d.ts} +5 -46
- package/dist/server/loadPage-IDGVDFBB.js +11 -0
- package/dist/server/{loadPage-DLC7DJZP.js.map → loadPage-IDGVDFBB.js.map} +1 -1
- package/dist/server/metadata.d.mts +6 -4
- package/dist/server/metadata.d.ts +6 -4
- package/dist/server/navigation.d.mts +199 -29
- package/dist/server/navigation.d.ts +199 -29
- package/dist/server/navigation.js +27 -43
- package/dist/server/navigation.js.map +1 -1
- package/dist/server/navigation.mjs +20 -36
- package/dist/server/navigation.mjs.map +1 -1
- package/dist/server/rendering/server.d.mts +8 -6
- package/dist/server/rendering/server.d.ts +8 -6
- package/dist/server/rendering/server.js +7 -6
- package/dist/server/rendering/server.js.map +1 -1
- package/dist/server/rendering/server.mjs +6 -5
- package/dist/server/rendering.d.mts +14 -10
- package/dist/server/rendering.d.ts +14 -10
- package/dist/server/rendering.js +9 -8
- package/dist/server/rendering.js.map +1 -1
- package/dist/server/rendering.mjs +8 -7
- package/dist/server/richTextSchema-DURiozvD.d.mts +62 -0
- package/dist/server/richTextSchema-DURiozvD.d.ts +62 -0
- package/dist/server/routing.d.mts +178 -11
- package/dist/server/routing.d.ts +178 -11
- package/dist/server/routing.js +95 -2
- package/dist/server/routing.js.map +1 -1
- package/dist/server/routing.mjs +94 -1
- package/dist/server/routing.mjs.map +1 -1
- package/dist/server/{schema-Bpy9N5ZI.d.mts → schema-Z6-afHJG.d.mts} +1 -1
- package/dist/server/{schema-Bpy9N5ZI.d.ts → schema-Z6-afHJG.d.ts} +1 -1
- package/dist/server/server.d.mts +9 -7
- package/dist/server/server.d.ts +9 -7
- package/dist/server/server.js +6 -6
- package/dist/server/server.mjs +5 -5
- package/dist/server/theme-bridge.js +8 -8
- package/dist/server/theme-bridge.mjs +2 -2
- package/dist/server/{types-Dj8B3QRb.d.ts → types-1cLz0vnq.d.mts} +55 -2
- package/dist/server/{types-txWsSxN7.d.mts → types-BjgZt8xJ.d.mts} +63 -2
- package/dist/server/{types-CdhKJrB0.d.mts → types-BvcJU7zk.d.ts} +55 -2
- package/dist/server/{types-BWQ-TohG.d.ts → types-CVykEqXN.d.ts} +289 -83
- package/dist/server/{types-CL916r6x.d.ts → types-DLBhEPSt.d.ts} +63 -2
- package/dist/server/{types-BLf-hE50.d.mts → types-Dsu9wsUh.d.mts} +289 -83
- package/dist/server/{validation-DzvDwwRo.d.mts → validation-BGuRo8P1.d.mts} +18 -5
- package/dist/server/{validation-CoU8uAiu.d.ts → validation-DU2YE7u5.d.ts} +18 -5
- package/package.json +5 -1
- package/dist/server/chunk-6JBKKV3G.js.map +0 -1
- package/dist/server/chunk-7DS4Q3GA.mjs.map +0 -1
- package/dist/server/chunk-EGTDJ4PL.js.map +0 -1
- package/dist/server/chunk-HOY77YBF.js.map +0 -1
- package/dist/server/chunk-I6K5REFT.mjs.map +0 -1
- package/dist/server/chunk-LCYGQDAB.mjs +0 -835
- package/dist/server/chunk-LCYGQDAB.mjs.map +0 -1
- package/dist/server/chunk-N3PX76AP.mjs.map +0 -1
- package/dist/server/chunk-R5B6IOFQ.js.map +0 -1
- package/dist/server/chunk-TNYU5EIO.js +0 -835
- package/dist/server/chunk-TNYU5EIO.js.map +0 -1
- package/dist/server/chunk-U2NI3TS3.mjs.map +0 -1
- package/dist/server/chunk-USQF2XTU.mjs.map +0 -1
- package/dist/server/chunk-VHDDXCK6.js.map +0 -1
- package/dist/server/loadPage-DLC7DJZP.js +0 -11
- package/dist/server/loadPage-GEGN4UAL.mjs +0 -11
- /package/dist/server/{chunk-ES6QDZUX.mjs.map → chunk-C6FIJC7T.mjs.map} +0 -0
- /package/dist/server/{chunk-24F6FTCI.mjs.map → chunk-OSF34JTQ.mjs.map} +0 -0
- /package/dist/server/{chunk-OP2GHK27.mjs.map → chunk-Z5ZA6Q4D.mjs.map} +0 -0
- /package/dist/server/{loadPage-GEGN4UAL.mjs.map → loadPage-DNQTTRHL.mjs.map} +0 -0
package/dist/client/analytics.js
CHANGED
|
@@ -132,7 +132,7 @@ function createMinimalAnalyticsClient(config) {
|
|
|
132
132
|
for (const cookie of cookies) {
|
|
133
133
|
const [name, value] = cookie.trim().split("=");
|
|
134
134
|
if (name === config.sessionCookieName) {
|
|
135
|
-
sessionId = value;
|
|
135
|
+
sessionId = value ?? null;
|
|
136
136
|
break;
|
|
137
137
|
}
|
|
138
138
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/analytics/index.ts","../../src/analytics/AnalyticsBootstrap.tsx"],"sourcesContent":["/**\n * Analytics utilities for tracking user behavior\n *\n * Lightweight analytics helpers for tracking page views, CTA clicks,\n * form submissions, and custom events.\n */\n\nexport { AnalyticsBootstrap, useAnalytics } from './AnalyticsBootstrap';\nexport type {\n AnalyticsConfig,\n AnalyticsClient,\n AnalyticsHelpers,\n TrackEventInput,\n} from './AnalyticsBootstrap';\n","/**\n * Analytics Bootstrap Component\n *\n * Client component that initializes analytics tracking for a Builder site.\n * Auto-tracks page views and provides helpers for tracking custom events.\n */\n\n'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nexport type AnalyticsConfig = {\n /**\n * Site ID for analytics tracking\n */\n siteId: string;\n\n /**\n * Site slug for analytics tracking\n */\n siteSlug: string;\n\n /**\n * Analytics endpoint URL\n * @default '/api/analytics/collect'\n */\n endpoint?: string;\n\n /**\n * Custom session cookie name\n * @default 'builder_analytics_session'\n */\n sessionCookieName?: string;\n\n /**\n * Disable analytics tracking\n * @default false\n */\n disabled?: boolean;\n};\n\nexport type AnalyticsClient = {\n track: (event: TrackEventInput) => Promise<void>;\n trackCtaClick: (metadata?: Record<string, unknown>) => Promise<void>;\n trackFormSubmit: (metadata?: Record<string, unknown>) => Promise<void>;\n destroy: () => void;\n};\n\nexport type TrackEventInput = {\n eventType: string;\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Analytics helpers returned by useAnalytics hook\n */\nexport type AnalyticsHelpers = {\n trackEvent: (event: TrackEventInput) => void;\n trackCtaClick: (metadata?: Record<string, unknown>) => void;\n trackFormSubmit: (metadata?: Record<string, unknown>) => void;\n};\n\n/**\n * Analytics Bootstrap component\n *\n * Place this component in your layout to enable analytics tracking.\n *\n * @example\n * ```tsx\n * import { AnalyticsBootstrap } from '@riverbankcms/sdk/analytics';\n *\n * export default function Layout({ children }) {\n * return (\n * <html>\n * <body>\n * {children}\n * <AnalyticsBootstrap\n * siteId=\"your-site-id\"\n * siteSlug=\"your-site-slug\"\n * />\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport function AnalyticsBootstrap(config: AnalyticsConfig) {\n useAnalytics(config);\n\n // Component renders nothing, analytics runs in background\n return null;\n}\n\n/**\n * Hook for tracking analytics events\n *\n * @param config - Analytics configuration. Pass null to disable analytics.\n * @returns Analytics helpers for tracking events\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { useAnalytics } from '@riverbankcms/sdk/analytics';\n *\n * export function MyComponent() {\n * const analytics = useAnalytics({\n * siteId: 'your-site-id',\n * siteSlug: 'your-site-slug',\n * });\n *\n * const handleClick = () => {\n * analytics.trackCtaClick({ buttonLabel: 'Sign Up' });\n * };\n *\n * return <button onClick={handleClick}>Sign Up</button>;\n * }\n * ```\n */\nexport function useAnalytics(config: AnalyticsConfig | null): AnalyticsHelpers {\n const siteId = config?.siteId ?? null;\n const siteSlug = config?.siteSlug ?? '';\n const endpoint = config?.endpoint ?? '/api/analytics/collect';\n const sessionCookieName = config?.sessionCookieName ?? 'builder_analytics_session';\n const disabled = config?.disabled ?? false;\n\n const activeConfig = useMemo(() => {\n if (!siteId || disabled) {\n return null;\n }\n return { siteId, siteSlug, endpoint, sessionCookieName };\n }, [disabled, endpoint, sessionCookieName, siteId, siteSlug]);\n\n const stateRef = useRef<{\n client: AnalyticsClient | null;\n queue: Array<(client: AnalyticsClient) => void>;\n }>({\n client: null,\n queue: [],\n });\n\n const configRef = useRef<typeof activeConfig>(null);\n configRef.current = activeConfig;\n\n const enqueue = useCallback((action: (client: AnalyticsClient) => void) => {\n if (!configRef.current) return;\n const state = stateRef.current;\n if (state.client) {\n action(state.client);\n return;\n }\n state.queue.push(action);\n }, []);\n\n useEffect(() => {\n const state = stateRef.current;\n\n if (!activeConfig) {\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n return;\n }\n\n const configSnapshot = activeConfig;\n let disposed = false;\n\n async function start() {\n try {\n // Create minimal analytics client\n const client = createMinimalAnalyticsClient({\n siteId: configSnapshot.siteId,\n siteSlug: configSnapshot.siteSlug,\n endpoint: configSnapshot.endpoint,\n sessionCookieName: configSnapshot.sessionCookieName,\n });\n\n if (disposed) return;\n\n state.client = client;\n\n // Flush queued events\n if (state.queue.length > 0) {\n const pending = state.queue.splice(0);\n for (const action of pending) action(client);\n }\n\n // Auto-track initial page view\n await client.track({\n eventType: 'page_view',\n metadata: { path: window.location.pathname },\n });\n } catch (error) {\n console.warn('[analytics] Failed to initialize client', error);\n }\n }\n\n start();\n\n return () => {\n disposed = true;\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n };\n }, [activeConfig]);\n\n const trackEvent = useCallback(\n (event: TrackEventInput) => {\n enqueue((client) => void client.track(event));\n },\n [enqueue]\n );\n\n const trackCtaClick = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackCtaClick(metadata));\n },\n [enqueue]\n );\n\n const trackFormSubmit = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackFormSubmit(metadata));\n },\n [enqueue]\n );\n\n return useMemo(\n () => ({ trackEvent, trackCtaClick, trackFormSubmit }),\n [trackEvent, trackCtaClick, trackFormSubmit]\n );\n}\n\n/**\n * Create a minimal analytics client\n *\n * This is a lightweight implementation for tracking basic events.\n * For full analytics features, use @riverbankcms/analytics package.\n */\nfunction createMinimalAnalyticsClient(config: {\n siteId: string;\n siteSlug: string;\n endpoint: string;\n sessionCookieName: string;\n}): AnalyticsClient {\n let sessionId: string | null = null;\n\n // Try to read existing session from cookie\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === config.sessionCookieName) {\n sessionId = value;\n break;\n }\n }\n\n // Generate new session if needed\n if (!sessionId) {\n sessionId = generateSessionId();\n // Set cookie for 30 days\n const expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\n document.cookie = `${config.sessionCookieName}=${sessionId}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;\n }\n\n const track = async (event: TrackEventInput) => {\n try {\n await fetch(config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n siteId: config.siteId,\n siteSlug: config.siteSlug,\n sessionId,\n eventType: event.eventType,\n metadata: {\n ...event.metadata,\n userAgent: navigator.userAgent,\n referrer: document.referrer,\n timestamp: new Date().toISOString(),\n },\n }),\n });\n } catch (error) {\n console.warn('[analytics] Failed to track event', error);\n }\n };\n\n const trackCtaClick = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'cta_click',\n metadata,\n });\n };\n\n const trackFormSubmit = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'form_submit',\n metadata,\n });\n };\n\n const destroy = () => {\n // Cleanup if needed\n };\n\n return {\n track,\n trackCtaClick,\n trackFormSubmit,\n destroy,\n };\n}\n\n/**\n * Generate a random session ID\n */\nfunction generateSessionId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/analytics/index.ts","../../src/analytics/AnalyticsBootstrap.tsx"],"sourcesContent":["/**\n * Analytics utilities for tracking user behavior\n *\n * Lightweight analytics helpers for tracking page views, CTA clicks,\n * form submissions, and custom events.\n */\n\nexport { AnalyticsBootstrap, useAnalytics } from './AnalyticsBootstrap';\nexport type {\n AnalyticsConfig,\n AnalyticsClient,\n AnalyticsHelpers,\n TrackEventInput,\n} from './AnalyticsBootstrap';\n","/**\n * Analytics Bootstrap Component\n *\n * Client component that initializes analytics tracking for a Builder site.\n * Auto-tracks page views and provides helpers for tracking custom events.\n */\n\n'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nexport type AnalyticsConfig = {\n /**\n * Site ID for analytics tracking\n */\n siteId: string;\n\n /**\n * Site slug for analytics tracking\n */\n siteSlug: string;\n\n /**\n * Analytics endpoint URL\n * @default '/api/analytics/collect'\n */\n endpoint?: string;\n\n /**\n * Custom session cookie name\n * @default 'builder_analytics_session'\n */\n sessionCookieName?: string;\n\n /**\n * Disable analytics tracking\n * @default false\n */\n disabled?: boolean;\n};\n\nexport type AnalyticsClient = {\n track: (event: TrackEventInput) => Promise<void>;\n trackCtaClick: (metadata?: Record<string, unknown>) => Promise<void>;\n trackFormSubmit: (metadata?: Record<string, unknown>) => Promise<void>;\n destroy: () => void;\n};\n\nexport type TrackEventInput = {\n eventType: string;\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Analytics helpers returned by useAnalytics hook\n */\nexport type AnalyticsHelpers = {\n trackEvent: (event: TrackEventInput) => void;\n trackCtaClick: (metadata?: Record<string, unknown>) => void;\n trackFormSubmit: (metadata?: Record<string, unknown>) => void;\n};\n\n/**\n * Analytics Bootstrap component\n *\n * Place this component in your layout to enable analytics tracking.\n *\n * @example\n * ```tsx\n * import { AnalyticsBootstrap } from '@riverbankcms/sdk/analytics';\n *\n * export default function Layout({ children }) {\n * return (\n * <html>\n * <body>\n * {children}\n * <AnalyticsBootstrap\n * siteId=\"your-site-id\"\n * siteSlug=\"your-site-slug\"\n * />\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport function AnalyticsBootstrap(config: AnalyticsConfig) {\n useAnalytics(config);\n\n // Component renders nothing, analytics runs in background\n return null;\n}\n\n/**\n * Hook for tracking analytics events\n *\n * @param config - Analytics configuration. Pass null to disable analytics.\n * @returns Analytics helpers for tracking events\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { useAnalytics } from '@riverbankcms/sdk/analytics';\n *\n * export function MyComponent() {\n * const analytics = useAnalytics({\n * siteId: 'your-site-id',\n * siteSlug: 'your-site-slug',\n * });\n *\n * const handleClick = () => {\n * analytics.trackCtaClick({ buttonLabel: 'Sign Up' });\n * };\n *\n * return <button onClick={handleClick}>Sign Up</button>;\n * }\n * ```\n */\nexport function useAnalytics(config: AnalyticsConfig | null): AnalyticsHelpers {\n const siteId = config?.siteId ?? null;\n const siteSlug = config?.siteSlug ?? '';\n const endpoint = config?.endpoint ?? '/api/analytics/collect';\n const sessionCookieName = config?.sessionCookieName ?? 'builder_analytics_session';\n const disabled = config?.disabled ?? false;\n\n const activeConfig = useMemo(() => {\n if (!siteId || disabled) {\n return null;\n }\n return { siteId, siteSlug, endpoint, sessionCookieName };\n }, [disabled, endpoint, sessionCookieName, siteId, siteSlug]);\n\n const stateRef = useRef<{\n client: AnalyticsClient | null;\n queue: Array<(client: AnalyticsClient) => void>;\n }>({\n client: null,\n queue: [],\n });\n\n const configRef = useRef<typeof activeConfig>(null);\n configRef.current = activeConfig;\n\n const enqueue = useCallback((action: (client: AnalyticsClient) => void) => {\n if (!configRef.current) return;\n const state = stateRef.current;\n if (state.client) {\n action(state.client);\n return;\n }\n state.queue.push(action);\n }, []);\n\n useEffect(() => {\n const state = stateRef.current;\n\n if (!activeConfig) {\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n return;\n }\n\n const configSnapshot = activeConfig;\n let disposed = false;\n\n async function start() {\n try {\n // Create minimal analytics client\n const client = createMinimalAnalyticsClient({\n siteId: configSnapshot.siteId,\n siteSlug: configSnapshot.siteSlug,\n endpoint: configSnapshot.endpoint,\n sessionCookieName: configSnapshot.sessionCookieName,\n });\n\n if (disposed) return;\n\n state.client = client;\n\n // Flush queued events\n if (state.queue.length > 0) {\n const pending = state.queue.splice(0);\n for (const action of pending) action(client);\n }\n\n // Auto-track initial page view\n await client.track({\n eventType: 'page_view',\n metadata: { path: window.location.pathname },\n });\n } catch (error) {\n console.warn('[analytics] Failed to initialize client', error);\n }\n }\n\n start();\n\n return () => {\n disposed = true;\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n };\n }, [activeConfig]);\n\n const trackEvent = useCallback(\n (event: TrackEventInput) => {\n enqueue((client) => void client.track(event));\n },\n [enqueue]\n );\n\n const trackCtaClick = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackCtaClick(metadata));\n },\n [enqueue]\n );\n\n const trackFormSubmit = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackFormSubmit(metadata));\n },\n [enqueue]\n );\n\n return useMemo(\n () => ({ trackEvent, trackCtaClick, trackFormSubmit }),\n [trackEvent, trackCtaClick, trackFormSubmit]\n );\n}\n\n/**\n * Create a minimal analytics client\n *\n * This is a lightweight implementation for tracking basic events.\n * For full analytics features, use @riverbankcms/analytics package.\n */\nfunction createMinimalAnalyticsClient(config: {\n siteId: string;\n siteSlug: string;\n endpoint: string;\n sessionCookieName: string;\n}): AnalyticsClient {\n let sessionId: string | null = null;\n\n // Try to read existing session from cookie\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === config.sessionCookieName) {\n sessionId = value ?? null;\n break;\n }\n }\n\n // Generate new session if needed\n if (!sessionId) {\n sessionId = generateSessionId();\n // Set cookie for 30 days\n const expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\n document.cookie = `${config.sessionCookieName}=${sessionId}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;\n }\n\n const track = async (event: TrackEventInput) => {\n try {\n await fetch(config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n siteId: config.siteId,\n siteSlug: config.siteSlug,\n sessionId,\n eventType: event.eventType,\n metadata: {\n ...event.metadata,\n userAgent: navigator.userAgent,\n referrer: document.referrer,\n timestamp: new Date().toISOString(),\n },\n }),\n });\n } catch (error) {\n console.warn('[analytics] Failed to track event', error);\n }\n };\n\n const trackCtaClick = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'cta_click',\n metadata,\n });\n };\n\n const trackFormSubmit = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'form_submit',\n metadata,\n });\n };\n\n const destroy = () => {\n // Cleanup if needed\n };\n\n return {\n track,\n trackCtaClick,\n trackFormSubmit,\n destroy,\n };\n}\n\n/**\n * Generate a random session ID\n */\nfunction generateSessionId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -105,7 +105,7 @@ function createMinimalAnalyticsClient(config) {
|
|
|
105
105
|
for (const cookie of cookies) {
|
|
106
106
|
const [name, value] = cookie.trim().split("=");
|
|
107
107
|
if (name === config.sessionCookieName) {
|
|
108
|
-
sessionId = value;
|
|
108
|
+
sessionId = value ?? null;
|
|
109
109
|
break;
|
|
110
110
|
}
|
|
111
111
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/analytics/AnalyticsBootstrap.tsx"],"sourcesContent":["/**\n * Analytics Bootstrap Component\n *\n * Client component that initializes analytics tracking for a Builder site.\n * Auto-tracks page views and provides helpers for tracking custom events.\n */\n\n'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nexport type AnalyticsConfig = {\n /**\n * Site ID for analytics tracking\n */\n siteId: string;\n\n /**\n * Site slug for analytics tracking\n */\n siteSlug: string;\n\n /**\n * Analytics endpoint URL\n * @default '/api/analytics/collect'\n */\n endpoint?: string;\n\n /**\n * Custom session cookie name\n * @default 'builder_analytics_session'\n */\n sessionCookieName?: string;\n\n /**\n * Disable analytics tracking\n * @default false\n */\n disabled?: boolean;\n};\n\nexport type AnalyticsClient = {\n track: (event: TrackEventInput) => Promise<void>;\n trackCtaClick: (metadata?: Record<string, unknown>) => Promise<void>;\n trackFormSubmit: (metadata?: Record<string, unknown>) => Promise<void>;\n destroy: () => void;\n};\n\nexport type TrackEventInput = {\n eventType: string;\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Analytics helpers returned by useAnalytics hook\n */\nexport type AnalyticsHelpers = {\n trackEvent: (event: TrackEventInput) => void;\n trackCtaClick: (metadata?: Record<string, unknown>) => void;\n trackFormSubmit: (metadata?: Record<string, unknown>) => void;\n};\n\n/**\n * Analytics Bootstrap component\n *\n * Place this component in your layout to enable analytics tracking.\n *\n * @example\n * ```tsx\n * import { AnalyticsBootstrap } from '@riverbankcms/sdk/analytics';\n *\n * export default function Layout({ children }) {\n * return (\n * <html>\n * <body>\n * {children}\n * <AnalyticsBootstrap\n * siteId=\"your-site-id\"\n * siteSlug=\"your-site-slug\"\n * />\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport function AnalyticsBootstrap(config: AnalyticsConfig) {\n useAnalytics(config);\n\n // Component renders nothing, analytics runs in background\n return null;\n}\n\n/**\n * Hook for tracking analytics events\n *\n * @param config - Analytics configuration. Pass null to disable analytics.\n * @returns Analytics helpers for tracking events\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { useAnalytics } from '@riverbankcms/sdk/analytics';\n *\n * export function MyComponent() {\n * const analytics = useAnalytics({\n * siteId: 'your-site-id',\n * siteSlug: 'your-site-slug',\n * });\n *\n * const handleClick = () => {\n * analytics.trackCtaClick({ buttonLabel: 'Sign Up' });\n * };\n *\n * return <button onClick={handleClick}>Sign Up</button>;\n * }\n * ```\n */\nexport function useAnalytics(config: AnalyticsConfig | null): AnalyticsHelpers {\n const siteId = config?.siteId ?? null;\n const siteSlug = config?.siteSlug ?? '';\n const endpoint = config?.endpoint ?? '/api/analytics/collect';\n const sessionCookieName = config?.sessionCookieName ?? 'builder_analytics_session';\n const disabled = config?.disabled ?? false;\n\n const activeConfig = useMemo(() => {\n if (!siteId || disabled) {\n return null;\n }\n return { siteId, siteSlug, endpoint, sessionCookieName };\n }, [disabled, endpoint, sessionCookieName, siteId, siteSlug]);\n\n const stateRef = useRef<{\n client: AnalyticsClient | null;\n queue: Array<(client: AnalyticsClient) => void>;\n }>({\n client: null,\n queue: [],\n });\n\n const configRef = useRef<typeof activeConfig>(null);\n configRef.current = activeConfig;\n\n const enqueue = useCallback((action: (client: AnalyticsClient) => void) => {\n if (!configRef.current) return;\n const state = stateRef.current;\n if (state.client) {\n action(state.client);\n return;\n }\n state.queue.push(action);\n }, []);\n\n useEffect(() => {\n const state = stateRef.current;\n\n if (!activeConfig) {\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n return;\n }\n\n const configSnapshot = activeConfig;\n let disposed = false;\n\n async function start() {\n try {\n // Create minimal analytics client\n const client = createMinimalAnalyticsClient({\n siteId: configSnapshot.siteId,\n siteSlug: configSnapshot.siteSlug,\n endpoint: configSnapshot.endpoint,\n sessionCookieName: configSnapshot.sessionCookieName,\n });\n\n if (disposed) return;\n\n state.client = client;\n\n // Flush queued events\n if (state.queue.length > 0) {\n const pending = state.queue.splice(0);\n for (const action of pending) action(client);\n }\n\n // Auto-track initial page view\n await client.track({\n eventType: 'page_view',\n metadata: { path: window.location.pathname },\n });\n } catch (error) {\n console.warn('[analytics] Failed to initialize client', error);\n }\n }\n\n start();\n\n return () => {\n disposed = true;\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n };\n }, [activeConfig]);\n\n const trackEvent = useCallback(\n (event: TrackEventInput) => {\n enqueue((client) => void client.track(event));\n },\n [enqueue]\n );\n\n const trackCtaClick = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackCtaClick(metadata));\n },\n [enqueue]\n );\n\n const trackFormSubmit = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackFormSubmit(metadata));\n },\n [enqueue]\n );\n\n return useMemo(\n () => ({ trackEvent, trackCtaClick, trackFormSubmit }),\n [trackEvent, trackCtaClick, trackFormSubmit]\n );\n}\n\n/**\n * Create a minimal analytics client\n *\n * This is a lightweight implementation for tracking basic events.\n * For full analytics features, use @riverbankcms/analytics package.\n */\nfunction createMinimalAnalyticsClient(config: {\n siteId: string;\n siteSlug: string;\n endpoint: string;\n sessionCookieName: string;\n}): AnalyticsClient {\n let sessionId: string | null = null;\n\n // Try to read existing session from cookie\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === config.sessionCookieName) {\n sessionId = value;\n break;\n }\n }\n\n // Generate new session if needed\n if (!sessionId) {\n sessionId = generateSessionId();\n // Set cookie for 30 days\n const expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\n document.cookie = `${config.sessionCookieName}=${sessionId}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;\n }\n\n const track = async (event: TrackEventInput) => {\n try {\n await fetch(config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n siteId: config.siteId,\n siteSlug: config.siteSlug,\n sessionId,\n eventType: event.eventType,\n metadata: {\n ...event.metadata,\n userAgent: navigator.userAgent,\n referrer: document.referrer,\n timestamp: new Date().toISOString(),\n },\n }),\n });\n } catch (error) {\n console.warn('[analytics] Failed to track event', error);\n }\n };\n\n const trackCtaClick = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'cta_click',\n metadata,\n });\n };\n\n const trackFormSubmit = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'form_submit',\n metadata,\n });\n };\n\n const destroy = () => {\n // Cleanup if needed\n };\n\n return {\n track,\n trackCtaClick,\n trackFormSubmit,\n destroy,\n };\n}\n\n/**\n * Generate a random session ID\n */\nfunction generateSessionId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/analytics/AnalyticsBootstrap.tsx"],"sourcesContent":["/**\n * Analytics Bootstrap Component\n *\n * Client component that initializes analytics tracking for a Builder site.\n * Auto-tracks page views and provides helpers for tracking custom events.\n */\n\n'use client';\n\nimport { useCallback, useEffect, useMemo, useRef } from 'react';\n\nexport type AnalyticsConfig = {\n /**\n * Site ID for analytics tracking\n */\n siteId: string;\n\n /**\n * Site slug for analytics tracking\n */\n siteSlug: string;\n\n /**\n * Analytics endpoint URL\n * @default '/api/analytics/collect'\n */\n endpoint?: string;\n\n /**\n * Custom session cookie name\n * @default 'builder_analytics_session'\n */\n sessionCookieName?: string;\n\n /**\n * Disable analytics tracking\n * @default false\n */\n disabled?: boolean;\n};\n\nexport type AnalyticsClient = {\n track: (event: TrackEventInput) => Promise<void>;\n trackCtaClick: (metadata?: Record<string, unknown>) => Promise<void>;\n trackFormSubmit: (metadata?: Record<string, unknown>) => Promise<void>;\n destroy: () => void;\n};\n\nexport type TrackEventInput = {\n eventType: string;\n metadata?: Record<string, unknown>;\n};\n\n/**\n * Analytics helpers returned by useAnalytics hook\n */\nexport type AnalyticsHelpers = {\n trackEvent: (event: TrackEventInput) => void;\n trackCtaClick: (metadata?: Record<string, unknown>) => void;\n trackFormSubmit: (metadata?: Record<string, unknown>) => void;\n};\n\n/**\n * Analytics Bootstrap component\n *\n * Place this component in your layout to enable analytics tracking.\n *\n * @example\n * ```tsx\n * import { AnalyticsBootstrap } from '@riverbankcms/sdk/analytics';\n *\n * export default function Layout({ children }) {\n * return (\n * <html>\n * <body>\n * {children}\n * <AnalyticsBootstrap\n * siteId=\"your-site-id\"\n * siteSlug=\"your-site-slug\"\n * />\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport function AnalyticsBootstrap(config: AnalyticsConfig) {\n useAnalytics(config);\n\n // Component renders nothing, analytics runs in background\n return null;\n}\n\n/**\n * Hook for tracking analytics events\n *\n * @param config - Analytics configuration. Pass null to disable analytics.\n * @returns Analytics helpers for tracking events\n *\n * @example\n * ```tsx\n * 'use client';\n *\n * import { useAnalytics } from '@riverbankcms/sdk/analytics';\n *\n * export function MyComponent() {\n * const analytics = useAnalytics({\n * siteId: 'your-site-id',\n * siteSlug: 'your-site-slug',\n * });\n *\n * const handleClick = () => {\n * analytics.trackCtaClick({ buttonLabel: 'Sign Up' });\n * };\n *\n * return <button onClick={handleClick}>Sign Up</button>;\n * }\n * ```\n */\nexport function useAnalytics(config: AnalyticsConfig | null): AnalyticsHelpers {\n const siteId = config?.siteId ?? null;\n const siteSlug = config?.siteSlug ?? '';\n const endpoint = config?.endpoint ?? '/api/analytics/collect';\n const sessionCookieName = config?.sessionCookieName ?? 'builder_analytics_session';\n const disabled = config?.disabled ?? false;\n\n const activeConfig = useMemo(() => {\n if (!siteId || disabled) {\n return null;\n }\n return { siteId, siteSlug, endpoint, sessionCookieName };\n }, [disabled, endpoint, sessionCookieName, siteId, siteSlug]);\n\n const stateRef = useRef<{\n client: AnalyticsClient | null;\n queue: Array<(client: AnalyticsClient) => void>;\n }>({\n client: null,\n queue: [],\n });\n\n const configRef = useRef<typeof activeConfig>(null);\n configRef.current = activeConfig;\n\n const enqueue = useCallback((action: (client: AnalyticsClient) => void) => {\n if (!configRef.current) return;\n const state = stateRef.current;\n if (state.client) {\n action(state.client);\n return;\n }\n state.queue.push(action);\n }, []);\n\n useEffect(() => {\n const state = stateRef.current;\n\n if (!activeConfig) {\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n return;\n }\n\n const configSnapshot = activeConfig;\n let disposed = false;\n\n async function start() {\n try {\n // Create minimal analytics client\n const client = createMinimalAnalyticsClient({\n siteId: configSnapshot.siteId,\n siteSlug: configSnapshot.siteSlug,\n endpoint: configSnapshot.endpoint,\n sessionCookieName: configSnapshot.sessionCookieName,\n });\n\n if (disposed) return;\n\n state.client = client;\n\n // Flush queued events\n if (state.queue.length > 0) {\n const pending = state.queue.splice(0);\n for (const action of pending) action(client);\n }\n\n // Auto-track initial page view\n await client.track({\n eventType: 'page_view',\n metadata: { path: window.location.pathname },\n });\n } catch (error) {\n console.warn('[analytics] Failed to initialize client', error);\n }\n }\n\n start();\n\n return () => {\n disposed = true;\n if (state.client) {\n state.client.destroy();\n state.client = null;\n }\n state.queue = [];\n };\n }, [activeConfig]);\n\n const trackEvent = useCallback(\n (event: TrackEventInput) => {\n enqueue((client) => void client.track(event));\n },\n [enqueue]\n );\n\n const trackCtaClick = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackCtaClick(metadata));\n },\n [enqueue]\n );\n\n const trackFormSubmit = useCallback(\n (metadata?: Record<string, unknown>) => {\n enqueue((client) => void client.trackFormSubmit(metadata));\n },\n [enqueue]\n );\n\n return useMemo(\n () => ({ trackEvent, trackCtaClick, trackFormSubmit }),\n [trackEvent, trackCtaClick, trackFormSubmit]\n );\n}\n\n/**\n * Create a minimal analytics client\n *\n * This is a lightweight implementation for tracking basic events.\n * For full analytics features, use @riverbankcms/analytics package.\n */\nfunction createMinimalAnalyticsClient(config: {\n siteId: string;\n siteSlug: string;\n endpoint: string;\n sessionCookieName: string;\n}): AnalyticsClient {\n let sessionId: string | null = null;\n\n // Try to read existing session from cookie\n const cookies = document.cookie.split(';');\n for (const cookie of cookies) {\n const [name, value] = cookie.trim().split('=');\n if (name === config.sessionCookieName) {\n sessionId = value ?? null;\n break;\n }\n }\n\n // Generate new session if needed\n if (!sessionId) {\n sessionId = generateSessionId();\n // Set cookie for 30 days\n const expires = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);\n document.cookie = `${config.sessionCookieName}=${sessionId}; expires=${expires.toUTCString()}; path=/; SameSite=Lax`;\n }\n\n const track = async (event: TrackEventInput) => {\n try {\n await fetch(config.endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n siteId: config.siteId,\n siteSlug: config.siteSlug,\n sessionId,\n eventType: event.eventType,\n metadata: {\n ...event.metadata,\n userAgent: navigator.userAgent,\n referrer: document.referrer,\n timestamp: new Date().toISOString(),\n },\n }),\n });\n } catch (error) {\n console.warn('[analytics] Failed to track event', error);\n }\n };\n\n const trackCtaClick = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'cta_click',\n metadata,\n });\n };\n\n const trackFormSubmit = async (metadata?: Record<string, unknown>) => {\n await track({\n eventType: 'form_submit',\n metadata,\n });\n };\n\n const destroy = () => {\n // Cleanup if needed\n };\n\n return {\n track,\n trackCtaClick,\n trackFormSubmit,\n destroy,\n };\n}\n\n/**\n * Generate a random session ID\n */\nfunction generateSessionId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n"],"mappings":"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","names":[]}
|
package/dist/client/bookings.js
CHANGED
|
@@ -516,7 +516,7 @@ function ServiceResourceSelector({
|
|
|
516
516
|
};
|
|
517
517
|
const canContinue = selectedServiceId && !isLoadingResources;
|
|
518
518
|
(0, import_react4.useEffect)(() => {
|
|
519
|
-
if (services.length === 1 && !selectedServiceId) {
|
|
519
|
+
if (services.length === 1 && services[0] && !selectedServiceId) {
|
|
520
520
|
handleServiceChange(services[0].id);
|
|
521
521
|
}
|
|
522
522
|
}, [services, selectedServiceId, handleServiceChange]);
|
|
@@ -939,15 +939,15 @@ function useAvailableDates({
|
|
|
939
939
|
setHasMore(false);
|
|
940
940
|
return;
|
|
941
941
|
}
|
|
942
|
-
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
943
|
-
const endDate = new Date(Date.now() + initialDays * 24 * 60 * 60 * 1e3).toISOString().split("T")[0];
|
|
942
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0] ?? "";
|
|
943
|
+
const endDate = new Date(Date.now() + initialDays * 24 * 60 * 60 * 1e3).toISOString().split("T")[0] ?? "";
|
|
944
944
|
fetchDates(today, endDate, false);
|
|
945
945
|
}, [serviceId, fetchDates, initialDays]);
|
|
946
946
|
const loadMore = (0, import_react6.useCallback)(() => {
|
|
947
947
|
if (!nextStartDateRef.current || isLoading) return;
|
|
948
948
|
const start = nextStartDateRef.current;
|
|
949
949
|
const msPerDay = 24 * 60 * 60 * 1e3;
|
|
950
|
-
const end = new Date(new Date(start).getTime() + BOOKING_FETCH_CHUNK_DAYS * msPerDay).toISOString().split("T")[0];
|
|
950
|
+
const end = new Date(new Date(start).getTime() + BOOKING_FETCH_CHUNK_DAYS * msPerDay).toISOString().split("T")[0] ?? "";
|
|
951
951
|
fetchDates(start, end, true);
|
|
952
952
|
}, [fetchDates, isLoading]);
|
|
953
953
|
return {
|
|
@@ -1366,7 +1366,7 @@ function useBookingSteps(siteId, formConfig, services) {
|
|
|
1366
1366
|
return (0, import_react9.useMemo)(() => {
|
|
1367
1367
|
if (!formConfig) return [];
|
|
1368
1368
|
const stepsArray = [];
|
|
1369
|
-
const effectiveServiceId = formConfig.settings?.serviceId || (services.length === 1 ? services[0]
|
|
1369
|
+
const effectiveServiceId = formConfig.settings?.serviceId || (services.length === 1 ? services[0]?.id : void 0);
|
|
1370
1370
|
const needsServiceSelection = !formConfig.settings?.serviceId && services.length > 1 || formConfig.settings?.serviceIds && formConfig.settings.serviceIds.length > 1;
|
|
1371
1371
|
if (needsServiceSelection) {
|
|
1372
1372
|
stepsArray.push({
|
|
@@ -1424,7 +1424,7 @@ function useBookingSteps(siteId, formConfig, services) {
|
|
|
1424
1424
|
|
|
1425
1425
|
// ../blocks/src/system/runtime/hooks/useBookingSubmission.ts
|
|
1426
1426
|
var import_react10 = require("react");
|
|
1427
|
-
function useBookingSubmission(
|
|
1427
|
+
function useBookingSubmission(_siteId) {
|
|
1428
1428
|
const [isSubmitting, setIsSubmitting] = (0, import_react10.useState)(false);
|
|
1429
1429
|
const [error, setError] = (0, import_react10.useState)(null);
|
|
1430
1430
|
const [isSuccess, setIsSuccess] = (0, import_react10.useState)(false);
|