keystone-design-bootstrap 1.0.57 → 1.0.59

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 (48) hide show
  1. package/dist/blog-post-vWzW8yFb.d.ts +50 -0
  2. package/dist/contexts/index.d.ts +13 -0
  3. package/dist/design_system/elements/index.d.ts +383 -0
  4. package/dist/design_system/logo/keystone-logo.d.ts +6 -0
  5. package/dist/design_system/sections/index.d.ts +232 -0
  6. package/dist/design_system/sections/index.js +25 -37
  7. package/dist/design_system/sections/index.js.map +1 -1
  8. package/dist/index.d.ts +69 -0
  9. package/dist/index.js +25 -37
  10. package/dist/index.js.map +1 -1
  11. package/dist/lib/component-registry.d.ts +13 -0
  12. package/dist/lib/hooks/index.d.ts +83 -0
  13. package/dist/lib/server-api.d.ts +44 -0
  14. package/dist/package-CB1tENyG.d.ts +148 -0
  15. package/dist/photos-CmBdWiuZ.d.ts +27 -0
  16. package/dist/themes/index.d.ts +16 -0
  17. package/dist/types/index.d.ts +312 -0
  18. package/dist/utils/cx.d.ts +15 -0
  19. package/dist/utils/gradient-placeholder.d.ts +8 -0
  20. package/dist/utils/is-react-component.d.ts +21 -0
  21. package/dist/utils/markdown-toc.d.ts +14 -0
  22. package/dist/utils/phone-helpers.d.ts +24 -0
  23. package/dist/utils/photo-helpers.d.ts +38 -0
  24. package/dist/website-photos-Cl1YqAno.d.ts +21 -0
  25. package/package.json +1 -1
  26. package/src/design_system/portal/PortalPage.tsx +107 -91
  27. package/src/design_system/portal/PortalTabTracker.tsx +24 -0
  28. package/src/design_system/sections/contact-section-form.aman.tsx +2 -2
  29. package/src/design_system/sections/contact-section-form.balance.tsx +2 -2
  30. package/src/design_system/sections/contact-section-form.barelux.tsx +2 -2
  31. package/src/design_system/sections/contact-section-form.tsx +2 -2
  32. package/src/design_system/sections/header-navigation.aman.tsx +1 -4
  33. package/src/design_system/sections/header-navigation.balance.tsx +1 -4
  34. package/src/design_system/sections/header-navigation.barelux.tsx +1 -4
  35. package/src/design_system/sections/header-navigation.tsx +1 -8
  36. package/src/index.ts +1 -1
  37. package/src/lib/cta-urls.ts +15 -38
  38. package/src/next/layouts/root-layout.tsx +6 -7
  39. package/src/next/routes/consumer-auth.ts +2 -4
  40. package/src/tracking/MetaPixelTracker.tsx +17 -12
  41. package/src/tracking/firePixelEvent.ts +26 -0
  42. package/src/tracking/index.ts +2 -6
  43. package/src/types/api/company-information.ts +2 -0
  44. package/src/tracking/BookingCtaTracker.tsx +0 -32
  45. package/src/tracking/ViewContentTracker.tsx +0 -21
  46. package/src/tracking/trackInitiateCheckout.ts +0 -16
  47. package/src/tracking/trackMetaLead.ts +0 -14
  48. package/src/tracking/trackViewContent.ts +0 -19
@@ -160,16 +160,14 @@ async function handleLogout(_request: Request, NR: NextResponseLike): Promise<Re
160
160
  /**
161
161
  * Creates a single POST handler that routes to the correct auth action based on
162
162
  * the dynamic `[action]` path segment.
163
- *
164
- * Compatible with Next.js 14 (sync params) and 15 (async params).
165
163
  */
