Skip to content

Commit cf9a3fb

Browse files
committed
feat(scripts): add consent manager provider using c15t
1 parent 4845d87 commit cf9a3fb

File tree

6 files changed

+1801
-27
lines changed

6 files changed

+1801
-27
lines changed

.changeset/full-bees-worry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@bigcommerce/catalyst-core': minor
3+
---
4+
5+
Adds a new consent manager provider using the `@c15t/nextjs` package to handle cookie consent management with support for multiple consent categories and cookie-based persistence.
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { z } from 'zod';
2+
3+
export const CONSENT_COOKIE_NAME = 'c15t-consent';
4+
5+
const ConsentNamesSchema = z.enum([
6+
'necessary',
7+
'experience',
8+
'functionality',
9+
'marketing',
10+
'measurement',
11+
]);
12+
const ConsentStateSchema = z.record(ConsentNamesSchema, z.boolean());
13+
const ConsentCookieSchema = z.object({
14+
preferences: ConsentStateSchema,
15+
timestamp: z.date(),
16+
});
17+
18+
function getConsentCookie() {
19+
if (typeof document === 'undefined') return null;
20+
21+
const cookies = document.cookie.split('; ');
22+
const cookie = cookies.find((c) => c.startsWith(`${CONSENT_COOKIE_NAME}=`));
23+
24+
if (!cookie) return null;
25+
26+
const value = cookie.split('=')[1] ?? null;
27+
28+
if (!value) return null;
29+
30+
const decoded = decodeURIComponent(value);
31+
const raw: unknown = JSON.parse(decoded);
32+
const result = ConsentCookieSchema.safeParse(raw);
33+
34+
if (!result.success) return null;
35+
36+
return result.data;
37+
}
38+
39+
function setConsentCookie(consent: Record<string, boolean>) {
40+
if (typeof document === 'undefined') return;
41+
42+
const encoded = encodeURIComponent(JSON.stringify(consent));
43+
44+
document.cookie = `${CONSENT_COOKIE_NAME}=${encoded}; path=/`;
45+
}
46+
47+
export function showConsentBanner() {
48+
let show = true;
49+
50+
try {
51+
const consent = getConsentCookie();
52+
53+
show = !consent;
54+
} catch {
55+
show = false;
56+
}
57+
58+
return {
59+
data: {
60+
showConsentBanner: show,
61+
branding: 'none',
62+
},
63+
error: null,
64+
ok: true,
65+
response: null,
66+
};
67+
}
68+
69+
export function setConsent(options?: {
70+
body?: { preferences?: Record<string, boolean>; type?: string; domain?: string };
71+
}) {
72+
const { preferences } = options?.body ?? {};
73+
74+
setConsentCookie(preferences ?? {});
75+
76+
return {
77+
data: null,
78+
error: null,
79+
ok: true,
80+
response: null,
81+
};
82+
}
83+
84+
export function verifyConsent() {
85+
const consent = getConsentCookie();
86+
87+
if (!consent) {
88+
return {
89+
data: {
90+
isValid: false,
91+
},
92+
error: null,
93+
ok: true,
94+
response: null,
95+
};
96+
}
97+
98+
return {
99+
data: {
100+
isValid: true,
101+
},
102+
error: null,
103+
ok: true,
104+
response: null,
105+
};
106+
}

core/lib/consent-manager/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './provider';
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use client';
2+
3+
import { ConsentManagerProvider as C15TConsentManagerProvider } from '@c15t/nextjs';
4+
import { type PropsWithChildren } from 'react';
5+
6+
import { setConsent, showConsentBanner, verifyConsent } from './handlers';
7+
8+
export function ConsentManagerProvider({ children }: PropsWithChildren) {
9+
return (
10+
<C15TConsentManagerProvider
11+
options={{
12+
mode: 'custom',
13+
consentCategories: ['necessary', 'experience', 'functionality', 'marketing', 'measurement'],
14+
15+
// @ts-expect-error endpointHandlers type is not yet exposed by the package
16+
endpointHandlers: {
17+
showConsentBanner,
18+
setConsent,
19+
verifyConsent,
20+
},
21+
}}
22+
>
23+
{children}
24+
</C15TConsentManagerProvider>
25+
);
26+
}

core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
},
1515
"dependencies": {
1616
"@bigcommerce/catalyst-client": "workspace:^",
17+
"@c15t/nextjs": "^1.7.0",
1718
"@conform-to/react": "^1.6.1",
1819
"@conform-to/zod": "^1.6.1",
1920
"@icons-pack/react-simple-icons": "^11.2.0",

0 commit comments

Comments
 (0)