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.
- package/dist/design_system/sections/index.d.ts +1 -2
- package/dist/index.d.ts +24 -5
- package/dist/lib/server-api.d.ts +1 -2
- package/dist/lib/server-api.js +1 -1
- package/dist/lib/server-api.js.map +1 -1
- package/dist/package-DeHKpQp7.d.ts +121 -0
- package/dist/types/index.d.ts +68 -6
- package/package.json +28 -28
- package/src/design_system/portal/PortalPage.tsx +2 -3
- package/src/lib/server-api.ts +1 -2
- package/dist/company-information-C1pP-SvU.d.ts +0 -50
- package/dist/config-C_XBZixg.d.ts +0 -21
- package/dist/consumer-BWjQawiO.d.ts +0 -48
- package/dist/design_system/portal/index.d.ts +0 -52
- package/dist/design_system/portal/index.js +0 -3113
- package/dist/design_system/portal/index.js.map +0 -1
- package/dist/lib/consumer-session.d.ts +0 -16
- package/dist/lib/consumer-session.js +0 -85
- package/dist/lib/consumer-session.js.map +0 -1
- package/dist/lib/cta-urls.d.ts +0 -34
- package/dist/lib/cta-urls.js +0 -33
- package/dist/lib/cta-urls.js.map +0 -1
- package/dist/next/contexts/form-definitions.d.ts +0 -17
- package/dist/next/contexts/form-definitions.js +0 -21
- package/dist/next/contexts/form-definitions.js.map +0 -1
- package/dist/next/gallery/design-gallery.d.ts +0 -103
- package/dist/next/gallery/design-gallery.js +0 -19301
- package/dist/next/gallery/design-gallery.js.map +0 -1
- package/dist/next/layouts/root-layout.d.ts +0 -55
- package/dist/next/layouts/root-layout.js +0 -19713
- package/dist/next/layouts/root-layout.js.map +0 -1
- package/dist/next/legal/privacy-policy.d.ts +0 -7
- package/dist/next/legal/privacy-policy.js +0 -18949
- package/dist/next/legal/privacy-policy.js.map +0 -1
- package/dist/next/legal/terms-of-service.d.ts +0 -7
- package/dist/next/legal/terms-of-service.js +0 -18949
- package/dist/next/legal/terms-of-service.js.map +0 -1
- package/dist/next/providers/ssr-provider.d.ts +0 -12
- package/dist/next/providers/ssr-provider.js +0 -12
- package/dist/next/providers/ssr-provider.js.map +0 -1
- package/dist/next/routes/chat.d.ts +0 -26
- package/dist/next/routes/chat.js +0 -160
- package/dist/next/routes/chat.js.map +0 -1
- package/dist/next/routes/consumer-auth.d.ts +0 -33
- package/dist/next/routes/consumer-auth.js +0 -254
- package/dist/next/routes/consumer-auth.js.map +0 -1
- package/dist/next/routes/form.d.ts +0 -37
- package/dist/next/routes/form.js +0 -97
- package/dist/next/routes/form.js.map +0 -1
- package/dist/package-IU_GpDA0.d.ts +0 -74
- package/src/types/rails-actioncable.d.ts +0 -16
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as Service, P as Package } from '../../package-
|
|
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
|
-
|
|
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 };
|
package/dist/lib/server-api.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { F as FormDefinition } from '../form-C94A_PX_.js';
|
|
2
|
-
import { C as CompanyInformation } from '../
|
|
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
|
|
package/dist/lib/server-api.js
CHANGED
|
@@ -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",
|
|
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":";AAUA,IAAM,UAAU,QAAQ,IAAI,WAAW;AACvC,IAAM,UAAU,QAAQ,IAAI,WAAW;AAOvC,eAAe,YAAe,UAAkB,UAAwB,CAAC,GAAsB;AAlB/F;AAmBE,QAAM,MAAM,GAAG,OAAO,GAAG,QAAQ;AAEjC,MAAI;AACF,UAAM,eAAiE;AAAA,MACrE,SAAS;AAAA,QACP,aAAa;AAAA,QACb,gBAAgB;AAAA,MAClB;AAAA,MACA,OAAO,QAAQ;AAAA,IACjB;AAEA,QAAI,QAAQ,YAAY;AACtB,mBAAa,OAAO,EAAE,YAAY,QAAQ,WAAW;AAAA,IACvD;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK,YAAY;AAE9C,QAAI,CAAC,SAAS,IAAI;AAChB,cAAQ,MAAM,sBAAsB,SAAS,MAAM,QAAQ,QAAQ,EAAE;AACrE,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AAGjC,YAAO,UAAK,SAAL,YAAa;AAAA,EACtB,SAAS,OAAO;AACd,YAAQ,MAAM,gCAAgC,QAAQ,KAAK,KAAK;AAChE,WAAO;AAAA,EACT;AACF;AAKO,IAAM,YAAY;AAAA,EACvB,KAAK,CAAc,UAAkB,YAA8C;AACjF,WAAO,YAAe,UAAU,WAAW,EAAE,YAAY,GAAG,CAAC;AAAA,EAC/D;AACF;AAGA,IAAM,iBAA+B,EAAE,YAAY,GAAG;AAEtD,eAAsB,wBAA4D;AAChF,SAAO,YAAgC,+BAA+B,cAAc;AACtF;AAGA,eAAsB,eAA2D;AAC/E,QAAM,OAAO,MAAM,YAAwC,sBAAsB,cAAc;AAC/F,SAAO,sBAAQ;AACjB;AAGO,SAAS,eAAe,WAAyE;AACtG,QAAM,KAAK,aAAa,OAAO,cAAc,YAAY,mBAAmB,aAAa,UAAU;AACnG,QAAM,MAAM,MAAM,QAAQ,OAAO,KAAK,OAAO,EAAE,EAAE,KAAK,IAAI;AAC1D,SAAO,QAAQ,MAAM,QAAQ,UAAU,QAAQ,KAAK,GAAG,IAAI,MAAM;AACnE;AAgBA,eAAsB,qBAAsD;AAC1E,QAAM,OAAO,MAAM,YAA6B,4BAA4B,cAAc;AAC1F,SAAO,sBAAQ;AACjB;AAGO,SAAS,iBAAiB,iBAAoE;AACnG,QAAM,MAAM,mDAAiB;AAC7B,QAAM,MAAM,OAAO,QAAQ,QAAQ,KAAK,OAAO,GAAG,EAAE,KAAK,IAAI;AAC7D,SAAO,QAAQ,MAAM,QAAQ,SAAS,MAAM;AAC9C;AAGO,SAAS,wBAAwB,iBAAoE;AAC1G,QAAM,QAAQ,mDAAiB;AAC/B,QAAM,MAAM,SAAS,QAAQ,UAAU,KAAK,OAAO,KAAK,EAAE,KAAK,IAAI;AACnE,SAAO,QAAQ,MAAM,QAAQ,UAAU,mBAAmB,KAAK,GAAG,IAAI,MAAM;AAC9E;AAGO,SAAS,uBAAuB,iBAA6D;AAlHpG;AAmHE,WAAO,wDAAiB,gBAAjB,mBAA8B,WAAU;AACjD;AAEA,eAAsB,cAAyC;AAC7D,SAAO,YAAuB,oBAAoB,cAAc;AAClE;AAEA,eAAsB,WAAW,MAAuC;AACtE,SAAO,YAAqB,4BAA4B,IAAI,IAAI,cAAc;AAChF;AAEA,eAAsB,eAAe;AACnC,SAAO,YAAY,qBAAqB,cAAc;AACxD;AAEA,eAAsB,YAAY,MAAc;AAC9C,SAAO,YAAY,6BAA6B,IAAI,IAAI,cAAc;AACxE;AAEA,eAAsB,aAAa;AACjC,SAAO,YAAY,mBAAmB,cAAc;AACtD;AAEA,eAAsB,UAAU;AAC9B,SAAO,YAAY,yBAAyB,cAAc;AAC5D;AAEA,eAAsB,eAAe;AACnC,SAAO,YAAY,sBAAsB,cAAc;AACzD;AAEA,eAAsB,YAAY,MAAc;AAC9C,SAAO,YAAY,8BAA8B,IAAI,IAAI,cAAc;AACzE;AAEA,eAAsB,iBAAiB;AACrC,SAAO,YAAY,wBAAwB,cAAc;AAC3D;AAEA,eAAsB,mBAAkD;AACtE,SAAO,YAA2B,0BAA0B,cAAc;AAC5E;AAEA,eAAsB,iBAAiB;AACrC,SAAO,YAAY,wBAAwB,cAAc;AAC3D;AAEA,eAAsB,cAAc,MAAc;AAChD,SAAO,YAAY,gCAAgC,IAAI,IAAI,cAAc;AAC3E;AAEA,eAAsB,iBAAiB;AAErC,SAAO,YAAY,wBAAwB,EAAE,OAAO,WAAW,CAAC;AAClE;AAGA,eAAsB,cAAyC;AAC7D,SAAO,YAAuB,oBAAoB,cAAc;AAClE;AAEA,eAAsB,WAAW,MAAuC;AACtE,SAAO,YAAqB,4BAA4B,mBAAmB,IAAI,CAAC,IAAI,cAAc;AACpG;AAGA,eAAsB,kBAAkB;AACtC,SAAO,WAAW;AACpB;AAGA,eAAsB,QAAQ,UAAkB;AAE9C,SAAO,YAA4B,iBAAiB,mBAAmB,QAAQ,CAAC,IAAI,cAAc;AACpG;AAGA,eAAsB,YAAY,IAAqB;AAErD,SAAO,YAA4B,sBAAsB,mBAAmB,EAAE,CAAC,IAAI,cAAc;AACnG;","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 };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
|
|
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 '../
|
|
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.
|
|
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": "./
|
|
7
|
-
"types": "./
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
8
|
"exports": {
|
|
9
|
-
".": "./
|
|
10
|
-
"./sections": "./
|
|
11
|
-
"./elements": "./
|
|
12
|
-
"./logo": "./
|
|
13
|
-
"./hooks": "./
|
|
14
|
-
"./contexts": "./
|
|
15
|
-
"./tracking": "./
|
|
16
|
-
"./components/DynamicFormFields": "./
|
|
17
|
-
"./lib/server-api": "./
|
|
18
|
-
"./lib/cta-urls": "./
|
|
19
|
-
"./lib/component-registry": "./
|
|
20
|
-
"./next/routes/chat": "./
|
|
21
|
-
"./next/routes/form": "./
|
|
22
|
-
"./next/contexts/form-definitions": "./
|
|
23
|
-
"./next/layouts/root-layout": "./
|
|
24
|
-
"./next/providers/ssr-provider": "./
|
|
25
|
-
"./next/gallery/design-gallery": "./
|
|
26
|
-
"./next/legal/privacy-policy": "./
|
|
27
|
-
"./next/legal/terms-of-service": "./
|
|
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": "./
|
|
30
|
-
"./themes": "./
|
|
31
|
-
"./utils/*": "./
|
|
32
|
-
"./portal": "./
|
|
33
|
-
"./lib/consumer-session": "./
|
|
34
|
-
"./next/routes/consumer-auth": "./
|
|
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
|
|
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;
|
package/src/lib/server-api.ts
CHANGED
|
@@ -165,8 +165,7 @@ export async function getJobPosting(slug: string) {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
export async function getSocialPosts() {
|
|
168
|
-
|
|
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 };
|