keystone-design-bootstrap 1.0.66 → 1.0.69

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 (29) hide show
  1. package/README.md +74 -132
  2. package/dist/design_system/sections/index.js +42 -11
  3. package/dist/design_system/sections/index.js.map +1 -1
  4. package/dist/index.js +42 -11
  5. package/dist/index.js.map +1 -1
  6. package/dist/tracking/index.d.ts +6 -1
  7. package/dist/tracking/index.js +5 -3
  8. package/dist/tracking/index.js.map +1 -1
  9. package/package.json +2 -1
  10. package/src/design_system/components/ChatWidget.tsx +6 -7
  11. package/src/design_system/portal/LoginForm.tsx +25 -9
  12. package/src/design_system/portal/LoginModalController.tsx +36 -12
  13. package/src/design_system/portal/PortalPage.tsx +5 -5
  14. package/src/design_system/portal/PortalTabTracker.tsx +10 -2
  15. package/src/design_system/sections/contact-section-form.aman.tsx +6 -1
  16. package/src/design_system/sections/contact-section-form.balance.tsx +6 -1
  17. package/src/design_system/sections/contact-section-form.barelux.tsx +6 -1
  18. package/src/design_system/sections/contact-section-form.tsx +6 -1
  19. package/src/design_system/sections/email-signup-section.tsx +6 -1
  20. package/src/design_system/sections/job-application-form.aman.tsx +6 -1
  21. package/src/design_system/sections/job-application-form.barelux.tsx +6 -1
  22. package/src/design_system/sections/job-application-form.tsx +6 -1
  23. package/src/lib/cta-urls.ts +13 -2
  24. package/src/lib/server-api.ts +18 -0
  25. package/src/next/layouts/root-layout.tsx +66 -33
  26. package/src/tracking/KeystoneAnalyticsTracker.tsx +41 -0
  27. package/src/tracking/PostHogProvider.tsx +128 -0
  28. package/src/tracking/captureEvent.ts +140 -0
  29. package/src/tracking/index.ts +5 -0
package/README.md CHANGED
@@ -1,175 +1,117 @@
1
1
  # Keystone Design Bootstrap
2
2
 
3
- A comprehensive design system for Keystone customer websites. Provides themed sections, elements, and utilities for building consistent, server-rendered Next.js sites.
3
+ The shared design system and runtime package powering all Keystone customer websites. Provides themed sections, UI elements, the member portal, server-side API helpers, form handling, Meta Pixel tracking, and the Next.js app shell.
4
4
 
5
- ## Quick Start
5
+ ---
6
6
 
7
- 1. **Set your theme** in `config/index.ts`:
8
- ```typescript
9
- export const config = {
10
- site: { theme: "barelux" } // or "aman", "classic"
11
- }
12
- ```
7
+ ## Documentation
13
8
 
14
- 2. **Import theme CSS** in your `app/globals.css`:
15
- ```css
16
- @import "keystone-design-bootstrap/styles/fonts.css";
17
- @import "keystone-design-bootstrap/styles/theme.css";
18
- @import "keystone-design-bootstrap/styles/typography.css";
19
- @import "keystone-design-bootstrap/styles/style-overrides.barelux.css"; /* Change to match your theme */
20
- ```
9
+ | Doc | Description |
10
+ |---|---|
11
+ | [`docs/architecture.md`](./docs/architecture.md) | Package structure, rendering model, theme system, publishing workflow |
12
+ | [`docs/server-api.md`](./docs/server-api.md) | All data-fetching functions, caching strategy, environment variables |
13
+ | [`docs/navigation-and-layout.md`](./docs/navigation-and-layout.md) | `KeystoneRootLayout`, `SiteConfig`, CTA URL resolution, dynamic nav, mobile sticky footer |
14
+ | [`docs/member-portal.md`](./docs/member-portal.md) | Member portal setup, tabs, auth flow, iframe booking, messaging |
15
+ | [`docs/forms.md`](./docs/forms.md) | Dynamic forms, `ContactSection`, form route, custom form pattern |
16
+ | [`docs/meta-tracking.md`](./docs/meta-tracking.md) | Meta Pixel initialization, automatic events, custom form tracking |
17
+ | [`docs/site-customization.md`](./docs/site-customization.md) | Per-site config, style overrides, component customization hierarchy |
18
+ | [`docs/theme-system.md`](./docs/theme-system.md) | Creating and registering themes, CSS tokens, component variants |
21
19
 
