@ndlib/component-library 1.0.26 → 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/Alerts/index.js +1 -1
- 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/dist/components/providers/alerts.d.ts +1 -1
- package/dist/components/providers/alerts.js +13 -21
- package/dist/components/providers/alerts.test.js +7 -7
- package/package.json +1 -1
|
@@ -32,7 +32,7 @@ export const Alerts = (_a) => {
|
|
|
32
32
|
return (_jsx(Box, Object.assign({}, rest, { children: alerts.map((alert, i) => {
|
|
33
33
|
const { type, description } = alert;
|
|
34
34
|
return (_jsx(Alert, { type: type, description: description, "data-nosnippet": true, sx: Object.assign({ mt: i ? '4px' : 0 }, alertStyles), dismiss: () => {
|
|
35
|
-
dismiss(alert.
|
|
35
|
+
dismiss(alert.id);
|
|
36
36
|
} }, i));
|
|
37
37
|
}) })));
|
|
38
38
|
};
|
|
@@ -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;
|
|
@@ -41,6 +41,7 @@ const composeGraphqlQuery = ({ startTime, endTime, }) => {
|
|
|
41
41
|
sort: ["type:desc", "startTime:asc"]
|
|
42
42
|
) {
|
|
43
43
|
data {
|
|
44
|
+
id
|
|
44
45
|
attributes {
|
|
45
46
|
title
|
|
46
47
|
description
|
|
@@ -53,8 +54,8 @@ const composeGraphqlQuery = ({ startTime, endTime, }) => {
|
|
|
53
54
|
}
|
|
54
55
|
`,
|
|
55
56
|
variables: {
|
|
56
|
-
startTime
|
|
57
|
-
endTime
|
|
57
|
+
startTime,
|
|
58
|
+
endTime,
|
|
58
59
|
},
|
|
59
60
|
});
|
|
60
61
|
};
|
|
@@ -63,22 +64,16 @@ const useAlertsQuery = ({ domain = ALERT_DOMAIN.LIBRARY, endpoint = DEFAULT_ENDP
|
|
|
63
64
|
const [alerts, setAlerts] = useState([]);
|
|
64
65
|
useEffect(() => {
|
|
65
66
|
const fetchData = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
66
|
-
var _a, _b
|
|
67
|
+
var _a, _b;
|
|
67
68
|
try {
|
|
68
|
-
const myHeaders = new Headers();
|
|
69
|
-
myHeaders.append('Content-Type', 'application/json');
|
|
70
69
|
const response = yield fetch(endpoint, {
|
|
71
70
|
method: 'POST',
|
|
72
|
-
headers:
|
|
73
|
-
body: composeGraphqlQuery({
|
|
74
|
-
startTime,
|
|
75
|
-
endTime,
|
|
76
|
-
}),
|
|
77
|
-
redirect: 'follow',
|
|
71
|
+
headers: { 'Content-Type': 'application/json' },
|
|
72
|
+
body: composeGraphqlQuery({ startTime, endTime }),
|
|
78
73
|
});
|
|
79
74
|
const json = yield response.json();
|
|
80
75
|
if ((_b = (_a = json === null || json === void 0 ? void 0 : json.data) === null || _a === void 0 ? void 0 : _a.alerts) === null || _b === void 0 ? void 0 : _b.data) {
|
|
81
|
-
const results =
|
|
76
|
+
const results = json.data.alerts.data.map((a) => (Object.assign({ id: a.id }, a.attributes)));
|
|
82
77
|
setAlerts(results);
|
|
83
78
|
}
|
|
84
79
|
}
|
|
@@ -110,23 +105,20 @@ export const AlertsProvider = ({ domain = ALERT_DOMAIN.LIBRARY, endpoint, startT
|
|
|
110
105
|
const [dismissedAlerts, setDismissedAlerts] = useState(storedDismissedAlerts ? JSON.parse(storedDismissedAlerts) : []);
|
|
111
106
|
const dismiss = (id) => {
|
|
112
107
|
if (!dismissedAlerts.includes(id)) {
|
|
113
|
-
const newDismissed = dismissedAlerts
|
|
108
|
+
const newDismissed = [...dismissedAlerts, id];
|
|
114
109
|
storage.setItem(DISMISSED_ALERTS_STORAGE_KEY, JSON.stringify(newDismissed));
|
|
115
110
|
setDismissedAlerts(newDismissed);
|
|
116
111
|
}
|
|
117
112
|
};
|
|
118
113
|
const filteredAlerts = alerts
|
|
119
|
-
.filter((alert) => !dismissedAlerts.includes(alert.
|
|
114
|
+
.filter((alert) => !dismissedAlerts.includes(alert.id))
|
|
120
115
|
.filter((alert) => { var _a; return (_a = alert === null || alert === void 0 ? void 0 : alert.domains) === null || _a === void 0 ? void 0 : _a.includes(domain); });
|
|
121
|
-
return (_jsx(AlertsContext.Provider, Object.assign({ value: {
|
|
122
|
-
alerts: filteredAlerts,
|
|
123
|
-
dismiss,
|
|
124
|
-
} }, { children: children })));
|
|
116
|
+
return (_jsx(AlertsContext.Provider, Object.assign({ value: { alerts: filteredAlerts, dismiss } }, { children: children })));
|
|
125
117
|
};
|
|
126
|
-
export const useAlerts = (pageAlerts) => {
|
|
118
|
+
export const useAlerts = (pageAlerts = []) => {
|
|
127
119
|
const { alerts: allAlerts, dismiss } = React.useContext(AlertsContext);
|
|
128
|
-
const alerts = pageAlerts
|
|
129
|
-
? allAlerts.filter((alert) => alert.global || pageAlerts.includes(alert.
|
|
120
|
+
const alerts = pageAlerts.length > 0
|
|
121
|
+
? allAlerts.filter((alert) => alert.global || pageAlerts.includes(alert.id))
|
|
130
122
|
: allAlerts.filter((alert) => alert.global);
|
|
131
123
|
return {
|
|
132
124
|
alerts,
|
|
@@ -18,7 +18,7 @@ describe('AlertsProvider and useAlerts', () => {
|
|
|
18
18
|
});
|
|
19
19
|
const mockAlerts = [
|
|
20
20
|
{
|
|
21
|
-
|
|
21
|
+
id: '1',
|
|
22
22
|
domains: ['library'],
|
|
23
23
|
startTime: '2020-09-06T04:00:00.000Z',
|
|
24
24
|
endTime: '2020-09-09T04:00:00.000Z',
|
|
@@ -28,7 +28,7 @@ describe('AlertsProvider and useAlerts', () => {
|
|
|
28
28
|
global: true,
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
|
-
|
|
31
|
+
id: '2',
|
|
32
32
|
title: 'Test Alert 2',
|
|
33
33
|
type: 'Warning',
|
|
34
34
|
description: 'Issue with Primo',
|
|
@@ -36,7 +36,7 @@ describe('AlertsProvider and useAlerts', () => {
|
|
|
36
36
|
global: false,
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
|
-
|
|
39
|
+
id: '3',
|
|
40
40
|
domains: ['library'],
|
|
41
41
|
startTime: '2020-09-06T04:00:00.000Z',
|
|
42
42
|
endTime: '2020-09-09T04:00:00.000Z',
|
|
@@ -61,7 +61,7 @@ describe('AlertsProvider and useAlerts', () => {
|
|
|
61
61
|
});
|
|
62
62
|
const TestComponent = () => {
|
|
63
63
|
const { alerts } = useAlerts();
|
|
64
|
-
return (_jsx("div", { children: alerts.map((alert) => (_jsx("div", { children: alert.title }, alert.
|
|
64
|
+
return (_jsx("div", { children: alerts.map((alert) => (_jsx("div", { children: alert.title }, alert.id))) }));
|
|
65
65
|
};
|
|
66
66
|
render(_jsx(AlertsProvider, { children: _jsx(TestComponent, {}) }));
|
|
67
67
|
yield waitFor(() => {
|
|
@@ -77,7 +77,7 @@ describe('AlertsProvider and useAlerts', () => {
|
|
|
77
77
|
const { alerts } = useAlerts();
|
|
78
78
|
return (_jsx("div", { children: alerts.length === 0
|
|
79
79
|
? 'No Alerts'
|
|
80
|
-
: alerts.map((alert) => _jsx("div", { children: alert.title }, alert.
|
|
80
|
+
: alerts.map((alert) => _jsx("div", { children: alert.title }, alert.id)) }));
|
|
81
81
|
};
|
|
82
82
|
render(_jsx(AlertsProvider, { children: _jsx(TestComponent, {}) }));
|
|
83
83
|
yield waitFor(() => {
|
|
@@ -92,7 +92,7 @@ describe('AlertsProvider and useAlerts', () => {
|
|
|
92
92
|
const { alerts } = useAlerts();
|
|
93
93
|
return (_jsx("div", { children: alerts.length === 0
|
|
94
94
|
? 'No Alerts'
|
|
95
|
-
: alerts.map((alert) => _jsx("div", { children: alert.title }, alert.
|
|
95
|
+
: alerts.map((alert) => _jsx("div", { children: alert.title }, alert.id)) }));
|
|
96
96
|
};
|
|
97
97
|
render(_jsx(AlertsProvider, { children: _jsx(TestComponent, {}) }));
|
|
98
98
|
yield waitFor(() => {
|
|
@@ -105,7 +105,7 @@ describe('AlertsProvider and useAlerts', () => {
|
|
|
105
105
|
const { alerts } = useAlerts();
|
|
106
106
|
return (_jsx("div", { children: alerts.length === 0
|
|
107
107
|
? 'No Alerts'
|
|
108
|
-
: alerts.map((alert) => _jsx("div", { children: alert.title }, alert.
|
|
108
|
+
: alerts.map((alert) => _jsx("div", { children: alert.title }, alert.id)) }));
|
|
109
109
|
};
|
|
110
110
|
render(_jsx(AlertsProvider, { children: _jsx(TestComponent, {}) }));
|
|
111
111
|
yield waitFor(() => {
|