keystone-design-bootstrap 1.0.21 → 1.0.22
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keystone-design-bootstrap",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "Keystone Design Bootstrap - Sections, Elements, and Theme System for customer websites",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"./logo": "./src/design_system/logo/keystone-logo.tsx",
|
|
13
13
|
"./hooks": "./src/lib/hooks/index.ts",
|
|
14
14
|
"./contexts": "./src/contexts/index.ts",
|
|
15
|
+
"./tracking": "./src/tracking/index.ts",
|
|
15
16
|
"./lib/server-api": "./src/lib/server-api.ts",
|
|
16
17
|
"./lib/component-registry": "./src/lib/component-registry.ts",
|
|
17
18
|
"./styles/*": "./src/styles/*",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useRef, useState } from 'react';
|
|
4
4
|
import { Checkbox, Form, Input, InputGroup, NativeSelect, Textarea, Button } from '../elements';
|
|
5
|
+
import { trackMetaLead } from '../../tracking/trackMetaLead';
|
|
5
6
|
import countries, { phoneCodeOptions } from '../../utils/countries';
|
|
6
7
|
|
|
7
8
|
interface ContactSectionFormProps {
|
|
@@ -87,6 +88,7 @@ export const ContactSectionForm = ({
|
|
|
87
88
|
setStatusMessage(result.message || successMessage);
|
|
88
89
|
formRef.current?.reset();
|
|
89
90
|
onSuccess?.();
|
|
91
|
+
trackMetaLead(result.eventId);
|
|
90
92
|
// Reset status after 5 seconds
|
|
91
93
|
setTimeout(() => setSubmitStatus('idle'), 5000);
|
|
92
94
|
} else {
|
package/src/lib/actions.ts
CHANGED
|
@@ -12,6 +12,8 @@ interface ContactFormResult {
|
|
|
12
12
|
success: boolean;
|
|
13
13
|
message?: string;
|
|
14
14
|
error?: string;
|
|
15
|
+
/** Present on lead form success; use for Meta Pixel dedup: fbq('track', 'Lead', {}, { eventID: eventId }) */
|
|
16
|
+
eventId?: string;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
/**
|
|
@@ -126,10 +128,13 @@ export async function submitLeadFormAction(formData: FormData): Promise<ContactF
|
|
|
126
128
|
error: data.error || 'Failed to submit lead form. Please try again.',
|
|
127
129
|
};
|
|
128
130
|
}
|
|
129
|
-
|
|
131
|
+
|
|
132
|
+
const eventId = data.data?.event_id ?? undefined;
|
|
133
|
+
|
|
130
134
|
return {
|
|
131
135
|
success: true,
|
|
132
136
|
message: data.message || 'Thank you! We\'ll be in touch soon.',
|
|
137
|
+
...(eventId && { eventId }),
|
|
133
138
|
};
|
|
134
139
|
} catch (error) {
|
|
135
140
|
console.error('Lead form submission error:', error);
|
package/src/lib/server-api.ts
CHANGED
|
@@ -60,6 +60,18 @@ export async function getCompanyInformation() {
|
|
|
60
60
|
return serverFetch('/public/company_information', defaultOptions);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
/** Ads config (e.g. Meta Pixel). Returns { meta_pixel_id?: string } or {}. Only present when account has connected Meta Ads. */
|
|
64
|
+
export async function getAdsConfig(): Promise<{ meta_pixel_id?: string } | null> {
|
|
65
|
+
const data = await serverFetch<{ meta_pixel_id?: string }>('/public/ads_config', defaultOptions);
|
|
66
|
+
return data ?? null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Extract Meta Pixel ID from ads config for use with <MetaPixel pixelId={...} />. */
|
|
70
|
+
export function getMetaPixelId(adsConfig: { meta_pixel_id?: string } | null | undefined): string | null {
|
|
71
|
+
const id = adsConfig && typeof adsConfig === 'object' && 'meta_pixel_id' in adsConfig && adsConfig.meta_pixel_id;
|
|
72
|
+
return id != null && id !== '' ? String(id) : null;
|
|
73
|
+
}
|
|
74
|
+
|
|
63
75
|
export async function getServices() {
|
|
64
76
|
return serverFetch('/public/services', defaultOptions);
|
|
65
77
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Script from 'next/script';
|
|
4
|
+
|
|
5
|
+
const FBEVENTS_URL = 'https://connect.facebook.net/en_US/fbevents.js';
|
|
6
|
+
|
|
7
|
+
const PIXEL_SCRIPT = (pixelId: string) => `
|
|
8
|
+
!function(f,b,e,v,n,t,s)
|
|
9
|
+
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
|
|
10
|
+
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
|
|
11
|
+
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
|
|
12
|
+
n.queue=[];t=b.createElement(e);t.async=!0;
|
|
13
|
+
t.src=v;s=b.getElementsByTagName(e)[0];
|
|
14
|
+
s.parentNode.insertBefore(t,s)}(window, document,'script','${FBEVENTS_URL}');
|
|
15
|
+
fbq('init', '${pixelId.replace(/'/g, "\\'")}');
|
|
16
|
+
fbq('track', 'PageView');
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
export type MetaPixelProps = {
|
|
20
|
+
/** Meta Pixel ID. When null/undefined, nothing is rendered. */
|
|
21
|
+
pixelId: string | null | undefined;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Renders the Meta (Facebook) Pixel base code: loads fbevents.js, initializes
|
|
26
|
+
* the pixel, and tracks PageView. Use in the root layout when ads config
|
|
27
|
+
* provides a meta_pixel_id.
|
|
28
|
+
*/
|
|
29
|
+
export function MetaPixel({ pixelId }: MetaPixelProps) {
|
|
30
|
+
if (!pixelId || typeof pixelId !== 'string' || pixelId.trim() === '') {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const id = pixelId.trim();
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
<Script
|
|
39
|
+
id="meta-pixel"
|
|
40
|
+
strategy="afterInteractive"
|
|
41
|
+
dangerouslySetInnerHTML={{ __html: PIXEL_SCRIPT(id) }}
|
|
42
|
+
/>
|
|
43
|
+
<noscript>
|
|
44
|
+
<img
|
|
45
|
+
height={1}
|
|
46
|
+
width={1}
|
|
47
|
+
style={{ display: 'none' }}
|
|
48
|
+
src={`https://www.facebook.com/tr?id=${id}&ev=PageView&noscript=1`}
|
|
49
|
+
alt=""
|
|
50
|
+
/>
|
|
51
|
+
</noscript>
|
|
52
|
+
</>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
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) fbq('track', 'Lead', {}, { eventID: eventId });
|
|
9
|
+
}
|