keystone-design-bootstrap 1.0.87 → 1.0.88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/design_system/sections/index.d.ts +1 -2
  2. package/dist/index.d.ts +24 -5
  3. package/dist/lib/server-api.d.ts +1 -2
  4. package/dist/lib/server-api.js +1 -1
  5. package/dist/lib/server-api.js.map +1 -1
  6. package/dist/package-DeHKpQp7.d.ts +121 -0
  7. package/dist/types/index.d.ts +68 -6
  8. package/package.json +28 -28
  9. package/src/design_system/portal/PortalPage.tsx +2 -3
  10. package/src/lib/server-api.ts +1 -2
  11. package/dist/company-information-C1pP-SvU.d.ts +0 -50
  12. package/dist/config-C_XBZixg.d.ts +0 -21
  13. package/dist/consumer-BWjQawiO.d.ts +0 -48
  14. package/dist/design_system/portal/index.d.ts +0 -52
  15. package/dist/design_system/portal/index.js +0 -3113
  16. package/dist/design_system/portal/index.js.map +0 -1
  17. package/dist/lib/consumer-session.d.ts +0 -16
  18. package/dist/lib/consumer-session.js +0 -85
  19. package/dist/lib/consumer-session.js.map +0 -1
  20. package/dist/lib/cta-urls.d.ts +0 -34
  21. package/dist/lib/cta-urls.js +0 -33
  22. package/dist/lib/cta-urls.js.map +0 -1
  23. package/dist/next/contexts/form-definitions.d.ts +0 -17
  24. package/dist/next/contexts/form-definitions.js +0 -21
  25. package/dist/next/contexts/form-definitions.js.map +0 -1
  26. package/dist/next/gallery/design-gallery.d.ts +0 -103
  27. package/dist/next/gallery/design-gallery.js +0 -19301
  28. package/dist/next/gallery/design-gallery.js.map +0 -1
  29. package/dist/next/layouts/root-layout.d.ts +0 -55
  30. package/dist/next/layouts/root-layout.js +0 -19713
  31. package/dist/next/layouts/root-layout.js.map +0 -1
  32. package/dist/next/legal/privacy-policy.d.ts +0 -7
  33. package/dist/next/legal/privacy-policy.js +0 -18949
  34. package/dist/next/legal/privacy-policy.js.map +0 -1
  35. package/dist/next/legal/terms-of-service.d.ts +0 -7
  36. package/dist/next/legal/terms-of-service.js +0 -18949
  37. package/dist/next/legal/terms-of-service.js.map +0 -1
  38. package/dist/next/providers/ssr-provider.d.ts +0 -12
  39. package/dist/next/providers/ssr-provider.js +0 -12
  40. package/dist/next/providers/ssr-provider.js.map +0 -1
  41. package/dist/next/routes/chat.d.ts +0 -26
  42. package/dist/next/routes/chat.js +0 -160
  43. package/dist/next/routes/chat.js.map +0 -1
  44. package/dist/next/routes/consumer-auth.d.ts +0 -33
  45. package/dist/next/routes/consumer-auth.js +0 -254
  46. package/dist/next/routes/consumer-auth.js.map +0 -1
  47. package/dist/next/routes/form.d.ts +0 -37
  48. package/dist/next/routes/form.js +0 -97
  49. package/dist/next/routes/form.js.map +0 -1
  50. package/dist/package-IU_GpDA0.d.ts +0 -74
  51. package/src/types/rails-actioncable.d.ts +0 -16
@@ -1,4 +1,4 @@
1
- import { S as Service, P as Package } from '../../package-IU_GpDA0.js';
1
+ import { S as Service, P as Package, C as CompanyInformation } from '../../package-DeHKpQp7.js';
2
2
  import * as React from 'react';
3
3
  import React__default, { ComponentProps, ReactNode, FC } from 'react';
4
4
  export { Theme } from '../../themes/index.js';
@@ -6,7 +6,6 @@ import { B as BlogPost, a as BlogPostAuthor, d as BlogPostTag } from '../../blog
6
6
  import { BadgeGroup } from '../elements/index.js';
7
7
  import { F as FormDefinition } from '../../form-C94A_PX_.js';
8
8
  import { W as WebsitePhotos } from '../../website-photos-Cl1YqAno.js';
9
- import { C as CompanyInformation } from '../../company-information-C1pP-SvU.js';
10
9
  import '../../photos-CmBdWiuZ.js';
11
10
  import 'react-aria-components';
12
11
  import 'embla-carousel-react';
package/dist/index.d.ts CHANGED
@@ -1,15 +1,13 @@
1
1
  export { AboutHome, BlogCardFullWidthHorizontal, BlogCardFullWidthHorizontalAlt, BlogCardFullWidthHorizontalCompact, BlogCardFullWidthHorizontalMinimal, BlogCardFullWidthVertical, BlogCardFullWidthVerticalAlt, BlogCardFullWidthVerticalCompact, BlogCardFullWidthVerticalMinimal, BlogCardHorizontal, BlogCardHorizontalBadge, BlogCardHorizontalCompact, BlogCardHorizontalMinimal, BlogCardVertical, BlogCardVerticalBadge, BlogCardVerticalCompact, BlogCardVerticalMinimal, BlogGallery, BlogHome, BlogPostSection, BlogSection, ContactHome, ContactSection, EmailSignupSection, EmailSignupSectionProps, FAQGrid, FAQHero, FAQHome, FeatureTabHorizontal, FeatureTabVertical, FeatureTextCentered, FeatureTextFeaturedIconBox, FeatureTextFeaturedIconCard, FeatureTextFeaturedIconLeft, FeatureTextFeaturedIconTopCentered, FeatureTextFeaturedIconTopCenteredBrand, FeatureTextFeaturedIconTopLeft, FeatureTextFeaturedIconTopLeftBrand, FeatureTextIconCard, FeatureTextIconLeft, FeatureTextIconTopCentered, FeatureTextIconTopLeft, FeatureTextIntegrationIconBox, FeatureTextIntegrationIconLeft, FeatureTextIntegrationIconTopCentered, FeatureTextIntegrationIconTopLeft, FeatureTextLeft, FeatureTextLeftBrand, FooterHome, GenericHeaderComponent, GenericTextHero, HeaderNavigation, HeroHome, HomeHeroComponent, JobApplicationForm, JobDetailHero, JobDetailSection, JobGallery, LocationDetailHero, LocationDetailsSection, LocationGrid, PackageForMenu, PolicyDocumentSection, ServiceDetailContent, ServiceDetailHero, ServiceMenuSection, ServiceMenuSectionProps, ServicesGrid, ServicesHome, SocialMediaGrid, SocialMediaHero, StatisticsSection, TeamGrid, TestimonialsGrid, TestimonialsHero, TestimonialsHome, ValuesSection, getBlogPostData } from './design_system/sections/index.js';