166
164
  export function createConsumerAuthHandlers({ NextResponse }: { NextResponse: NextResponseLike }) {
167
165
  return {
168
166
  POST: async (
169
167
  request: Request,
170
- context: { params: Promise<{ action: string }> | { action: string } }
168
+ context: { params: Promise<{ action: string }> }
171
169
  ): Promise<Response> => {
172
- const { action } = await Promise.resolve(context.params);
170
+ const { action } = await context.params;
173
171
  if (action === 'initiate') return handleInitiate(request, NextResponse);
174
172
  if (action === 'login') return handleLogin(request, NextResponse);
175
173
  if (action === 'signup') return handleSignup(request, NextResponse);
@@ -2,14 +2,20 @@
2
2
 
3
3
  import { useEffect } from 'react';
4
4
  import { usePathname } from 'next/navigation';
5
- import { trackViewContent } from './trackViewContent';
6
- import { trackInitiateCheckout } from './trackInitiateCheckout';
5
+ import { firePixelEvent } from './firePixelEvent';
7
6
 
8
7
  type RouteRule = {
9
8
  pattern: RegExp;
10
9
  getParams: (match: RegExpMatchArray) => { contentName: string; contentCategory: string };
11
10
  };
12
11
 
12
+ function slugToTitle(slug: string): string {
13
+ return slug
14
+ .split('-')
15
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
16
+ .join(' ');
17
+ }
18
+
13
19
  // Checked in order — first match wins. More specific patterns come first.
14
20
  const ROUTE_RULES: RouteRule[] = [
15
21
  {
@@ -28,6 +34,10 @@ const ROUTE_RULES: RouteRule[] = [
28
34
  pattern: /^\/locations$/,
29
35
  getParams: () => ({ contentName: 'Locations', contentCategory: 'Locations' }),
30
36
  },
37
+ {
38
+ pattern: /^\/portal$/,
39
+ getParams: () => ({ contentName: 'Member Portal', contentCategory: 'Pricing' }),
40
+ },
31
41
  {
32
42
  pattern: /^\/service-menu$/,
33
43
  getParams: () => ({ contentName: 'Service Menu', contentCategory: 'Pricing' }),
@@ -42,13 +52,6 @@ const ROUTE_RULES: RouteRule[] = [
42
52
  },
43
53
  ];
44
54
 
45
- function slugToTitle(slug: string): string {
46
- return slug
47
- .split('-')
48
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
49
- .join(' ');
50
- }
51
-
52
55
  type Props = {
53
56
  /** External booking URL. When set, fires InitiateCheckout on any click targeting that URL. */
54
57
  bookingUrl?: string | null;
@@ -58,6 +61,9 @@ type Props = {
58
61
  * Single client-side tracker placed once in KeystoneRootLayout.
59
62
  * - Fires ViewContent on every route change for known page patterns.
60
63
  * - Fires InitiateCheckout whenever a visitor clicks a link to the external booking URL.
64
+ *
65
+ * Portal booking tab tracking is handled directly inside PortalPage via PortalTabTracker
66
+ * since intent is only established when the Booking tab is explicitly opened.
61
67
  */
62
68
  export function MetaPixelTracker({ bookingUrl }: Props) {
63
69
  const pathname = usePathname();
@@ -67,7 +73,7 @@ export function MetaPixelTracker({ bookingUrl }: Props) {
67
73
  const match = pathname.match(rule.pattern);
68
74
  if (match) {
69
75
  const { contentName, contentCategory } = rule.getParams(match);
70
- trackViewContent(contentName, contentCategory);
76
+ firePixelEvent('ViewContent', { contentName, contentCategory });
71
77
  break;
72
78
  }
73
79
  }
@@ -79,8 +85,7 @@ export function MetaPixelTracker({ bookingUrl }: Props) {
79
85
  const handleClick = (e: MouseEvent) => {
80
86
  const anchor = (e.target as Element).closest('a');
81
87
  if (anchor?.href?.startsWith(bookingUrl)) {
82
- console.debug('[MetaPixel] Booking link clicked', { href: anchor.href });
83
- trackInitiateCheckout();
88
+ firePixelEvent('InitiateCheckout');
84
89
  }
85
90
  };
86
91
 
@@ -0,0 +1,26 @@
1
+ type FbqFn = (method: string, eventName: string, params?: Record<string, string>) => void;
2
+
3
+ export type PixelEvent = 'PageView' | 'ViewContent' | 'InitiateCheckout' | 'Lead';
4
+
5
+ export interface PixelEventParams {
6
+ contentName?: string;
7
+ contentCategory?: string;
8
+ }
9
+
10
+ /**
11
+ * Single entry point for all client-side Meta Pixel event fires.
12
+ * Silently no-ops if fbq is not loaded (pixel not configured for this site).
13
+ */
14
+ export function firePixelEvent(event: PixelEvent, params?: PixelEventParams): void {
15
+ if (typeof window === 'undefined') return;
16
+ const fbq = (window as Window & { fbq?: FbqFn }).fbq;
17
+ if (!fbq) {
18
+ console.debug('[MetaPixel] skipped — fbq not loaded', { event });
19
+ return;
20
+ }
21
+ const normalized: Record<string, string> = {};
22
+ if (params?.contentName) normalized.content_name = params.contentName;
23
+ if (params?.contentCategory) normalized.content_category = params.contentCategory;
24
+ console.debug('[MetaPixel]', event, normalized);
25
+ fbq('track', event, Object.keys(normalized).length > 0 ? normalized : undefined);
26
+ }
@@ -1,9 +1,5 @@
1
1
  export { MetaPixel } from './MetaPixel';
2
2
  export type { MetaPixelProps } from './MetaPixel';
3
- export { trackMetaLead } from './trackMetaLead';
4
- export { trackViewContent } from './trackViewContent';
5
- export { trackInitiateCheckout } from './trackInitiateCheckout';
6
3
  export { MetaPixelTracker } from './MetaPixelTracker';
7
- // Kept for custom use — MetaPixelTracker covers the standard cases automatically.
8
- export { ViewContentTracker } from './ViewContentTracker';
9
- export { BookingCtaTracker } from './BookingCtaTracker';
4
+ export { firePixelEvent } from './firePixelEvent';
5
+ export type { PixelEvent, PixelEventParams } from './firePixelEvent';
@@ -36,6 +36,8 @@ export interface CompanyInformation {
36
36
  sales_email?: string;
37
37
  business_hours?: string;
38
38
  external_management_url?: string;
39
+ /** Member portal URL for this account. When set, used as the primary CTA instead of external_management_url. */
40
+ portal_url?: string | null;
39
41
  created_at: string;
40
42
  updated_at: string;
41
43
  photo_attachments?: PhotoAttachment[];
@@ -1,32 +0,0 @@
1
- 'use client';
2
-
3
- import { useEffect } from 'react';
4
- import { trackInitiateCheckout } from './trackInitiateCheckout';
5
-
6
- type Props = {
7
- bookingUrl: string | null | undefined;
8
- };
9
-
10
- /**
11
- * Drop into the root layout to fire Meta Pixel InitiateCheckout whenever a visitor
12
- * clicks any anchor whose href points to the external booking URL.
13
- * Uses document-level click delegation — no changes needed to individual buttons.
14
- */
15
- export function BookingCtaTracker({ bookingUrl }: Props) {
16
- useEffect(() => {
17
- if (!bookingUrl) return;
18
-
19
- const handleClick = (e: MouseEvent) => {
20
- const anchor = (e.target as Element).closest('a');
21
- if (!anchor) return;
22
- if (anchor.href && anchor.href.startsWith(bookingUrl)) {
23
- trackInitiateCheckout();
24
- }
25
- };
26
-
27
- document.addEventListener('click', handleClick);
28
- return () => document.removeEventListener('click', handleClick);
29
- }, [bookingUrl]);
30
-
31
- return null;
32
- }
@@ -1,21 +0,0 @@
1
- 'use client';
2
-
3
- import { useEffect } from 'react';
4
- import { trackViewContent } from './trackViewContent';
5
-
6
- type Props = {
7
- contentName?: string;
8
- contentCategory?: string;
9
- };
10
-
11
- /**
12
- * Drop into any server-rendered page to fire the Meta Pixel ViewContent event on mount.
13
- * Renders nothing — purely a tracking side-effect component.
14
- */
15
- export function ViewContentTracker({ contentName, contentCategory }: Props) {
16
- useEffect(() => {
17
- trackViewContent(contentName, contentCategory);
18
- }, [contentName, contentCategory]);
19
-
20
- return null;
21
- }
@@ -1,16 +0,0 @@
1
- type FbqFn = (method: string, eventName: string, params?: object) => void;
2
-
3
- /**
4
- * Fires the client-side Meta Pixel InitiateCheckout event.
5
- * Call this when a visitor clicks a booking / scheduling button.
6
- */
7
- export function trackInitiateCheckout(): void {
8
- if (typeof window === 'undefined') return;
9
- const fbq = (window as Window & { fbq?: FbqFn }).fbq;
10
- if (!fbq) {
11
- console.debug('[MetaPixel] InitiateCheckout skipped — fbq not loaded');
12
- return;
13
- }
14
- console.debug('[MetaPixel] InitiateCheckout');
15
- fbq('track', 'InitiateCheckout');
16
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Fires the client-side Meta Pixel Lead event with the same eventID as server CAPI
3
- * so Meta can deduplicate browser + server events.
4
- */
5
- export function trackMetaLead(eventId: string | undefined): void {
6
- if (typeof window === 'undefined' || !eventId) return;
7
- const fbq = (window as Window & { fbq?: (method: string, eventName: string, params?: object, options?: { eventID?: string }) => void }).fbq;
8
- if (!fbq) {
9
- console.debug('[MetaPixel] Lead skipped — fbq not loaded', { eventId });
10
- return;
11
- }
12
- console.debug('[MetaPixel] Lead', { eventId });
13
- fbq('track', 'Lead', {}, { eventID: eventId });
14
- }
@@ -1,19 +0,0 @@
1
- type FbqFn = (method: string, eventName: string, params?: object) => void;
2
-
3
- /**
4
- * Fires the client-side Meta Pixel ViewContent event.
5
- * Call this on service/offer detail pages so Meta knows which content is most engaging.
6
- */
7
- export function trackViewContent(contentName?: string, contentCategory?: string): void {
8
- if (typeof window === 'undefined') return;
9
- const fbq = (window as Window & { fbq?: FbqFn }).fbq;
10
- if (!fbq) {
11
- console.debug('[MetaPixel] ViewContent skipped — fbq not loaded', { contentName, contentCategory });
12
- return;
13
- }
14
- const params: Record<string, string> = {};
15
- if (contentName) params.content_name = contentName;
16
- if (contentCategory) params.content_category = contentCategory;
17
- console.debug('[MetaPixel] ViewContent', params);
18
- fbq('track', 'ViewContent', params);
19
- }