22
- 3. **Run** `npm run dev` and you're ready!
20
+ ---
23
21
 
24
- ## Installation
22
+ ## Quick start (new customer site)
23
+
24
+ ### 1. Environment variables
25
25
 
26
26
  ```bash
27
- npm install @keystone-pzjr/design-bootstrap
27
+ # .env.local
28
+ API_URL=http://localhost:3000/api/v1
29
+ API_KEY=your-api-key-here
28
30
  ```
29
31
 
30
- ## Using the Design System
31
-
32
- ### Elements
33
- Reusable UI components:
32
+ ### 2. Config
34
33
 
35
34
  ```typescript
36
- import { Button, Input, Carousel } from '@keystone-pzjr/design-bootstrap/elements'
35
+ // config/index.ts
36
+ import type { SiteConfig } from 'keystone-design-bootstrap/types';
37
37
 
38
- <Button color="primary" size="md">Click Me</Button>
39
- <Input label="Email" type="email" />
40
- <Carousel items={photos} />
38
+ export const config: SiteConfig = {
39
+ site: { title: "Business Name", description: "", theme: "aman" },
40
+ navigation: { header: […], footer: [[…], […], […], […]] },
41
+ };
41
42
  ```
42
43
 
43
- ### Server API
44
- Async functions for fetching data server-side:
44
+ ### 3. Root layout
45
45
 
46
46
  ```typescript
47
- import { getServices, getTestimonials, getBlogPosts } from '@keystone-pzjr/design-bootstrap/lib/server-api'
47
+ // app/layout.tsx
48
+ import { KeystoneRootLayout } from 'keystone-design-bootstrap/next/layouts/root-layout';
49
+ import { config } from '@/config';
48
50
 
49
- const services = await getServices()
50
- const testimonials = await getTestimonials()
51
- ```
52
-
53
- ### Sections
54
- Pre-built page components that accept data via props:
55
-
56
- ```typescript
57
- import { HeroHome, TestimonialsHome } from '@keystone-pzjr/design-bootstrap/sections'
58
- import { getTestimonials } from '@keystone-pzjr/design-bootstrap/lib/server-api'
59
-
60
- export default async function HomePage() {
61
- const testimonials = await getTestimonials()
62
- return (
63
- <main>
64
- <HeroHome />
65
- <TestimonialsHome testimonials={testimonials} />
66
- </main>
67
- )
51
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
52
+ return <KeystoneRootLayout config={config}>{children}</KeystoneRootLayout>;
68
53
  }
69
54
  ```
70
55
 