2
2
  export { Avatar, AvatarLabelGroup, Badge, BadgeGroup, BadgeWithDot, Breadcrumb, Button, ButtonGroup, Carousel, CarouselContext, CarouselSectionWrapper, ComboBox, FeaturedIcon, Form, FormContainer, GoogleMap, HintText, Input, InputBase, InputGroup, Label, MarkdownRenderer, Modal, ModalProps, NativeSelect, Pagination, PaginationPageDefault, PaginationPageMinimalCenter, PhotoWithFallback, PrivacyCheckbox, RatingBadge, RatingStars, RoundButton, Select, SelectItem, SocialIcon, StarIcon, Textarea, Tooltip, VerifiedTick, VideoModal, VideoPlayButton, Wreath, getSocialIcon, getStarProgress, useCarousel } from './design_system/elements/index.js';
3
- export { ResolvedCtaUrls, isExternalCtaUrl, resolveCtaUrls } from './lib/cta-urls.js';
3
+ import { C as CompanyInformation } from './package-DeHKpQp7.js';
4
4
  export { ThemeProvider, useTheme } from './contexts/index.js';
5
5
  import React__default from 'react';
6
6
  export { Theme } from './themes/index.js';
7
- import './package-IU_GpDA0.js';
8
- import './photos-CmBdWiuZ.js';
9
7
  import './blog-post-vWzW8yFb.js';
8
+ import './photos-CmBdWiuZ.js';
10
9
  import './form-C94A_PX_.js';
11
10
  import './website-photos-Cl1YqAno.js';
12
- import './company-information-C1pP-SvU.js';
13
11
  import 'react-aria-components';
14
12
  import 'embla-carousel-react';
15
13
 
