@ndlib/component-library 1.0.27 → 1.0.28
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/components/elements/ConsentBanner/ConsentBanner.stories.d.ts +15 -0
- package/dist/components/elements/ConsentBanner/ConsentBanner.stories.js +109 -0
- package/dist/components/elements/ConsentBanner/ConsentBanner.test.d.ts +1 -0
- package/dist/components/elements/ConsentBanner/ConsentBanner.test.js +68 -0
- package/dist/components/elements/ConsentBanner/consentBanner.d.ts +13 -0
- package/dist/components/elements/ConsentBanner/consentBanner.js +201 -0
- package/package.json +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { ConsentBanner } from './consentBanner';
|
|
3
|
+
declare global {
|
|
4
|
+
interface Window {
|
|
5
|
+
clarity?: unknown;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
declare const meta: Meta<typeof ConsentBanner>;
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof ConsentBanner>;
|
|
11
|
+
export declare const EEA_Shows: Story;
|
|
12
|
+
export declare const NonEEA_Hides: Story;
|
|
13
|
+
export declare const AcceptFlow: Story;
|
|
14
|
+
export declare const DenyFlow: Story;
|
|
15
|
+
export declare const AutoDetect_FetchMock: Story;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
+
import { ConsentBanner } from './consentBanner';
|
|
12
|
+
function clearConsent() {
|
|
13
|
+
try {
|
|
14
|
+
localStorage.removeItem('clarityConsent');
|
|
15
|
+
document.cookie = 'clarityConsent=; Max-Age=0; path=/';
|
|
16
|
+
}
|
|
17
|
+
catch (_a) {
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function cleanupClarityScripts() {
|
|
21
|
+
document
|
|
22
|
+
.querySelectorAll('script[src*="clarity.ms"]')
|
|
23
|
+
.forEach((s) => { var _a; return (_a = s.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(s); });
|
|
24
|
+
if (window.clarity) {
|
|
25
|
+
delete window.clarity;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const meta = {
|
|
29
|
+
title: 'Components/ConsentBanner',
|
|
30
|
+
component: ConsentBanner,
|
|
31
|
+
argTypes: {
|
|
32
|
+
clarityProjectId: { control: 'text' },
|
|
33
|
+
countryCode: { control: 'text' },
|
|
34
|
+
autoDetect: { control: 'boolean' },
|
|
35
|
+
geoEndpoint: { control: 'text' },
|
|
36
|
+
storageKey: { control: 'text' },
|
|
37
|
+
},
|
|
38
|
+
decorators: [
|
|
39
|
+
(Story) => {
|
|
40
|
+
clearConsent();
|
|
41
|
+
cleanupClarityScripts();
|
|
42
|
+
const containerStyle = {
|
|
43
|
+
minHeight: 180,
|
|
44
|
+
border: '1px dashed #ccc',
|
|
45
|
+
padding: 16,
|
|
46
|
+
position: 'relative',
|
|
47
|
+
};
|
|
48
|
+
return (_jsxs("div", Object.assign({ style: containerStyle }, { children: [_jsx("p", Object.assign({ style: { marginTop: 0 } }, { children: "The banner (if shown) is fixed to the bottom of the viewport." })), _jsx(Story, {})] })));
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
parameters: {
|
|
52
|
+
layout: 'fullscreen',
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
export default meta;
|
|
56
|
+
export const EEA_Shows = {
|
|
57
|
+
name: 'EEA (DE) → Banner shows',
|
|
58
|
+
args: {
|
|
59
|
+
clarityProjectId: 'CLARITY_PROJECT_ID',
|
|
60
|
+
countryCode: 'DE',
|
|
61
|
+
autoDetect: false,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
export const NonEEA_Hides = {
|
|
65
|
+
name: 'Non-EEA (US) → No banner',
|
|
66
|
+
args: {
|
|
67
|
+
clarityProjectId: 'CLARITY_PROJECT_ID',
|
|
68
|
+
countryCode: 'US',
|
|
69
|
+
autoDetect: false,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
export const AcceptFlow = {
|
|
73
|
+
name: 'Accept flow (DE)',
|
|
74
|
+
args: {
|
|
75
|
+
clarityProjectId: 'CLARITY_PROJECT_ID',
|
|
76
|
+
countryCode: 'DE',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
export const DenyFlow = {
|
|
80
|
+
name: 'Deny flow (DE)',
|
|
81
|
+
args: {
|
|
82
|
+
clarityProjectId: 'CLARITY_PROJECT_ID',
|
|
83
|
+
countryCode: 'DE',
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
export const AutoDetect_FetchMock = {
|
|
87
|
+
name: 'Auto-detect (fetch override → DE)',
|
|
88
|
+
args: {
|
|
89
|
+
clarityProjectId: 'CLARITY_PROJECT_ID',
|
|
90
|
+
autoDetect: true,
|
|
91
|
+
geoEndpoint: '/api/geo',
|
|
92
|
+
},
|
|
93
|
+
decorators: [
|
|
94
|
+
(Story) => {
|
|
95
|
+
const g = global;
|
|
96
|
+
const originalFetch = g.fetch;
|
|
97
|
+
g.fetch = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
98
|
+
return ({
|
|
99
|
+
text: () => __awaiter(void 0, void 0, void 0, function* () { return 'DE'; }),
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
const node = _jsx(Story, {});
|
|
103
|
+
queueMicrotask(() => {
|
|
104
|
+
g.fetch = originalFetch;
|
|
105
|
+
});
|
|
106
|
+
return node;
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
12
|
+
import userEvent from '@testing-library/user-event';
|
|
13
|
+
import { ConsentBanner } from './consentBanner';
|
|
14
|
+
function cleanupClarityScripts() {
|
|
15
|
+
document
|
|
16
|
+
.querySelectorAll('script[src*="clarity.ms"]')
|
|
17
|
+
.forEach((s) => { var _a; return (_a = s.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(s); });
|
|
18
|
+
}
|
|
19
|
+
function resetConsent() {
|
|
20
|
+
try {
|
|
21
|
+
localStorage.removeItem('clarityConsent');
|
|
22
|
+
}
|
|
23
|
+
catch (_a) { }
|
|
24
|
+
document.cookie = 'clarityConsent=; Max-Age=0; path=/';
|
|
25
|
+
cleanupClarityScripts();
|
|
26
|
+
if (window.clarity)
|
|
27
|
+
delete window.clarity;
|
|
28
|
+
}
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
resetConsent();
|
|
31
|
+
});
|
|
32
|
+
describe('ConsentBanner', () => {
|
|
33
|
+
test('shows banner for EEA country (DE) when no prior decision', () => {
|
|
34
|
+
render(_jsx(ConsentBanner, { clarityProjectId: "PID", countryCode: "DE", autoDetect: false }));
|
|
35
|
+
expect(screen.getByRole('dialog', { name: /consent for analytics/i })).toBeInTheDocument();
|
|
36
|
+
expect(screen.getByRole('button', { name: /accept/i })).toBeInTheDocument();
|
|
37
|
+
expect(screen.getByRole('button', { name: /deny/i })).toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
test('does not show banner for non-EEA country (US)', () => {
|
|
40
|
+
render(_jsx(ConsentBanner, { clarityProjectId: "PID", countryCode: "US", autoDetect: false }));
|
|
41
|
+
expect(screen.queryByRole('dialog', { name: /consent for analytics/i })).not.toBeInTheDocument();
|
|
42
|
+
});
|
|
43
|
+
test('clicking Deny stores decision and hides banner (no script injected)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
44
|
+
const user = userEvent.setup();
|
|
45
|
+
render(_jsx(ConsentBanner, { clarityProjectId: "PID", countryCode: "DE" }));
|
|
46
|
+
const deny = yield screen.findByRole('button', { name: /deny/i });
|
|
47
|
+
yield user.click(deny);
|
|
48
|
+
yield waitFor(() => expect(screen.queryByRole('dialog', { name: /consent for analytics/i })).not.toBeInTheDocument());
|
|
49
|
+
expect(localStorage.getItem('clarityConsent')).toBe('false');
|
|
50
|
+
expect(document.querySelector('script[src*="clarity.ms"]')).not.toBeInTheDocument();
|
|
51
|
+
}));
|
|
52
|
+
test('autoDetect fetch → banner shows for mocked DE (runner-agnostic)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
53
|
+
const originalFetch = globalThis.fetch;
|
|
54
|
+
globalThis.fetch = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
|
+
return ({
|
|
56
|
+
text: () => __awaiter(void 0, void 0, void 0, function* () { return 'DE'; }),
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
try {
|
|
60
|
+
render(_jsx(ConsentBanner, { clarityProjectId: "PID", autoDetect: true }));
|
|
61
|
+
yield waitFor(() => expect(screen.getByRole('dialog', { name: /consent for analytics/i })).toBeInTheDocument());
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
;
|
|
65
|
+
globalThis.fetch = originalFetch;
|
|
66
|
+
}
|
|
67
|
+
}));
|
|
68
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
type ConsentBannerProps = {
|
|
3
|
+
clarityProjectId: string;
|
|
4
|
+
countryCode?: string | null;
|
|
5
|
+
autoDetect?: boolean;
|
|
6
|
+
geoEndpoint?: string;
|
|
7
|
+
storageKey?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: React.CSSProperties;
|
|
10
|
+
onConsentChange?: (consented: boolean) => void;
|
|
11
|
+
};
|
|
12
|
+
export declare const ConsentBanner: React.FC<ConsentBannerProps>;
|
|
13
|
+
export default ConsentBanner;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
+
import React from 'react';
|
|
12
|
+
const EEA_UK_CH = new Set([
|
|
13
|
+
'AT',
|
|
14
|
+
'BE',
|
|
15
|
+
'BG',
|
|
16
|
+
'HR',
|
|
17
|
+
'CY',
|
|
18
|
+
'CZ',
|
|
19
|
+
'DK',
|
|
20
|
+
'EE',
|
|
21
|
+
'FI',
|
|
22
|
+
'FR',
|
|
23
|
+
'DE',
|
|
24
|
+
'GR',
|
|
25
|
+
'HU',
|
|
26
|
+
'IS',
|
|
27
|
+
'IE',
|
|
28
|
+
'IT',
|
|
29
|
+
'LV',
|
|
30
|
+
'LI',
|
|
31
|
+
'LT',
|
|
32
|
+
'LU',
|
|
33
|
+
'MT',
|
|
34
|
+
'NL',
|
|
35
|
+
'NO',
|
|
36
|
+
'PL',
|
|
37
|
+
'PT',
|
|
38
|
+
'RO',
|
|
39
|
+
'SK',
|
|
40
|
+
'SI',
|
|
41
|
+
'ES',
|
|
42
|
+
'SE',
|
|
43
|
+
'GB',
|
|
44
|
+
'CH',
|
|
45
|
+
]);
|
|
46
|
+
const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
47
|
+
function getStoredDecision(key) {
|
|
48
|
+
var _a, _b, _c;
|
|
49
|
+
if (!isBrowser)
|
|
50
|
+
return null;
|
|
51
|
+
try {
|
|
52
|
+
const v = (_c = (_a = localStorage.getItem(key)) !== null && _a !== void 0 ? _a : (_b = document.cookie.match(new RegExp(`${key}=([^;]+)`))) === null || _b === void 0 ? void 0 : _b[1]) !== null && _c !== void 0 ? _c : null;
|
|
53
|
+
if (v === 'true')
|
|
54
|
+
return true;
|
|
55
|
+
if (v === 'false')
|
|
56
|
+
return false;
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
catch (_d) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function setStoredDecision(key, val) {
|
|
64
|
+
if (!isBrowser)
|
|
65
|
+
return;
|
|
66
|
+
try {
|
|
67
|
+
localStorage.setItem(key, String(val));
|
|
68
|
+
}
|
|
69
|
+
catch (_a) {
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const days = 180;
|
|
73
|
+
const expires = new Date(Date.now() + days * 864e5).toUTCString();
|
|
74
|
+
document.cookie = `${key}=${val}; path=/; SameSite=Lax; expires=${expires}`;
|
|
75
|
+
}
|
|
76
|
+
catch (_b) {
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function loadClarity(clarityProjectId) {
|
|
80
|
+
if (!isBrowser)
|
|
81
|
+
return;
|
|
82
|
+
const w = window;
|
|
83
|
+
if (typeof w.clarity === 'function')
|
|
84
|
+
return;
|
|
85
|
+
w.clarity = (...args) => {
|
|
86
|
+
w.clarity.q = w.clarity.q || [];
|
|
87
|
+
w.clarity.q.push(args);
|
|
88
|
+
};
|
|
89
|
+
const t = document.createElement('script');
|
|
90
|
+
t.async = true;
|
|
91
|
+
t.src = `https://www.clarity.ms/tag/${clarityProjectId}`;
|
|
92
|
+
const scripts = document.getElementsByTagName('script');
|
|
93
|
+
const y = scripts && scripts.length ? scripts[0] : null;
|
|
94
|
+
if (y && y.parentNode) {
|
|
95
|
+
y.parentNode.insertBefore(t, y);
|
|
96
|
+
}
|
|
97
|
+
else if (document.head) {
|
|
98
|
+
document.head.appendChild(t);
|
|
99
|
+
}
|
|
100
|
+
else if (document.body) {
|
|
101
|
+
document.body.appendChild(t);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
document.documentElement.appendChild(t);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export const ConsentBanner = ({ clarityProjectId, countryCode = null, autoDetect = false, geoEndpoint, storageKey = 'clarityConsent', className, style, onConsentChange, }) => {
|
|
108
|
+
const [shouldShow, setShouldShow] = React.useState(false);
|
|
109
|
+
const [resolvedCountry, setResolvedCountry] = React.useState(countryCode);
|
|
110
|
+
React.useEffect(() => {
|
|
111
|
+
if (!isBrowser)
|
|
112
|
+
return;
|
|
113
|
+
const prior = getStoredDecision(storageKey);
|
|
114
|
+
if (prior === true) {
|
|
115
|
+
try {
|
|
116
|
+
loadClarity(clarityProjectId);
|
|
117
|
+
}
|
|
118
|
+
catch (_a) {
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}, [clarityProjectId, storageKey]);
|
|
122
|
+
React.useEffect(() => {
|
|
123
|
+
if (countryCode) {
|
|
124
|
+
setResolvedCountry(countryCode.toUpperCase());
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!autoDetect || !isBrowser)
|
|
128
|
+
return;
|
|
129
|
+
const endpoint = geoEndpoint || 'https://ipapi.co/country/';
|
|
130
|
+
let cancelled = false;
|
|
131
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
132
|
+
try {
|
|
133
|
+
const res = yield fetch(endpoint, { credentials: 'omit' });
|
|
134
|
+
const text = (yield res.text()).trim().slice(0, 2).toUpperCase();
|
|
135
|
+
if (!cancelled && /^[A-Z]{2}$/.test(text)) {
|
|
136
|
+
setResolvedCountry(text);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (_a) {
|
|
140
|
+
}
|
|
141
|
+
}))();
|
|
142
|
+
return () => {
|
|
143
|
+
cancelled = true;
|
|
144
|
+
};
|
|
145
|
+
}, [autoDetect, geoEndpoint, countryCode]);
|
|
146
|
+
React.useEffect(() => {
|
|
147
|
+
if (!isBrowser)
|
|
148
|
+
return;
|
|
149
|
+
const prior = getStoredDecision(storageKey);
|
|
150
|
+
if (prior !== null) {
|
|
151
|
+
setShouldShow(false);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (!resolvedCountry) {
|
|
155
|
+
setShouldShow(false);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
setShouldShow(EEA_UK_CH.has(resolvedCountry));
|
|
159
|
+
}, [resolvedCountry, storageKey]);
|
|
160
|
+
const handleAccept = () => {
|
|
161
|
+
setStoredDecision(storageKey, true);
|
|
162
|
+
setShouldShow(false);
|
|
163
|
+
onConsentChange === null || onConsentChange === void 0 ? void 0 : onConsentChange(true);
|
|
164
|
+
try {
|
|
165
|
+
loadClarity(clarityProjectId);
|
|
166
|
+
}
|
|
167
|
+
catch (_a) {
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const handleDeny = () => {
|
|
171
|
+
setStoredDecision(storageKey, false);
|
|
172
|
+
setShouldShow(false);
|
|
173
|
+
onConsentChange === null || onConsentChange === void 0 ? void 0 : onConsentChange(false);
|
|
174
|
+
};
|
|
175
|
+
if (!shouldShow)
|
|
176
|
+
return null;
|
|
177
|
+
return (_jsxs("div", Object.assign({ role: "dialog", "aria-live": "polite", "aria-label": "Consent for analytics", className: className, style: Object.assign({ position: 'fixed', bottom: 0, left: 0, right: 0, zIndex: 99999, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '0.75rem', padding: '0.9rem 1rem', background: 'rgba(17, 24, 39, 0.98)', color: 'white', boxShadow: '0 -6px 24px rgba(0,0,0,0.25)', flexWrap: 'wrap' }, style) }, { children: [_jsx("p", Object.assign({ style: {
|
|
178
|
+
fontFamily: 'Arial, sans-serif',
|
|
179
|
+
textAlign: 'center',
|
|
180
|
+
margin: 0,
|
|
181
|
+
lineHeight: 1.4,
|
|
182
|
+
flex: '1 1 420px',
|
|
183
|
+
} }, { children: "We use Microsoft Clarity to improve our site. Do you consent to analytics cookies?" })), _jsxs("div", Object.assign({ style: { display: 'flex', gap: '0.5rem', flexShrink: 0 } }, { children: [_jsx("button", Object.assign({ onClick: handleDeny, type: "button", style: {
|
|
184
|
+
border: '1px solid rgba(255,255,255,0.65)',
|
|
185
|
+
background: 'transparent',
|
|
186
|
+
color: 'white',
|
|
187
|
+
padding: '0.6rem 0.9rem',
|
|
188
|
+
borderRadius: 8,
|
|
189
|
+
cursor: 'pointer',
|
|
190
|
+
fontWeight: 600,
|
|
191
|
+
} }, { children: "Deny" })), _jsx("button", Object.assign({ onClick: handleAccept, type: "button", style: {
|
|
192
|
+
border: 'none',
|
|
193
|
+
background: 'white',
|
|
194
|
+
color: '#111827',
|
|
195
|
+
padding: '0.6rem 0.9rem',
|
|
196
|
+
borderRadius: 8,
|
|
197
|
+
cursor: 'pointer',
|
|
198
|
+
fontWeight: 700,
|
|
199
|
+
} }, { children: "Accept" }))] }))] })));
|
|
200
|
+
};
|
|
201
|
+
export default ConsentBanner;
|