71
- **Available:** `HeroHome`, `ServicesHome`, `TestimonialsHome`, `BlogSection`, `ContactSection`, `HeaderNavigation`, `FooterHome`, and more.
72
-
73
- ## Package Exports
74
-
75
- ```typescript
76
- // Sections (hero, footer, header, testimonials, etc.)
77
- import { HeroHome, FooterHome, TestimonialsHome } from '@keystone-pzjr/design-bootstrap/sections'
78
-
79
- // Elements (buttons, inputs, carousels, etc.)
80
- import { Button, Input, Carousel } from '@keystone-pzjr/design-bootstrap/elements'
81
-
82
- // Hooks
83
- import { useBreakpoint } from '@keystone-pzjr/design-bootstrap/hooks'
84
-
85
- // Theme context
86
- import { ThemeProvider } from '@keystone-pzjr/design-bootstrap/contexts'
56
+ ### 4. CSS imports
87
57
 
88
- // Server API utilities
89
- import { getServices, getTestimonials } from '@keystone-pzjr/design-bootstrap/lib/server-api'
90
-
91
- // Types
92
- import type { Service, Testimonial } from '@keystone-pzjr/design-bootstrap/types'
93
-
94
- // Themes
95
- import { themes } from '@keystone-pzjr/design-bootstrap/themes'
58
+ ```css
59
+ /* app/globals.css */
60
+ @import "keystone-design-bootstrap/styles/fonts.css";
61
+ @import "keystone-design-bootstrap/styles/theme.css";
62
+ @import "keystone-design-bootstrap/styles/typography.css";
63
+ @import "keystone-design-bootstrap/styles/style-overrides.aman.css"; /* match your theme */
64
+ @import "../styles/custom-overrides.css";
96
65
  ```
97
66
 
98
- ## Meta Pixel Tracking
67
+ ---
99
68
 
100
- Meta Pixel is initialised automatically in `KeystoneRootLayout` when the account has a connected Meta integration with a pixel configured. Most events fire without any extra work. The one place you need to add tracking manually is **custom form submissions**.
69
+ ## Package exports reference
101
70
 
102
- ### What fires automatically
103
-
104
- | Event | Trigger |
71
+ | Import path | Contents |
105
72
  |---|---|
106
- | `PageView` | Every page load |
107
- | `ViewContent` | Route changes to `/services`, `/services/:slug`, `/locations`, `/locations/:slug`, `/portal`, `/service-menu`, `/faq`, `/contact` |
108
- | `InitiateCheckout` | Click on any link to the account's external booking URL |
109
- | Portal tab events | Opening Services, Packages, Specials, or Booking tabs in the member portal |
110
-
111
- ### Adding tracking to a custom form
112
-
113
- On successful submission, add two calls:
73
+ | `keystone-design-bootstrap/sections` | All section components |
74
+ | `keystone-design-bootstrap/elements` | UI element components |
75
+ | `keystone-design-bootstrap/portal` | `PortalPage` and portal sub-components |
76
+ | `keystone-design-bootstrap/next/layouts/root-layout` | `KeystoneRootLayout` |
77
+ | `keystone-design-bootstrap/next/routes/consumer-auth` | `createConsumerAuthHandlers` |
78
+ | `keystone-design-bootstrap/next/routes/form` | `createFormRouteHandlers` (re-exported as `POST`) |
79
+ | `keystone-design-bootstrap/lib/server-api` | Server-side data fetching functions |
80
+ | `keystone-design-bootstrap/lib/cta-urls` | `resolveCtaUrls`, `resolvePortalPath`, `isExternalCtaUrl` |
81
+ | `keystone-design-bootstrap/tracking` | `firePixelEvent`, `setPixelUserData` |
82
+ | `keystone-design-bootstrap/types` | TypeScript types |
83
+ | `keystone-design-bootstrap/hooks` | Client-side hooks |
84
+ | `keystone-design-bootstrap/styles/*` | CSS files |
114
85
 
115
- ```tsx
116
- import { firePixelEvent, setPixelUserData } from 'keystone-design-bootstrap/tracking';
117
-
118
- // inside your success handler, after a confirmed API response:
119
- await setPixelUserData({ email: data.email, phone: data.phone });
120
- firePixelEvent('Lead');
121
- ```
86
+ ---
122
87
 
123
- Also submit with `formType: 'lead'` in the POST body — this triggers the server-side CAPI `Lead` event automatically with no extra backend work.
88
+ ## Local development
124
89
 
125
- Both calls are silent no-ops when no Meta Pixel is configured for the site.
90
+ Use `yalc` to test local builds in a customer site:
126
91
 
127
- See `components/sections/VipReferralForm.tsx` in any customer site for a complete working example.
128
-
129
- ## Architecture
130
-
131
- - **Server-first**: Data fetching happens server-side, components render as Server Components where possible
132
- - **Theme variants**: Components automatically select variants based on active theme
133
- - **Tailwind-first**: Use semantic utility classes (`bg-primary`, `text-fg-primary`, `font-display`)
134
- - **Type-safe**: Full TypeScript support throughout
135
- - **CSS variables**: Themes customize via CSS custom properties
136
- - **Self-hosted fonts**: Uses Fontsource for optimized, bundled font loading
137
-
138
- ## Theme System
139
-
140
- **Available themes:** `classic`, `aman`, `barelux`
141
-
142
- ### Themes
92
+ ```bash
93
+ # In this package
94
+ npm run build && yalc publish
143
95
 
144
- - **classic**: Default professional theme, Inter font, neutral colors
145
- - **aman**: Luxury theme with Playfair Display serifs, warm beige, bronze accents
146
- - **barelux**: Modern minimal theme with Poppins, clean lines
96
+ # In the customer site
97
+ yalc update keystone-design-bootstrap
147
98
 
148
- ### Creating a Theme
99
+ # To restore the published npm version
100
+ yalc remove keystone-design-bootstrap && npm install
101
+ ```
149
102
 
150
- See [`docs/theme-system.md`](./docs/theme-system.md) for complete instructions.
103
+ ---
151
104
 
152
- **With AI assistance:**
153
- ```
154
- I am creating a new theme. Here is a link to an example: https://www.example.com
155
- [Attach screenshots of various pages]
105
+ ## Creating a new theme
156
106
 
157
- Please follow the prompt in /docs/ai-prompt-template.md
158
- ```
107
+ See [`docs/theme-system.md`](./docs/theme-system.md) for the full guide.
159
108
 
160
- **Manual steps:**
109
+ Quick checklist:
161
110
  1. Register in `src/themes/index.ts`
162
111
  2. Install fonts via Fontsource
163
112
  3. Create `src/styles/style-overrides.{theme}.css`
164
113
  4. Create component variants (optional)
165
- 5. Add to design gallery app
166
- 6. Pass lint, typecheck, and build
167
-
168
- **Critical rules:**
169
- - Never modify base components or foundation CSS
170
- - Use semantic variables/classes only
171
- - Set BOTH `--color-*` and `--background-*` prefixes
172
- - Match base component props exactly
173
- - Ensure `npm run lint`, `npm run typecheck`, `npm run build` pass with zero errors/warnings
114
+ 5. Add to design gallery
115
+ 6. `npm run lint && npm run typecheck && npm run build` — must all pass
174
116
 
175
- See [`.cursor/rules/theme-creation.mdc`](./.cursor/rules/theme-creation.mdc) for detailed rules
117
+ **Available themes:** `classic`, `aman`, `barelux`, `balance`
@@ -6261,7 +6261,7 @@ async function setPixelUserData(userData) {
6261
6261
  getRegisteredPixelIds().forEach((id3) => fbq("init", id3, hashed));
6262
6262
  }
6263
6263
  }
6264
- function firePixelEvent(event, params) {
6264
+ function firePixelEvent(event, params, eventId) {
6265
6265
  const fbq = getFbq();
6266
6266
  if (!fbq) {
6267
6267
  console.debug("[MetaPixel] skipped \u2014 fbq not loaded", { event });
@@ -6271,8 +6271,10 @@ function firePixelEvent(event, params) {
6271
6271
  const normalized = {};
6272
6272
  if (params == null ? void 0 : params.contentName) normalized.content_name = params.contentName;
6273
6273
  if (params == null ? void 0 : params.contentCategory) normalized.content_category = params.contentCategory;
6274
- console.debug("[MetaPixel]", event, normalized);
6275
- fbq("track", event, Object.keys(normalized).length > 0 ? normalized : void 0);
6274
+ const customData = Object.keys(normalized).length > 0 ? normalized : void 0;
6275
+ const eventData = eventId ? { eventID: eventId } : void 0;
6276
+ console.debug("[MetaPixel]", event, normalized, eventId ? { eventID: eventId } : "");
6277
+ fbq("track", event, customData, eventData);
6276
6278
  }
6277
6279
 
6278
6280
  // src/next/contexts/form-definitions.tsx
@@ -6330,7 +6332,7 @@ var ContactSectionForm = ({
6330
6332
  (_a = formRef.current) == null ? void 0 : _a.reset();
6331
6333
  onSuccess == null ? void 0 : onSuccess();
6332
6334
  await setPixelUserData({ email: data.email, phone: data.phone });
6333
- firePixelEvent("Lead");
6335
+ firePixelEvent("Lead", void 0, result.eventId);
6334
6336
  setTimeout(() => setSubmitStatus("idle"), 5e3);
6335
6337
  } else {
6336
6338
  setSubmitStatus("error");
@@ -6496,6 +6498,7 @@ var FooterHome = ({
6496
6498
  // src/design_system/sections/header-navigation.tsx
6497
6499
  import React22, { useRef as useRef7, useState as useState10 } from "react";
6498
6500
  import Link4 from "next/link";
6501
+ import { usePathname } from "next/navigation";
6499
6502
  import Image8 from "next/image";
6500
6503
  import { ChevronDown as ChevronDown4 } from "@untitledui/icons";
6501
6504
  import { Button as AriaButton8, Dialog as AriaDialog, DialogTrigger as AriaDialogTrigger, Popover as AriaPopover3 } from "react-aria-components";
@@ -6547,6 +6550,19 @@ var CONTACT_PATH = "/contact";
6547
6550
  function isExternalCtaUrl(href) {
6548
6551
  return href.startsWith("http://") || href.startsWith("https://");
6549
6552
  }
6553
+ function resolvePortalPath(companyInformation) {
6554
+ var _a;
6555
+ const url = (_a = companyInformation == null ? void 0 : companyInformation.portal_url) == null ? void 0 : _a.trim();
6556
+ if (!url) return null;
6557
+ let pathname = null;
6558
+ try {
6559
+ pathname = new URL(url).pathname;
6560
+ } catch (e) {
6561
+ pathname = url.startsWith("/") ? url : null;
6562
+ }
6563
+ if (!pathname || pathname === "/") return null;
6564
+ return pathname.endsWith("/") ? pathname.slice(0, -1) : pathname;
6565
+ }
6550
6566
  function resolveCtaUrls(companyInformation) {
6551
6567
  var _a, _b, _c;
6552
6568
  const portalUrl = ((_a = companyInformation == null ? void 0 : companyInformation.portal_url) == null ? void 0 : _a.trim()) || null;
@@ -6610,6 +6626,9 @@ function HeaderNavigation({
6610
6626
  image: logoImage
6611
6627
  };
6612
6628
  const dynamicNavigation = navigation;
6629
+ const pathname = usePathname();
6630
+ const portalPath = resolvePortalPath(companyInformation);
6631
+ const isPortalPage = portalPath ? pathname == null ? void 0 : pathname.startsWith(portalPath) : false;
6613
6632
  const getVariantClasses = () => {
6614
6633
  switch (variant) {
6615
6634
  case "minimal":
@@ -6817,7 +6836,7 @@ function HeaderNavigation({
6817
6836
  (cta_button == null ? void 0 : cta_button.secondary_label) && ctaUrls.hasSecondary ? cta_button.secondary_label : (cta_button == null ? void 0 : cta_button.label) || "Get Started"
6818
6837
  ))))
6819
6838
  ))))
6820
- ), /* @__PURE__ */ React22.createElement("div", { className: "fixed bottom-0 left-0 right-0 z-40 md:hidden bg-fg-primary" }, /* @__PURE__ */ React22.createElement("div", { className: "flex gap-0" }, (cta_button == null ? void 0 : cta_button.secondary_label) && ctaUrls.hasSecondary && /* @__PURE__ */ React22.createElement(
6839
+ ), !isPortalPage && /* @__PURE__ */ React22.createElement("div", { className: "fixed bottom-0 left-0 right-0 z-40 md:hidden bg-fg-primary" }, /* @__PURE__ */ React22.createElement("div", { className: "flex gap-0" }, (cta_button == null ? void 0 : cta_button.secondary_label) && ctaUrls.hasSecondary && /* @__PURE__ */ React22.createElement(
6821
6840
  Button2,
6822
6841
  {
6823
6842
  href: ctaUrls.secondaryHref,
@@ -8591,6 +8610,7 @@ registerThemeVariant("hero-home", "aman", HeroHome2);
8591
8610
  import React36, { useState as useState16, useRef as useRef9, useCallback as useCallback5 } from "react";
8592
8611
  import Link6 from "next/link";
8593
8612
  import Image11 from "next/image";
8613
+ import { usePathname as usePathname2 } from "next/navigation";
8594
8614
  var MAX_DROPDOWN_ITEMS = 3;
8595
8615
  function HeaderNavigation2({
8596
8616
  props,
@@ -8626,6 +8646,9 @@ function HeaderNavigation2({
8626
8646
  const companyName = logoTextOverride || (companyInformation == null ? void 0 : companyInformation.company_name) || ((_b = props == null ? void 0 : props.logo) == null ? void 0 : _b.text) || "";
8627
8647
  const navigation = navigationOverride || ((_c = config == null ? void 0 : config.navigation) == null ? void 0 : _c.header) || [];
8628
8648
  const ctaUrls = resolveCtaUrls(companyInformation);
8649
+ const pathname = usePathname2();
8650
+ const portalPath = resolvePortalPath(companyInformation);
8651
+ const isPortalPage = portalPath ? pathname == null ? void 0 : pathname.startsWith(portalPath) : false;
8629
8652
  const cancelCloseTimeout = useCallback5(() => {
8630
8653
  if (closeTimeoutRef.current) {
8631
8654
  clearTimeout(closeTimeoutRef.current);
@@ -8843,7 +8866,7 @@ function HeaderNavigation2({
8843
8866
  onClick: () => setIsMobileMenuOpen(false)
8844
8867
  },
8845
8868
  ((_q = props == null ? void 0 : props.cta_button) == null ? void 0 : _q.secondary_label) && ctaUrls.hasSecondary ? props.cta_button.secondary_label : ((_r = props == null ? void 0 : props.cta_button) == null ? void 0 : _r.label) || "Contact"
8846
- ))))), /* @__PURE__ */ React36.createElement("div", { className: "fixed bottom-0 left-0 right-0 z-40 md:hidden bg-fg-primary" }, /* @__PURE__ */ React36.createElement("div", { className: "flex gap-0" }, ((_s = props == null ? void 0 : props.cta_button) == null ? void 0 : _s.secondary_label) && ctaUrls.hasSecondary && /* @__PURE__ */ React36.createElement(
8869
+ ))))), !isPortalPage && /* @__PURE__ */ React36.createElement("div", { className: "fixed bottom-0 left-0 right-0 z-40 md:hidden bg-fg-primary" }, /* @__PURE__ */ React36.createElement("div", { className: "flex gap-0" }, ((_s = props == null ? void 0 : props.cta_button) == null ? void 0 : _s.secondary_label) && ctaUrls.hasSecondary && /* @__PURE__ */ React36.createElement(
8847
8870
  Button2,
8848
8871
  {
8849
8872
  href: ctaUrls.secondaryHref,
@@ -9092,7 +9115,7 @@ var ContactSectionForm2 = ({
9092
9115
  (_a = formRef.current) == null ? void 0 : _a.reset();
9093
9116
  onSuccess == null ? void 0 : onSuccess();
9094
9117
  await setPixelUserData({ email: data.email, phone: data.phone });
9095
- firePixelEvent("Lead");
9118
+ firePixelEvent("Lead", void 0, result.eventId);
9096
9119
  setTimeout(() => setSubmitStatus("idle"), 5e3);
9097
9120
  } else {
9098
9121
  setSubmitStatus("error");
@@ -17683,6 +17706,7 @@ registerThemeVariant("hero-home", "barelux", HeroHome3);
17683
17706
  import React45, { useState as useState23, useRef as useRef14, useCallback as useCallback8 } from "react";
17684
17707
  import Link8 from "next/link";
17685
17708
  import Image12 from "next/image";
17709
+ import { usePathname as usePathname3 } from "next/navigation";
17686
17710
  var MAX_DROPDOWN_ITEMS2 = 6;
17687
17711
  function HeaderNavigation3({
17688
17712
  props,
@@ -17708,6 +17732,9 @@ function HeaderNavigation3({
17708
17732
  const companyName = logoTextOverride || (companyInformation == null ? void 0 : companyInformation.company_name) || ((_b = props == null ? void 0 : props.logo) == null ? void 0 : _b.text) || "";
17709
17733
  const navigation = navigationOverride || ((_c = config == null ? void 0 : config.navigation) == null ? void 0 : _c.header) || [];
17710
17734
  const ctaUrls = resolveCtaUrls(companyInformation);
17735
+ const pathname = usePathname3();
17736
+ const portalPath = resolvePortalPath(companyInformation);
17737
+ const isPortalPage = portalPath ? pathname == null ? void 0 : pathname.startsWith(portalPath) : false;
17711
17738
  const cancelCloseTimeout = useCallback8(() => {
17712
17739
  if (closeTimeoutRef.current) {
17713
17740
  clearTimeout(closeTimeoutRef.current);
@@ -17899,7 +17926,7 @@ function HeaderNavigation3({
17899
17926
  onClick: () => setIsMobileMenuOpen(false)
17900
17927
  },
17901
17928
  ((_m = props == null ? void 0 : props.cta_button) == null ? void 0 : _m.label) || ""
17902
- ))))), /* @__PURE__ */ React45.createElement("div", { className: "fixed bottom-0 left-0 right-0 z-40 md:hidden bg-fg-primary" }, /* @__PURE__ */ React45.createElement("div", { className: "flex gap-0" }, ((_n = props == null ? void 0 : props.cta_button) == null ? void 0 : _n.secondary_label) && ctaUrls.hasSecondary && /* @__PURE__ */ React45.createElement(
17929
+ ))))), !isPortalPage && /* @__PURE__ */ React45.createElement("div", { className: "fixed bottom-0 left-0 right-0 z-40 md:hidden bg-fg-primary" }, /* @__PURE__ */ React45.createElement("div", { className: "flex gap-0" }, ((_n = props == null ? void 0 : props.cta_button) == null ? void 0 : _n.secondary_label) && ctaUrls.hasSecondary && /* @__PURE__ */ React45.createElement(
17903
17930
  Button2,
17904
17931
  {
17905
17932
  href: ctaUrls.secondaryHref,
@@ -18294,7 +18321,7 @@ var ContactSectionForm3 = ({
18294
18321
  (_a = formRef.current) == null ? void 0 : _a.reset();
18295
18322
  onSuccess == null ? void 0 : onSuccess();
18296
18323
  await setPixelUserData({ email: data.email, phone: data.phone });
18297
- firePixelEvent("Lead");
18324
+ firePixelEvent("Lead", void 0, result.eventId);
18298
18325
  setTimeout(() => setSubmitStatus("idle"), 5e3);
18299
18326
  } else {
18300
18327
  setSubmitStatus("error");
@@ -18474,6 +18501,7 @@ registerThemeVariant("hero-home", "balance", HeroHome4);
18474
18501
  import React53, { useState as useState27, useRef as useRef16, useCallback as useCallback9 } from "react";
18475
18502
  import Link10 from "next/link";
18476
18503
  import Image13 from "next/image";
18504
+ import { usePathname as usePathname4 } from "next/navigation";
18477
18505
  function HeaderNavigation4({
18478
18506
  props,
18479
18507
  navigation: navigationOverride,
@@ -18498,6 +18526,9 @@ function HeaderNavigation4({
18498
18526
  const companyName = logoTextOverride || (companyInformation == null ? void 0 : companyInformation.company_name) || ((_b = props == null ? void 0 : props.logo) == null ? void 0 : _b.text) || "";
18499
18527
  const navigation = navigationOverride || ((_c = config == null ? void 0 : config.navigation) == null ? void 0 : _c.header) || [];
18500
18528
  const ctaUrls = resolveCtaUrls(companyInformation);
18529
+ const pathname = usePathname4();
18530
+ const portalPath = resolvePortalPath(companyInformation);
18531
+ const isPortalPage = portalPath ? pathname == null ? void 0 : pathname.startsWith(portalPath) : false;
18501
18532
  const cancelCloseTimeout = useCallback9(() => {
18502
18533
  if (closeTimeoutRef.current) {
18503
18534
  clearTimeout(closeTimeoutRef.current);
@@ -18659,7 +18690,7 @@ function HeaderNavigation4({
18659
18690
  onClick: () => setIsMobileMenuOpen(false)
18660
18691
  },
18661
18692
  ((_m = props == null ? void 0 : props.cta_button) == null ? void 0 : _m.label) || ""
18662
- ))))), /* @__PURE__ */ React53.createElement("div", { className: "fixed bottom-0 left-0 right-0 z-40 md:hidden", style: { backgroundColor: "rgb(148, 133, 84)" } }, /* @__PURE__ */ React53.createElement("div", { className: "flex gap-0" }, ((_n = props == null ? void 0 : props.cta_button) == null ? void 0 : _n.secondary_label) && ctaUrls.hasSecondary && /* @__PURE__ */ React53.createElement(
18693
+ ))))), !isPortalPage && /* @__PURE__ */ React53.createElement("div", { className: "fixed bottom-0 left-0 right-0 z-40 md:hidden", style: { backgroundColor: "rgb(148, 133, 84)" } }, /* @__PURE__ */ React53.createElement("div", { className: "flex gap-0" }, ((_n = props == null ? void 0 : props.cta_button) == null ? void 0 : _n.secondary_label) && ctaUrls.hasSecondary && /* @__PURE__ */ React53.createElement(
18663
18694
  Button2,
18664
18695
  {
18665
18696
  href: ctaUrls.secondaryHref,
@@ -18788,7 +18819,7 @@ var ContactSectionForm4 = ({
18788
18819
  (_a = formRef.current) == null ? void 0 : _a.reset();
18789
18820
  onSuccess == null ? void 0 : onSuccess();
18790
18821
  await setPixelUserData({ email: data.email, phone: data.phone });
18791
- firePixelEvent("Lead");
18822
+ firePixelEvent("Lead", void 0, result.eventId);
18792
18823
  setTimeout(() => setSubmitStatus("idle"), 5e3);
18793
18824
  } else {
18794
18825
  setSubmitStatus("error");