@@ -23,6 +21,27 @@ interface ContactFormResult {
23
21
  declare function submitContactFormAction(formData: FormData): Promise<ContactFormResult>;
24
22
  declare function submitLeadFormAction(formData: FormData): Promise<ContactFormResult>;
25
23
 
24
+ /**
25
+ * Resolves the primary and secondary CTA hrefs used across the site.
26
+ *
27
+ * Resolution order for primaryHref:
28
+ * 1. portal_url — set by backend when account has consumer portal enabled
29
+ * 2. external_management_url — booking platform URL from the API
30
+ * 3. /contact — final fallback
31
+ *
32
+ * No per-site configuration needed. Enable the portal in the admin console and
33
+ * every CTA across the site automatically routes to the portal.
34
+ */
35
+
36
+ /** True when the href is absolute (external); use for target="_blank" and rel="noopener noreferrer". */
37
+ declare function isExternalCtaUrl(href: string): boolean;
38
+ interface ResolvedCtaUrls {
39
+ primaryHref: string;
40
+ secondaryHref: string;
41
+ hasSecondary: boolean;
42
+ }
43
+ declare function resolveCtaUrls(companyInformation?: CompanyInformation | null): ResolvedCtaUrls;
44
+
26
45
  interface TeamMember {
27
46
  id: number;
28
47
  name: string;
@@ -48,4 +67,4 @@ interface ChatWidgetProps {
48
67
  }
49
68
  declare function ChatWidget({ position, primaryColor, sessionId: providedSessionId, contactId, displayName: providedDisplayName, teamMembers }: ChatWidgetProps): React__default.JSX.Element;
50
69
 
51
- export { ChatWidget, submitContactFormAction, submitLeadFormAction };
70
+ export { ChatWidget, type ResolvedCtaUrls, isExternalCtaUrl, resolveCtaUrls, submitContactFormAction, submitLeadFormAction };
@@ -1,6 +1,5 @@
1
1
  import { F as FormDefinition } from '../form-C94A_PX_.js';
2
- import { C as CompanyInformation } from '../company-information-C1pP-SvU.js';
3
- import { P as Package, S as Service } from '../package-IU_GpDA0.js';
2
+ import { C as CompanyInformation, P as Package, S as Service } from '../package-DeHKpQp7.js';
4
3
  import { W as WebsitePhotos } from '../website-photos-Cl1YqAno.js';
5
4
  import '../photos-CmBdWiuZ.js';
6
5
 
@@ -100,7 +100,7 @@ async function getJobPosting(slug) {
100
100
  return serverFetch(`/public/job_postings/by_slug/${slug}`, defaultOptions);
101
101
  }
102
102
  async function getSocialPosts() {
103
- return serverFetch("/public/social_posts", { cache: "no-store" });
103
+ return serverFetch("/public/social_posts", defaultOptions);
104
104
  }
105
105
  async function getPackages() {
106
106
  return serverFetch("/public/packages", defaultOptions);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/server-api.ts"],"sourcesContent":["/**\n * Server-side API client for SSR\n * API key is stored securely on the server - never exposed to browser\n */\n\nimport type { CompanyInformation } from '../types/api/company-information';\nimport type { Service } from '../types/api/service';\nimport type { Package } from '../types/api/package';\nimport type { WebsitePhotos } from '../types/api/website-photos';\n\nconst API_URL = process.env.API_URL || 'http://localhost:3000/api/v1';\nconst API_KEY = process.env.API_KEY || '';\n\ninterface FetchOptions {\n cache?: RequestCache;\n revalidate?: number;\n}\n\nasync function serverFetch<T>(endpoint: string, options: FetchOptions = {}): Promise<T | null> {\n const url = `${API_URL}${endpoint}`;\n \n try {\n const fetchOptions: RequestInit & { next?: { revalidate?: number } } = {\n headers: {\n 'X-API-Key': API_KEY,\n 'Content-Type': 'application/json',\n },\n cache: options.cache,\n };\n \n if (options.revalidate) {\n fetchOptions.next = { revalidate: options.revalidate };\n }\n \n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n console.error(`[Server API] Error ${response.status} for ${endpoint}`);\n return null;\n }\n\n const json = await response.json();\n \n // Rails API returns { data: [...], meta: {...} }\n return json.data ?? json;\n } catch (error) {\n console.error(`[Server API] Failed to fetch ${endpoint}:`, error);\n return null;\n }\n}\n\n/**\n * Generic serverApi object for flexible endpoint access\n */\nexport const serverApi = {\n get: <T = unknown>(endpoint: string, options?: FetchOptions): Promise<T | null> => {\n return serverFetch<T>(endpoint, options || { revalidate: 60 });\n }\n};\n\n// Revalidate data every 60 seconds (ISR)\nconst defaultOptions: FetchOptions = { revalidate: 60 };\n\nexport async function getCompanyInformation(): Promise<CompanyInformation | null> {\n return serverFetch<CompanyInformation>('/public/company_information', defaultOptions);\n}\n\n/** Ads config (e.g. Meta Pixel). Returns { meta_pixel_id?: string } or {}. Only present when account has connected Meta Ads. */\nexport async function getAdsConfig(): Promise<{ meta_pixel_id?: string } | null> {\n const data = await serverFetch<{ meta_pixel_id?: string }>('/public/ads_config', defaultOptions);\n return data ?? null;\n}\n\n/** Extract Meta Pixel ID from ads config for use with <MetaPixel pixelId={...} />. Only returns a value when present and valid (numeric). */\nexport function getMetaPixelId(adsConfig: { meta_pixel_id?: string } | null | undefined): string | null {\n const id = adsConfig && typeof adsConfig === 'object' && 'meta_pixel_id' in adsConfig && adsConfig.meta_pixel_id;\n const str = id != null && id !== '' ? String(id).trim() : '';\n return str !== '' && str !== 'null' && /^\\d+$/.test(str) ? str : null;\n}\n\nexport type AnalyticsConfig = {\n /** PostHog project API key — platform-wide, from POSTHOG_API_KEY env var on the Rails server. */\n posthog_api_key?: string;\n /** Per-site GTM container ID (e.g. GTM-ABC123), provisioned by Keystone. */\n gtm_container_public_id?: string;\n /**\n * Environment identifier from KEYSTONE_ENV on the Rails server (e.g. \"production\", \"staging\",\n * \"development\"). Registered as a PostHog super property on every event so the sync job can\n * filter by environment and avoid cross-environment data contamination.\n */\n environment?: string;\n};\n\n/** Analytics config for customer sites. Returns platform-wide analytics keys (e.g. PostHog). */\nexport async function getAnalyticsConfig(): Promise<AnalyticsConfig | null> {\n const data = await serverFetch<AnalyticsConfig>('/public/analytics_config', defaultOptions);\n return data ?? null;\n}\n\n/** Extract PostHog API key from analytics config for use with <PostHogProvider apiKey={...} />. */\nexport function getPostHogApiKey(analyticsConfig: AnalyticsConfig | null | undefined): string | null {\n const key = analyticsConfig?.posthog_api_key;\n const str = key != null && key !== '' ? String(key).trim() : '';\n return str !== '' && str !== 'null' ? str : null;\n}\n\n/** Extract GTM container ID from analytics config for use with <GoogleTagManager containerId={...} />. */\nexport function getGtmContainerPublicId(analyticsConfig: AnalyticsConfig | null | undefined): string | null {\n const value = analyticsConfig?.gtm_container_public_id;\n const str = value != null && value !== '' ? String(value).trim() : '';\n return str !== '' && str !== 'null' && /^GTM-[A-Z0-9]+$/i.test(str) ? str : null;\n}\n\n/** Extract environment string from analytics config for use with <PostHogProvider environment={...} />. */\nexport function getKeystoneEnvironment(analyticsConfig: AnalyticsConfig | null | undefined): string {\n return analyticsConfig?.environment?.trim() || 'development';\n}\n\nexport async function getServices(): Promise<Service[] | null> {\n return serverFetch<Service[]>('/public/services', defaultOptions);\n}\n\nexport async function getService(slug: string): Promise<Service | null> {\n return serverFetch<Service>(`/public/services/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getLocations() {\n return serverFetch('/public/locations', defaultOptions);\n}\n\nexport async function getLocation(slug: string) {\n return serverFetch(`/public/locations/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getReviews() {\n return serverFetch('/public/reviews', defaultOptions);\n}\n\nexport async function getFAQs() {\n return serverFetch('/public/faq_questions', defaultOptions);\n}\n\nexport async function getBlogPosts() {\n return serverFetch('/public/blog_posts', defaultOptions);\n}\n\nexport async function getBlogPost(slug: string) {\n return serverFetch(`/public/blog_posts/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getTeamMembers() {\n return serverFetch('/public/team_members', defaultOptions);\n}\n\nexport async function getWebsitePhotos(): Promise<WebsitePhotos | null> {\n return serverFetch<WebsitePhotos>('/public/website_photos', defaultOptions);\n}\n\nexport async function getJobPostings() {\n return serverFetch('/public/job_postings', defaultOptions);\n}\n\nexport async function getJobPosting(slug: string) {\n return serverFetch(`/public/job_postings/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getSocialPosts() {\n // Social payloads can exceed Next's data-cache item size; avoid noisy build warnings.\n return serverFetch('/public/social_posts', { cache: 'no-store' });\n}\n\n/** Packages (bundles of service items). */\nexport async function getPackages(): Promise<Package[] | null> {\n return serverFetch<Package[]>('/public/packages', defaultOptions);\n}\n\nexport async function getPackage(slug: string): Promise<Package | null> {\n return serverFetch<Package>(`/public/packages/by_slug/${encodeURIComponent(slug)}`, defaultOptions);\n}\n\n// Alias for testimonials (API uses \"reviews\")\nexport async function getTestimonials() {\n return getReviews();\n}\n\n/** Form definition for dynamic form rendering, fetched by form_type. */\nexport async function getForm(formType: string) {\n type FormDefinition = import('../types/api/form').FormDefinition;\n return serverFetch<FormDefinition>(`/public/forms/${encodeURIComponent(formType)}`, defaultOptions);\n}\n\n/** Form definition for dynamic form rendering, fetched by numeric ID. */\nexport async function getFormById(id: number | string) {\n type FormDefinition = import('../types/api/form').FormDefinition;\n return serverFetch<FormDefinition>(`/public/form_by_id/${encodeURIComponent(id)}`, defaultOptions);\n}\n\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/lib/server-api.ts"],"sourcesContent":["/**\n * Server-side API client for SSR\n * API key is stored securely on the server - never exposed to browser\n */\n\nimport type { CompanyInformation } from '../types/api/company-information';\nimport type { Service } from '../types/api/service';\nimport type { Package } from '../types/api/package';\nimport type { WebsitePhotos } from '../types/api/website-photos';\n\nconst API_URL = process.env.API_URL || 'http://localhost:3000/api/v1';\nconst API_KEY = process.env.API_KEY || '';\n\ninterface FetchOptions {\n cache?: RequestCache;\n revalidate?: number;\n}\n\nasync function serverFetch<T>(endpoint: string, options: FetchOptions = {}): Promise<T | null> {\n const url = `${API_URL}${endpoint}`;\n \n try {\n const fetchOptions: RequestInit & { next?: { revalidate?: number } } = {\n headers: {\n 'X-API-Key': API_KEY,\n 'Content-Type': 'application/json',\n },\n cache: options.cache,\n };\n \n if (options.revalidate) {\n fetchOptions.next = { revalidate: options.revalidate };\n }\n \n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n console.error(`[Server API] Error ${response.status} for ${endpoint}`);\n return null;\n }\n\n const json = await response.json();\n \n // Rails API returns { data: [...], meta: {...} }\n return json.data ?? json;\n } catch (error) {\n console.error(`[Server API] Failed to fetch ${endpoint}:`, error);\n return null;\n }\n}\n\n/**\n * Generic serverApi object for flexible endpoint access\n */\nexport const serverApi = {\n get: <T = unknown>(endpoint: string, options?: FetchOptions): Promise<T | null> => {\n return serverFetch<T>(endpoint, options || { revalidate: 60 });\n }\n};\n\n// Revalidate data every 60 seconds (ISR)\nconst defaultOptions: FetchOptions = { revalidate: 60 };\n\nexport async function getCompanyInformation(): Promise<CompanyInformation | null> {\n return serverFetch<CompanyInformation>('/public/company_information', defaultOptions);\n}\n\n/** Ads config (e.g. Meta Pixel). Returns { meta_pixel_id?: string } or {}. Only present when account has connected Meta Ads. */\nexport async function getAdsConfig(): Promise<{ meta_pixel_id?: string } | null> {\n const data = await serverFetch<{ meta_pixel_id?: string }>('/public/ads_config', defaultOptions);\n return data ?? null;\n}\n\n/** Extract Meta Pixel ID from ads config for use with <MetaPixel pixelId={...} />. Only returns a value when present and valid (numeric). */\nexport function getMetaPixelId(adsConfig: { meta_pixel_id?: string } | null | undefined): string | null {\n const id = adsConfig && typeof adsConfig === 'object' && 'meta_pixel_id' in adsConfig && adsConfig.meta_pixel_id;\n const str = id != null && id !== '' ? String(id).trim() : '';\n return str !== '' && str !== 'null' && /^\\d+$/.test(str) ? str : null;\n}\n\nexport type AnalyticsConfig = {\n /** PostHog project API key — platform-wide, from POSTHOG_API_KEY env var on the Rails server. */\n posthog_api_key?: string;\n /** Per-site GTM container ID (e.g. GTM-ABC123), provisioned by Keystone. */\n gtm_container_public_id?: string;\n /**\n * Environment identifier from KEYSTONE_ENV on the Rails server (e.g. \"production\", \"staging\",\n * \"development\"). Registered as a PostHog super property on every event so the sync job can\n * filter by environment and avoid cross-environment data contamination.\n */\n environment?: string;\n};\n\n/** Analytics config for customer sites. Returns platform-wide analytics keys (e.g. PostHog). */\nexport async function getAnalyticsConfig(): Promise<AnalyticsConfig | null> {\n const data = await serverFetch<AnalyticsConfig>('/public/analytics_config', defaultOptions);\n return data ?? null;\n}\n\n/** Extract PostHog API key from analytics config for use with <PostHogProvider apiKey={...} />. */\nexport function getPostHogApiKey(analyticsConfig: AnalyticsConfig | null | undefined): string | null {\n const key = analyticsConfig?.posthog_api_key;\n const str = key != null && key !== '' ? String(key).trim() : '';\n return str !== '' && str !== 'null' ? str : null;\n}\n\n/** Extract GTM container ID from analytics config for use with <GoogleTagManager containerId={...} />. */\nexport function getGtmContainerPublicId(analyticsConfig: AnalyticsConfig | null | undefined): string | null {\n const value = analyticsConfig?.gtm_container_public_id;\n const str = value != null && value !== '' ? String(value).trim() : '';\n return str !== '' && str !== 'null' && /^GTM-[A-Z0-9]+$/i.test(str) ? str : null;\n}\n\n/** Extract environment string from analytics config for use with <PostHogProvider environment={...} />. */\nexport function getKeystoneEnvironment(analyticsConfig: AnalyticsConfig | null | undefined): string {\n return analyticsConfig?.environment?.trim() || 'development';\n}\n\nexport async function getServices(): Promise<Service[] | null> {\n return serverFetch<Service[]>('/public/services', defaultOptions);\n}\n\nexport async function getService(slug: string): Promise<Service | null> {\n return serverFetch<Service>(`/public/services/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getLocations() {\n return serverFetch('/public/locations', defaultOptions);\n}\n\nexport async function getLocation(slug: string) {\n return serverFetch(`/public/locations/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getReviews() {\n return serverFetch('/public/reviews', defaultOptions);\n}\n\nexport async function getFAQs() {\n return serverFetch('/public/faq_questions', defaultOptions);\n}\n\nexport async function getBlogPosts() {\n return serverFetch('/public/blog_posts', defaultOptions);\n}\n\nexport async function getBlogPost(slug: string) {\n return serverFetch(`/public/blog_posts/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getTeamMembers() {\n return serverFetch('/public/team_members', defaultOptions);\n}\n\nexport async function getWebsitePhotos(): Promise<WebsitePhotos | null> {\n return serverFetch<WebsitePhotos>('/public/website_photos', defaultOptions);\n}\n\nexport async function getJobPostings() {\n return serverFetch('/public/job_postings', defaultOptions);\n}\n\nexport async function getJobPosting(slug: string) {\n return serverFetch(`/public/job_postings/by_slug/${slug}`, defaultOptions);\n}\n\nexport async function getSocialPosts() {\n return serverFetch('/public/social_posts', defaultOptions);\n}\n\n/** Packages (bundles of service items). */\nexport async function getPackages(): Promise<Package[] | null> {\n return serverFetch<Package[]>('/public/packages', defaultOptions);\n}\n\nexport async function getPackage(slug: string): Promise<Package | null> {\n return serverFetch<Package>(`/public/packages/by_slug/${encodeURIComponent(slug)}`, defaultOptions);\n}\n\n// Alias for testimonials (API uses \"reviews\")\nexport async function getTestimonials() {\n return getReviews();\n}\n\n/** Form definition for dynamic form rendering, fetched by form_type. */\nexport async function getForm(formType: string) {\n type FormDefinition = import('../types/api/form').FormDefinition;\n return serverFetch<FormDefinition>(`/public/forms/${encodeURIComponent(formType)}`, defaultOptions);\n}\n\n/** Form definition for dynamic form rendering, fetched by numeric ID. */\nexport async function getFormById(id: number | string) {\n type FormDefinition = import('../types/api/form').FormDefinition;\n return serverFetch<FormDefinition>(`/public/form_by_id/${encodeURIComponent(id)}`, defaultOptions);\n}\n\n"],"mappings":"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","names":[]}
@@ -0,0 +1,121 @@
1
+ import { P as PhotoAttachment, a as Photo } from './photos-CmBdWiuZ.js';
2
+
3
+ /** Nested under `service_items[].offers` and `packages[].offers` in public API. */
4
+ interface OfferPublic {
5
+ id: number;
6
+ name: string;
7
+ description: string | null;
8
+ value_terms: string | null;
9
+ active?: boolean;
10
+ expires_at?: string | null;
11
+ expired?: boolean;
12
+ photo_attachments?: PhotoAttachment[];
13
+ }
14
+
15
+ interface Service {
16
+ id: number;
17
+ name: string;
18
+ slug: string;
19
+ description_markdown: string;
20
+ summary?: string;
21
+ pricing_info?: string;
22
+ features_markdown?: string;
23
+ featured: boolean;
24
+ sort_order: number;
25
+ photo_attachments?: PhotoAttachment[];
26
+ service_items?: ServiceItem[];
27
+ created_at: string;
28
+ updated_at: string;
29
+ }
30
+ interface ServiceItem {
31
+ id: number;
32
+ name: string;
33
+ slug: string;
34
+ summary?: string | null;
35
+ description_markdown?: string | null;
36
+ pricing_info?: string | null;
37
+ price_cents?: number | null;
38
+ duration_minutes?: number | null;
39
+ sort_order: number;
40
+ service_id?: number;
41
+ photo_attachments?: PhotoAttachment[];
42
+ offers?: OfferPublic[];
43
+ }
44
+ interface ServiceParams {
45
+ featured?: boolean;
46
+ q?: string;
47
+ page?: number;
48
+ per_page?: number;
49
+ }
50
+ type ServiceResponse = Service[];
51
+
52
+ interface CompanyInformation {
53
+ id: number;
54
+ company_name: string;
55
+ tagline: string;
56
+ mission_statement_markdown?: string;
57
+ about_text_markdown?: string;
58
+ description_markdown?: string;
59
+ values_markdown?: string;
60
+ stats_markdown?: string;
61
+ founded_year?: number;
62
+ logo_photo?: Photo;
63
+ favicon_url?: string;
64
+ facebook_url?: string;
65
+ instagram_url?: string;
66
+ tiktok_url?: string;
67
+ linkedin_url?: string;
68
+ twitter_url?: string;
69
+ youtube_url?: string;
70
+ pinterest_url?: string;
71
+ google_my_business_url?: string;
72
+ yelp_url?: string;
73
+ tripadvisor_url?: string;
74
+ google_reviews_url?: string;
75
+ primary_phone?: string;
76
+ primary_email?: string;
77
+ primary_address_line_1?: string;
78
+ primary_address_line_2?: string;
79
+ primary_city?: string;
80
+ primary_state?: string;
81
+ primary_zip_code?: string;
82
+ primary_country?: string;
83
+ support_email?: string;
84
+ sales_email?: string;
85
+ business_hours?: string;
86
+ external_management_url?: string;
87
+ /** Member portal URL for this account. When set, used as the primary CTA instead of external_management_url. */
88
+ portal_url?: string | null;
89
+ terms_of_service_markdown?: string;
90
+ privacy_policy_markdown?: string;
91
+ created_at: string;
92
+ updated_at: string;
93
+ photo_attachments?: PhotoAttachment[];
94
+ account_status?: string;
95
+ chat_enabled?: boolean;
96
+ }
97
+ type CompanyInformationResponse = CompanyInformation | null;
98
+
99
+ interface PackageItem {
100
+ quantity: number;
101
+ service_item?: {
102
+ id: number;
103
+ name: string;
104
+ slug: string;
105
+ summary?: string | null;
106
+ };
107
+ }
108
+ interface Package {
109
+ id: number;
110
+ name: string;
111
+ slug: string;
112
+ summary?: string | null;
113
+ description_markdown?: string | null;
114
+ pricing_info?: string | null;
115
+ price_cents?: number | null;
116
+ photo_attachments?: PhotoAttachment[];
117
+ package_items?: PackageItem[];
118
+ offers?: OfferPublic[];
119
+ }
120
+
121
+ export type { CompanyInformation as C, OfferPublic as O, Package as P, Service as S, CompanyInformationResponse as a, PackageItem as b, ServiceItem as c, ServiceParams as d, ServiceResponse as e };
@@ -1,14 +1,29 @@
1
- export { Theme } from '../themes/index.js';
2
- export { N as NavItem, S as SiteConfig } from '../config-C_XBZixg.js';
1
+ import { Theme } from '../themes/index.js';
3
2
  export { B as BlogPost, a as BlogPostAuthor, b as BlogPostParams, c as BlogPostResponse, d as BlogPostTag } from '../blog-post-vWzW8yFb.js';
4
- export { C as CompanyInformation, a as CompanyInformationResponse } from '../company-information-C1pP-SvU.js';
5
- export { a as Consumer, c as ConsumerContact, b as ContactSummary, C as ConversationSummary, M as Message } from '../consumer-BWjQawiO.js';
3
+ export { C as CompanyInformation, a as CompanyInformationResponse, O as OfferPublic, P as Package, b as PackageItem, S as Service, c as ServiceItem, d as ServiceParams, e as ServiceResponse } from '../package-DeHKpQp7.js';
6
4
  import { P as PhotoAttachment } from '../photos-CmBdWiuZ.js';
7
5
  export { a as Photo } from '../photos-CmBdWiuZ.js';
8
6
  export { F as FormDefinition, a as FormFieldDefinition, b as FormFieldItem, c as FormFieldOption, d as FormType } from '../form-C94A_PX_.js';
9
- export { O as OfferPublic, P as Package, a as PackageItem, S as Service, b as ServiceItem, c as ServiceParams, d as ServiceResponse } from '../package-IU_GpDA0.js';
10
7
  export { a as WebsitePhoto, W as WebsitePhotos, b as WebsitePhotosResponse } from '../website-photos-Cl1YqAno.js';
11
8
 
9
+ interface NavItem {
10
+ label: string;
11
+ href: string;
12
+ subtitle?: string;
13
+ children?: NavItem[];
14
+ }
15
+ interface SiteConfig {
16
+ site: {
17
+ title: string;
18
+ description: string;
19
+ theme: Theme;
20
+ };
21
+ navigation: {
22
+ header: NavItem[];
23
+ footer: NavItem[][];
24
+ };
25
+ }
26
+
12
27
  interface Testimonial {
13
28
  id: number;
14
29
  reviewer_name: string;
@@ -188,6 +203,53 @@ interface JobPostingParams {
188
203
  }
189
204
  type JobPostingResponse = JobPosting[];
190
205
 
206
+ /** Consumer and messaging types (aligned with Rails ConsumerSerializer and conversation endpoints). */
207
+ interface Consumer {
208
+ id: number;
209
+ email: string | null;
210
+ phone: string | null;
211
+ primary_identifier: string | null;
212
+ contacts?: ConsumerContact[];
213
+ }
214
+ interface ConsumerContact {
215
+ id: number;
216
+ display_name: string;
217
+ account?: {
218
+ id: number;
219
+ name: string;
220
+ slug?: string;
221
+ };
222
+ }
223
+ interface ConversationSummary {
224
+ contact_id: number;
225
+ business?: {
226
+ id: number;
227
+ name: string;
228
+ company_name?: string;
229
+ };
230
+ last_message_at: string | null;
231
+ last_message_preview?: string | null;
232
+ message_count: number;
233
+ }
234
+ interface Message {
235
+ id: number;
236
+ body: string | null;
237
+ /** "outbound" = sent by the business; "inbound" = sent by the contact/member. */
238
+ direction: 'inbound' | 'outbound';
239
+ sender_type: 'contact' | 'agent' | 'human';
240
+ sender_display_name?: string;
241
+ created_at: string;
242
+ }
243
+ interface ContactSummary {
244
+ id: number;
245
+ display_name: string;
246
+ business?: {
247
+ id: number;
248
+ name: string;
249
+ company_name?: string;
250
+ };
251
+ }
252
+
191
253
  interface ContactInfo {
192
254
  id?: number;
193
255
  about_text_markdown?: string;
@@ -248,4 +310,4 @@ interface ContactFormResponse {
248
310
  data: ContactFormSubmission;
249
311
  }
250
312
 
251
- export { type ContactFormData, type ContactFormResponse, type ContactFormSubmission, type ContactInfo, type ContactResponse, type FaqCategory, type FaqCategoryResponse, type FaqParams, type FaqQuestion, type FaqResponse, type JobPosting, type JobPostingParams, type JobPostingResponse, type Location, type LocationParams, type LocationResponse, PhotoAttachment, type SocialPost, type SocialPostParams, type SocialPostResponse, type TeamMember, type TeamMemberParams, type TeamMemberResponse, type Testimonial, type TestimonialParams, type TestimonialResponse };
313
+ export { type Consumer, type ConsumerContact, type ContactFormData, type ContactFormResponse, type ContactFormSubmission, type ContactInfo, type ContactResponse, type ContactSummary, type ConversationSummary, type FaqCategory, type FaqCategoryResponse, type FaqParams, type FaqQuestion, type FaqResponse, type JobPosting, type JobPostingParams, type JobPostingResponse, type Location, type LocationParams, type LocationResponse, type Message, type NavItem, PhotoAttachment, type SiteConfig, type SocialPost, type SocialPostParams, type SocialPostResponse, type TeamMember, type TeamMemberParams, type TeamMemberResponse, type Testimonial, type TestimonialParams, type TestimonialResponse, Theme };
package/package.json CHANGED
@@ -1,37 +1,37 @@
1
1
  {
2
2
  "name": "keystone-design-bootstrap",
3
- "version": "1.0.87",
3
+ "version": "1.0.88",
4
4
  "description": "Keystone Design Bootstrap - Sections, Elements, and Theme System for customer websites",
5
5
  "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
6
+ "main": "./src/index.ts",
7
+ "types": "./src/index.ts",
8
8
  "exports": {
9
- ".": "./dist/index.js",
10
- "./sections": "./dist/design_system/sections/index.js",
11
- "./elements": "./dist/design_system/elements/index.js",
12
- "./logo": "./dist/design_system/logo/keystone-logo.js",
13
- "./hooks": "./dist/lib/hooks/index.js",
14
- "./contexts": "./dist/contexts/index.js",
15
- "./tracking": "./dist/tracking/index.js",
16
- "./components/DynamicFormFields": "./dist/design_system/components/DynamicFormFields.js",
17
- "./lib/server-api": "./dist/lib/server-api.js",
18
- "./lib/cta-urls": "./dist/lib/cta-urls.js",
19
- "./lib/component-registry": "./dist/lib/component-registry.js",
20
- "./next/routes/chat": "./dist/next/routes/chat.js",
21
- "./next/routes/form": "./dist/next/routes/form.js",
22
- "./next/contexts/form-definitions": "./dist/next/contexts/form-definitions.js",
23
- "./next/layouts/root-layout": "./dist/next/layouts/root-layout.js",
24
- "./next/providers/ssr-provider": "./dist/next/providers/ssr-provider.js",
25
- "./next/gallery/design-gallery": "./dist/next/gallery/design-gallery.js",
26
- "./next/legal/privacy-policy": "./dist/next/legal/privacy-policy.js",
27
- "./next/legal/terms-of-service": "./dist/next/legal/terms-of-service.js",
9
+ ".": "./src/index.ts",
10
+ "./sections": "./src/design_system/sections/index.tsx",
11
+ "./elements": "./src/design_system/elements/index.tsx",
12
+ "./logo": "./src/design_system/logo/keystone-logo.tsx",
13
+ "./hooks": "./src/lib/hooks/index.ts",
14
+ "./contexts": "./src/contexts/index.ts",
15
+ "./tracking": "./src/tracking/index.ts",
16
+ "./components/DynamicFormFields": "./src/design_system/components/DynamicFormFields.tsx",
17
+ "./lib/server-api": "./src/lib/server-api.ts",
18
+ "./lib/cta-urls": "./src/lib/cta-urls.ts",
19
+ "./lib/component-registry": "./src/lib/component-registry.ts",
20
+ "./next/routes/chat": "./src/next/routes/chat.ts",
21
+ "./next/routes/form": "./src/next/routes/form.ts",
22
+ "./next/contexts/form-definitions": "./src/next/contexts/form-definitions.tsx",
23
+ "./next/layouts/root-layout": "./src/next/layouts/root-layout.tsx",
24
+ "./next/providers/ssr-provider": "./src/next/providers/ssr-provider.tsx",
25
+ "./next/gallery/design-gallery": "./src/next/gallery/design-gallery.tsx",
26
+ "./next/legal/privacy-policy": "./src/next/legal/privacy-policy.tsx",
27
+ "./next/legal/terms-of-service": "./src/next/legal/terms-of-service.tsx",
28
28
  "./styles/*": "./src/styles/*",
29
- "./types": "./dist/types/index.js",
30
- "./themes": "./dist/themes/index.js",
31
- "./utils/*": "./dist/utils/*",
32
- "./portal": "./dist/design_system/portal/index.js",
33
- "./lib/consumer-session": "./dist/lib/consumer-session.js",
34
- "./next/routes/consumer-auth": "./dist/next/routes/consumer-auth.js"
29
+ "./types": "./src/types/index.ts",
30
+ "./themes": "./src/themes/index.ts",
31
+ "./utils/*": "./src/utils/*",
32
+ "./portal": "./src/design_system/portal/index.ts",
33
+ "./lib/consumer-session": "./src/lib/consumer-session.ts",
34
+ "./next/routes/consumer-auth": "./src/next/routes/consumer-auth.ts"
35
35
  },
36
36
  "repository": {
37
37
  "type": "git",
@@ -72,13 +72,12 @@ export interface PortalPageProps {
72
72
  /** HEAD-request the booking URL and inspect framing headers to decide whether to embed in an iframe. */
73
73
  async function checkIframeAllowed(url: string): Promise<boolean> {
74
74
  try {
75
- const fetchOptions: RequestInit & { next?: { revalidate?: number } } = {
75
+ const res = await fetch(url, {
76
76
  method: 'HEAD',
77
77
  redirect: 'follow',
78
78
  // Cache for 1 hour — booking platforms rarely change their embedding policy.
79
79
  next: { revalidate: 3600 },
80
- };
81
- const res = await fetch(url, fetchOptions);
80
+ });
82
81
 
83
82
  const xfo = res.headers.get('x-frame-options')?.toUpperCase();
84
83
  if (xfo === 'DENY' || xfo === 'SAMEORIGIN') return false;
@@ -165,8 +165,7 @@ export async function getJobPosting(slug: string) {
165
165
  }
166
166
 
167
167
  export async function getSocialPosts() {
168
- // Social payloads can exceed Next's data-cache item size; avoid noisy build warnings.
169
- return serverFetch('/public/social_posts', { cache: 'no-store' });
168
+ return serverFetch('/public/social_posts', defaultOptions);
170
169
  }
171
170
 
172
171
  /** Packages (bundles of service items). */
@@ -1,50 +0,0 @@
1
- import { a as Photo, P as PhotoAttachment } from './photos-CmBdWiuZ.js';
2
-
3
- interface CompanyInformation {
4
- id: number;
5
- company_name: string;
6
- tagline: string;
7
- mission_statement_markdown?: string;
8
- about_text_markdown?: string;
9
- description_markdown?: string;
10
- values_markdown?: string;
11
- stats_markdown?: string;
12
- founded_year?: number;
13
- logo_photo?: Photo;
14
- favicon_url?: string;
15
- facebook_url?: string;
16
- instagram_url?: string;
17
- tiktok_url?: string;
18
- linkedin_url?: string;
19
- twitter_url?: string;
20
- youtube_url?: string;
21
- pinterest_url?: string;
22
- google_my_business_url?: string;
23
- yelp_url?: string;
24
- tripadvisor_url?: string;
25
- google_reviews_url?: string;
26
- primary_phone?: string;
27
- primary_email?: string;
28
- primary_address_line_1?: string;
29
- primary_address_line_2?: string;
30
- primary_city?: string;
31
- primary_state?: string;
32
- primary_zip_code?: string;
33
- primary_country?: string;
34
- support_email?: string;
35
- sales_email?: string;
36
- business_hours?: string;
37
- external_management_url?: string;
38
- /** Member portal URL for this account. When set, used as the primary CTA instead of external_management_url. */
39
- portal_url?: string | null;
40
- terms_of_service_markdown?: string;
41
- privacy_policy_markdown?: string;
42
- created_at: string;
43
- updated_at: string;
44
- photo_attachments?: PhotoAttachment[];
45
- account_status?: string;
46
- chat_enabled?: boolean;
47
- }
48
- type CompanyInformationResponse = CompanyInformation | null;
49
-
50
- export type { CompanyInformation as C, CompanyInformationResponse as a };
@@ -1,21 +0,0 @@
1
- import { Theme } from './themes/index.js';
2
-
3
- interface NavItem {
4
- label: string;
5
- href: string;
6
- subtitle?: string;
7
- children?: NavItem[];
8
- }
9
- interface SiteConfig {
10
- site: {
11
- title: string;
12
- description: string;
13
- theme: Theme;
14
- };
15
- navigation: {
16
- header: NavItem[];
17
- footer: NavItem[][];
18
- };
19
- }
20
-
21
- export type { NavItem as N, SiteConfig as S };
@@ -1,48 +0,0 @@
1
- /** Consumer and messaging types (aligned with Rails ConsumerSerializer and conversation endpoints). */
2
- interface Consumer {
3
- id: number;
4
- email: string | null;
5
- phone: string | null;
6
- primary_identifier: string | null;
7
- contacts?: ConsumerContact[];
8
- }
9
- interface ConsumerContact {
10
- id: number;
11
- display_name: string;
12
- account?: {
13
- id: number;
14
- name: string;
15
- slug?: string;
16
- };
17
- }
18
- interface ConversationSummary {
19
- contact_id: number;
20
- business?: {
21
- id: number;
22
- name: string;
23
- company_name?: string;
24
- };
25
- last_message_at: string | null;
26
- last_message_preview?: string | null;
27
- message_count: number;
28
- }
29
- interface Message {
30
- id: number;
31
- body: string | null;
32
- /** "outbound" = sent by the business; "inbound" = sent by the contact/member. */
33
- direction: 'inbound' | 'outbound';
34
- sender_type: 'contact' | 'agent' | 'human';
35
- sender_display_name?: string;
36
- created_at: string;
37
- }
38
- interface ContactSummary {
39
- id: number;
40
- display_name: string;
41
- business?: {
42
- id: number;
43
- name: string;
44
- company_name?: string;
45
- };
46
- }
47
-
48
- export type { ConversationSummary as C, Message as M, Consumer as a, ContactSummary as b, ConsumerContact as c };
@@ -1,52 +0,0 @@
1
- import * as React from 'react';
2
- import React__default from 'react';
3
-
4
- declare const ALL_TABS: readonly ["services", "packages", "specials", "messages", "book"];
5
- type Tab = (typeof ALL_TABS)[number];
6
- interface PortalPageProps {
7
- searchParams?: Promise<Record<string, string>> | Record<string, string>;
8
- portalHref?: string;
9
- bookingHref?: string | null;
10
- bookingLabel?: string;
11
- /**
12
- * Controls which tabs are rendered in the portal header.
13
- * Default: ['book', 'services', 'packages', 'specials', 'messages']
14
- */
15
- enabledTabs?: Tab[];
16
- /**
17
- * Optional per-tab label overrides, e.g. { messages: 'Chat with Us' }.
18
- */
19
- tabLabels?: Partial<Record<Tab, string>>;
20
- /**
21
- * When true, always opens booking in a new tab even if the URL supports iframes.
22
- * Useful when the booking page's iframe experience is broken or undesirable.
23
- */
24
- forceExternalBooking?: boolean;
25
- /**
26
- * Path to the site's contact page, shown when no booking URL is configured.
27
- * Defaults to "/contact".
28
- */
29
- contactHref?: string;
30
- }
31
- declare function PortalPage({ searchParams, portalHref, bookingHref, bookingLabel, enabledTabs, tabLabels, forceExternalBooking, contactHref, }: PortalPageProps): Promise<React__default.JSX.Element>;
32
-
33
- interface LoginFormProps {
34
- onSuccess?: () => void;
35
- onClose?: () => void;
36
- }
37
- declare function LoginForm({ onSuccess, onClose }: LoginFormProps): React__default.JSX.Element;
38
-
39
- declare function LogoutButton(): React.JSX.Element;
40
-
41
- /**
42
- * Renders a single login modal for the entire portal.
43
- * Any server-rendered element with `data-open-login-modal` will open it on click.
44
- *
45
- * After successful auth, the modal switches to a loading state and stays open
46
- * until the router transition (router.refresh / router.push) has fully completed
47
- * and the server component has re-rendered with the new session. This prevents
48
- * the brief flash of logged-out content that would otherwise appear.
49
- */
50
- declare function LoginModalController(): React__default.JSX.Element;
51
-
52
- export { LoginForm, LoginModalController, LogoutButton, PortalPage, type PortalPageProps };