@redacto.io/consent-sdk-react 9.4.0 → 10.0.0-beta.0
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/CHANGELOG.md +6 -0
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +122 -15
- package/dist/index.mjs +122 -15
- package/dist/privacy-center.d.mts +31 -7
- package/dist/privacy-center.d.ts +31 -7
- package/dist/privacy-center.js +187 -44
- package/dist/privacy-center.mjs +187 -44
- package/package.json +1 -1
- package/src/RedactoNoticeConsent/RedactoNoticeConsent.test.tsx +5 -0
- package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +29 -4
- package/src/RedactoNoticeConsent/api/index.ts +131 -2
- package/src/RedactoNoticeConsent/api/types.ts +33 -1
- package/src/RedactoNoticeConsent/types.ts +1 -0
- package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +3 -1
- package/src/RedactoNoticeConsentInline/api/index.ts +5 -2
- package/src/RedactoNoticeConsentInline/api/types.ts +1 -1
- package/src/RedactoNoticeConsentInline/types.ts +1 -0
- package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +6 -4
- package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +3 -1
- package/src/RedactoPrivacyCenter/api/actions.ts +10 -3
- package/src/RedactoPrivacyCenter/api/client.ts +67 -21
- package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +12 -1
- package/src/RedactoPrivacyCenter/components/Form.tsx +58 -6
- package/src/RedactoPrivacyCenter/components/groupHelpers.ts +64 -1
- package/src/RedactoPrivacyCenter/context/AuthContext.tsx +7 -5
- package/src/RedactoPrivacyCenter/context/BaseUrlContext.tsx +8 -2
- package/src/RedactoPrivacyCenter/context/types.ts +1 -0
- package/src/RedactoPrivacyCenter/lib/api.ts +8 -0
- package/src/RedactoPrivacyCenter/lib/constants.ts +9 -0
- package/src/RedactoPrivacyCenter/lib/types.ts +11 -1
- package/src/RedactoPrivacyCenter/lib/utils.ts +28 -0
- package/tests/Form.test.tsx +5 -0
- package/tests/mocks.ts +1 -0
- package/tests/resolveContactFromJwt.test.ts +44 -0
package/CHANGELOG.md
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -47,6 +47,7 @@ type Props$1 = Readonly<{
|
|
|
47
47
|
accessToken: string;
|
|
48
48
|
refreshToken: string;
|
|
49
49
|
baseUrl?: string;
|
|
50
|
+
ledgerBaseUrl: string;
|
|
50
51
|
settings?: Partial<Settings$1>;
|
|
51
52
|
language?: string;
|
|
52
53
|
blockUI?: boolean;
|
|
@@ -68,7 +69,7 @@ type Props$1 = Readonly<{
|
|
|
68
69
|
* to view and manage their consent preferences. Supports both initial consent
|
|
69
70
|
* collection and reconsent flows.
|
|
70
71
|
*/
|
|
71
|
-
declare const RedactoNoticeConsent: ({ noticeId, accessToken, refreshToken, baseUrl, language, blockUI, onAccept, onDecline, onError, settings, applicationId, validateAgainst, digilockerMode, digilockerCallbackUrl, includeFullyConsentedData, reviewModeButtonText, }: Props$1) => react_jsx_runtime.JSX.Element;
|
|
72
|
+
declare const RedactoNoticeConsent: ({ noticeId, accessToken, refreshToken, baseUrl, ledgerBaseUrl, language, blockUI, onAccept, onDecline, onError, settings, applicationId, validateAgainst, digilockerMode, digilockerCallbackUrl, includeFullyConsentedData, reviewModeButtonText, }: Props$1) => react_jsx_runtime.JSX.Element;
|
|
72
73
|
|
|
73
74
|
type Settings = {
|
|
74
75
|
button: {
|
|
@@ -102,6 +103,7 @@ type Props = Readonly<{
|
|
|
102
103
|
accessToken?: string;
|
|
103
104
|
refreshToken?: string;
|
|
104
105
|
baseUrl?: string;
|
|
106
|
+
ledgerBaseUrl: string;
|
|
105
107
|
settings?: Partial<Settings>;
|
|
106
108
|
language?: string;
|
|
107
109
|
onAccept?: () => void;
|
|
@@ -112,7 +114,7 @@ type Props = Readonly<{
|
|
|
112
114
|
}>;
|
|
113
115
|
|
|
114
116
|
declare const RedactoConsentInline: react.MemoExoticComponent<{
|
|
115
|
-
({ org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl, language, onAccept, onError, onValidationChange, settings, applicationId, }: Props): react_jsx_runtime.JSX.Element | null;
|
|
117
|
+
({ org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl, ledgerBaseUrl, language, onAccept, onError, onValidationChange, settings, applicationId, }: Props): react_jsx_runtime.JSX.Element | null;
|
|
116
118
|
displayName: string;
|
|
117
119
|
}>;
|
|
118
120
|
|
package/dist/index.d.ts
CHANGED
|
@@ -47,6 +47,7 @@ type Props$1 = Readonly<{
|
|
|
47
47
|
accessToken: string;
|
|
48
48
|
refreshToken: string;
|
|
49
49
|
baseUrl?: string;
|
|
50
|
+
ledgerBaseUrl: string;
|
|
50
51
|
settings?: Partial<Settings$1>;
|
|
51
52
|
language?: string;
|
|
52
53
|
blockUI?: boolean;
|
|
@@ -68,7 +69,7 @@ type Props$1 = Readonly<{
|
|
|
68
69
|
* to view and manage their consent preferences. Supports both initial consent
|
|
69
70
|
* collection and reconsent flows.
|
|
70
71
|
*/
|
|
71
|
-
declare const RedactoNoticeConsent: ({ noticeId, accessToken, refreshToken, baseUrl, language, blockUI, onAccept, onDecline, onError, settings, applicationId, validateAgainst, digilockerMode, digilockerCallbackUrl, includeFullyConsentedData, reviewModeButtonText, }: Props$1) => react_jsx_runtime.JSX.Element;
|
|
72
|
+
declare const RedactoNoticeConsent: ({ noticeId, accessToken, refreshToken, baseUrl, ledgerBaseUrl, language, blockUI, onAccept, onDecline, onError, settings, applicationId, validateAgainst, digilockerMode, digilockerCallbackUrl, includeFullyConsentedData, reviewModeButtonText, }: Props$1) => react_jsx_runtime.JSX.Element;
|
|
72
73
|
|
|
73
74
|
type Settings = {
|
|
74
75
|
button: {
|
|
@@ -102,6 +103,7 @@ type Props = Readonly<{
|
|
|
102
103
|
accessToken?: string;
|
|
103
104
|
refreshToken?: string;
|
|
104
105
|
baseUrl?: string;
|
|
106
|
+
ledgerBaseUrl: string;
|
|
105
107
|
settings?: Partial<Settings>;
|
|
106
108
|
language?: string;
|
|
107
109
|
onAccept?: () => void;
|
|
@@ -112,7 +114,7 @@ type Props = Readonly<{
|
|
|
112
114
|
}>;
|
|
113
115
|
|
|
114
116
|
declare const RedactoConsentInline: react.MemoExoticComponent<{
|
|
115
|
-
({ org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl, language, onAccept, onError, onValidationChange, settings, applicationId, }: Props): react_jsx_runtime.JSX.Element | null;
|
|
117
|
+
({ org_uuid, workspace_uuid, notice_uuid, accessToken, baseUrl, ledgerBaseUrl, language, onAccept, onError, onValidationChange, settings, applicationId, }: Props): react_jsx_runtime.JSX.Element | null;
|
|
116
118
|
displayName: string;
|
|
117
119
|
}>;
|
|
118
120
|
|
package/dist/index.js
CHANGED
|
@@ -181,7 +181,7 @@ var fetchConsentContent = async ({
|
|
|
181
181
|
};
|
|
182
182
|
var submitConsentEvent = async ({
|
|
183
183
|
accessToken,
|
|
184
|
-
|
|
184
|
+
ledgerBaseUrl,
|
|
185
185
|
noticeUuid,
|
|
186
186
|
purposes,
|
|
187
187
|
declined,
|
|
@@ -202,7 +202,10 @@ var submitConsentEvent = async ({
|
|
|
202
202
|
if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
|
|
203
203
|
throw new Error("Invalid token: missing organization or workspace UUID");
|
|
204
204
|
}
|
|
205
|
-
|
|
205
|
+
if (!ledgerBaseUrl) {
|
|
206
|
+
throw new Error("ledgerBaseUrl is required to submit consent");
|
|
207
|
+
}
|
|
208
|
+
const apiBaseUrl = ledgerBaseUrl;
|
|
206
209
|
const validatedPurposes = purposes.map((purpose) => {
|
|
207
210
|
if (!purpose.uuid) {
|
|
208
211
|
throw new Error(`Invalid purpose data: missing uuid`);
|
|
@@ -248,6 +251,88 @@ var submitConsentEvent = async ({
|
|
|
248
251
|
}
|
|
249
252
|
apiCache.clear();
|
|
250
253
|
};
|
|
254
|
+
var fetchNoticeConsentStatus = async ({
|
|
255
|
+
accessToken,
|
|
256
|
+
ledgerBaseUrl,
|
|
257
|
+
noticeUuid,
|
|
258
|
+
signal
|
|
259
|
+
}) => {
|
|
260
|
+
if (!accessToken || !ledgerBaseUrl || !noticeUuid) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
const decodedToken = decodeTokenSafely(accessToken);
|
|
264
|
+
if (!decodedToken) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
|
|
268
|
+
if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
const response = await fetch(
|
|
273
|
+
`${ledgerBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeUuid}/check-consent`,
|
|
274
|
+
{
|
|
275
|
+
method: "POST",
|
|
276
|
+
headers: {
|
|
277
|
+
Authorization: `Bearer ${accessToken}`,
|
|
278
|
+
"Content-Type": "application/json"
|
|
279
|
+
},
|
|
280
|
+
body: "{}",
|
|
281
|
+
signal
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
if (!response.ok) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
const data = await response.json();
|
|
288
|
+
const body = data && typeof data === "object" && "detail" in data && data.detail ? data.detail : data;
|
|
289
|
+
if (!body || !Array.isArray(body.purposes)) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
return body;
|
|
293
|
+
} catch {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
var buildLedgerConsentOverlay = (status, configPurposes) => {
|
|
298
|
+
var _a, _b;
|
|
299
|
+
const byUuid = new Map(status.purposes.map((p) => [p.uuid, p]));
|
|
300
|
+
const hasHistory = status.purposes.some(
|
|
301
|
+
(p) => (p.status || "INACTIVE") !== "INACTIVE"
|
|
302
|
+
);
|
|
303
|
+
if (!hasHistory) {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
const purpose_selections = {};
|
|
307
|
+
for (const cp of configPurposes) {
|
|
308
|
+
const lp = byUuid.get(cp.uuid);
|
|
309
|
+
const purposeStatus = (lp == null ? void 0 : lp.status) || "INACTIVE";
|
|
310
|
+
const selectedByUuid = new Map(
|
|
311
|
+
((lp == null ? void 0 : lp.data_elements) || []).map((de) => [de.uuid, de.selected])
|
|
312
|
+
);
|
|
313
|
+
const data_elements = {};
|
|
314
|
+
for (const de of cp.data_elements) {
|
|
315
|
+
data_elements[de.uuid] = {
|
|
316
|
+
selected: (_a = selectedByUuid.get(de.uuid)) != null ? _a : false,
|
|
317
|
+
enabled: de.enabled,
|
|
318
|
+
required: de.required
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
purpose_selections[cp.uuid] = {
|
|
322
|
+
selected: (_b = lp == null ? void 0 : lp.selected) != null ? _b : false,
|
|
323
|
+
status: purposeStatus,
|
|
324
|
+
needs_reconsent: purposeStatus !== "ACTIVE",
|
|
325
|
+
data_elements
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
const reconsent_required = configPurposes.some(
|
|
329
|
+
(cp) => {
|
|
330
|
+
var _a2;
|
|
331
|
+
return (((_a2 = purpose_selections[cp.uuid]) == null ? void 0 : _a2.status) || "INACTIVE") !== "ACTIVE";
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
return { reconsent_required, purpose_selections };
|
|
335
|
+
};
|
|
251
336
|
var fetchTTSAudioUrls = async ({
|
|
252
337
|
accessToken,
|
|
253
338
|
baseUrl,
|
|
@@ -2294,6 +2379,7 @@ var RedactoNoticeConsent = ({
|
|
|
2294
2379
|
accessToken,
|
|
2295
2380
|
refreshToken,
|
|
2296
2381
|
baseUrl,
|
|
2382
|
+
ledgerBaseUrl,
|
|
2297
2383
|
language = "en",
|
|
2298
2384
|
blockUI = true,
|
|
2299
2385
|
onAccept,
|
|
@@ -2648,7 +2734,7 @@ var RedactoNoticeConsent = ({
|
|
|
2648
2734
|
return content.dpo_info[key] || defaultText;
|
|
2649
2735
|
};
|
|
2650
2736
|
const fetchNotice = async () => {
|
|
2651
|
-
var _a2;
|
|
2737
|
+
var _a2, _b2, _c2;
|
|
2652
2738
|
if (isRequestInProgressRef.current) {
|
|
2653
2739
|
return;
|
|
2654
2740
|
}
|
|
@@ -2689,8 +2775,24 @@ var RedactoNoticeConsent = ({
|
|
|
2689
2775
|
{}
|
|
2690
2776
|
);
|
|
2691
2777
|
setCollapsedPurposes(initialCollapsedState);
|
|
2692
|
-
|
|
2693
|
-
|
|
2778
|
+
let isReconsentRequired = consentContentData.detail.reconsent_required;
|
|
2779
|
+
let purposeSelections = consentContentData.detail.purpose_selections;
|
|
2780
|
+
if (ledgerBaseUrl && !applicationId) {
|
|
2781
|
+
const ledgerStatus = await fetchNoticeConsentStatus({
|
|
2782
|
+
accessToken,
|
|
2783
|
+
ledgerBaseUrl,
|
|
2784
|
+
noticeUuid: noticeId,
|
|
2785
|
+
signal: (_b2 = abortControllerRef.current) == null ? void 0 : _b2.signal
|
|
2786
|
+
});
|
|
2787
|
+
if (ledgerStatus) {
|
|
2788
|
+
const overlay = buildLedgerConsentOverlay(
|
|
2789
|
+
ledgerStatus,
|
|
2790
|
+
activeConfig.purposes
|
|
2791
|
+
);
|
|
2792
|
+
isReconsentRequired = (_c2 = overlay == null ? void 0 : overlay.reconsent_required) != null ? _c2 : false;
|
|
2793
|
+
purposeSelections = overlay == null ? void 0 : overlay.purpose_selections;
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2694
2796
|
const newCategorizedPurposes = isReconsentRequired ? {
|
|
2695
2797
|
alreadyConsented: activeConfig.purposes.filter(
|
|
2696
2798
|
(purpose) => {
|
|
@@ -2721,9 +2823,9 @@ var RedactoNoticeConsent = ({
|
|
|
2721
2823
|
const initialDataElementState = activeConfig.purposes.reduce(
|
|
2722
2824
|
(acc, purpose) => {
|
|
2723
2825
|
purpose.data_elements.forEach((element) => {
|
|
2724
|
-
var _a3,
|
|
2826
|
+
var _a3, _b3;
|
|
2725
2827
|
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
2726
|
-
if ((
|
|
2828
|
+
if ((_b3 = (_a3 = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid]) == null ? void 0 : _a3.data_elements) == null ? void 0 : _b3[element.uuid]) {
|
|
2727
2829
|
acc[combinedId] = purposeSelections[purpose.uuid].data_elements[element.uuid].selected;
|
|
2728
2830
|
} else {
|
|
2729
2831
|
acc[combinedId] = false;
|
|
@@ -2739,9 +2841,9 @@ var RedactoNoticeConsent = ({
|
|
|
2739
2841
|
const initialSelections = {};
|
|
2740
2842
|
newCategorizedPurposes.alreadyConsented.forEach((purpose) => {
|
|
2741
2843
|
purpose.data_elements.forEach((element) => {
|
|
2742
|
-
var _a3,
|
|
2844
|
+
var _a3, _b3;
|
|
2743
2845
|
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
2744
|
-
if ((
|
|
2846
|
+
if ((_b3 = (_a3 = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid]) == null ? void 0 : _a3.data_elements) == null ? void 0 : _b3[element.uuid]) {
|
|
2745
2847
|
initialSelections[combinedId] = purposeSelections[purpose.uuid].data_elements[element.uuid].selected;
|
|
2746
2848
|
} else {
|
|
2747
2849
|
initialSelections[combinedId] = false;
|
|
@@ -2762,9 +2864,9 @@ var RedactoNoticeConsent = ({
|
|
|
2762
2864
|
activeConfig.purposes.forEach(
|
|
2763
2865
|
(purpose) => {
|
|
2764
2866
|
purpose.data_elements.forEach((element) => {
|
|
2765
|
-
var _a3,
|
|
2867
|
+
var _a3, _b3;
|
|
2766
2868
|
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
2767
|
-
if ((
|
|
2869
|
+
if ((_b3 = (_a3 = purposeSelections[purpose.uuid]) == null ? void 0 : _a3.data_elements) == null ? void 0 : _b3[element.uuid]) {
|
|
2768
2870
|
initialSelections[combinedId] = purposeSelections[purpose.uuid].data_elements[element.uuid].selected;
|
|
2769
2871
|
} else {
|
|
2770
2872
|
initialSelections[combinedId] = false;
|
|
@@ -2895,7 +2997,7 @@ var RedactoNoticeConsent = ({
|
|
|
2895
2997
|
if (content) {
|
|
2896
2998
|
await submitConsentEvent({
|
|
2897
2999
|
accessToken,
|
|
2898
|
-
|
|
3000
|
+
ledgerBaseUrl,
|
|
2899
3001
|
noticeUuid: content.notice_uuid,
|
|
2900
3002
|
purposes: content.purposes.map((purpose) => {
|
|
2901
3003
|
const isAlreadyConsented = (categorizedPurposes == null ? void 0 : categorizedPurposes.alreadyConsented.some(
|
|
@@ -4676,13 +4778,16 @@ var submitConsentEvent2 = async ({
|
|
|
4676
4778
|
org_uuid,
|
|
4677
4779
|
workspace_uuid,
|
|
4678
4780
|
accessToken,
|
|
4679
|
-
|
|
4781
|
+
ledgerBaseUrl,
|
|
4680
4782
|
noticeUuid,
|
|
4681
4783
|
purposes,
|
|
4682
4784
|
declined,
|
|
4683
4785
|
meta_data
|
|
4684
4786
|
}) => {
|
|
4685
|
-
|
|
4787
|
+
if (!ledgerBaseUrl) {
|
|
4788
|
+
throw new Error("ledgerBaseUrl is required to submit consent");
|
|
4789
|
+
}
|
|
4790
|
+
const apiBaseUrl = ledgerBaseUrl;
|
|
4686
4791
|
const payload = {
|
|
4687
4792
|
notice_uuid: noticeUuid,
|
|
4688
4793
|
purposes: purposes.map((purpose) => {
|
|
@@ -5133,6 +5238,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
5133
5238
|
notice_uuid,
|
|
5134
5239
|
accessToken,
|
|
5135
5240
|
baseUrl,
|
|
5241
|
+
ledgerBaseUrl,
|
|
5136
5242
|
language = "en",
|
|
5137
5243
|
onAccept,
|
|
5138
5244
|
onError,
|
|
@@ -5366,7 +5472,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
5366
5472
|
org_uuid,
|
|
5367
5473
|
workspace_uuid,
|
|
5368
5474
|
accessToken: tokenToUse,
|
|
5369
|
-
|
|
5475
|
+
ledgerBaseUrl,
|
|
5370
5476
|
noticeUuid: content.notice_uuid,
|
|
5371
5477
|
purposes: content.purposes.map((purpose) => {
|
|
5372
5478
|
const hasSelectedRequiredElement = purpose.data_elements.some(
|
|
@@ -5405,6 +5511,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
5405
5511
|
org_uuid,
|
|
5406
5512
|
workspace_uuid,
|
|
5407
5513
|
baseUrl,
|
|
5514
|
+
ledgerBaseUrl,
|
|
5408
5515
|
selectedDataElements,
|
|
5409
5516
|
selectedPurposes,
|
|
5410
5517
|
applicationId,
|
package/dist/index.mjs
CHANGED
|
@@ -155,7 +155,7 @@ var fetchConsentContent = async ({
|
|
|
155
155
|
};
|
|
156
156
|
var submitConsentEvent = async ({
|
|
157
157
|
accessToken,
|
|
158
|
-
|
|
158
|
+
ledgerBaseUrl,
|
|
159
159
|
noticeUuid,
|
|
160
160
|
purposes,
|
|
161
161
|
declined,
|
|
@@ -176,7 +176,10 @@ var submitConsentEvent = async ({
|
|
|
176
176
|
if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
|
|
177
177
|
throw new Error("Invalid token: missing organization or workspace UUID");
|
|
178
178
|
}
|
|
179
|
-
|
|
179
|
+
if (!ledgerBaseUrl) {
|
|
180
|
+
throw new Error("ledgerBaseUrl is required to submit consent");
|
|
181
|
+
}
|
|
182
|
+
const apiBaseUrl = ledgerBaseUrl;
|
|
180
183
|
const validatedPurposes = purposes.map((purpose) => {
|
|
181
184
|
if (!purpose.uuid) {
|
|
182
185
|
throw new Error(`Invalid purpose data: missing uuid`);
|
|
@@ -222,6 +225,88 @@ var submitConsentEvent = async ({
|
|
|
222
225
|
}
|
|
223
226
|
apiCache.clear();
|
|
224
227
|
};
|
|
228
|
+
var fetchNoticeConsentStatus = async ({
|
|
229
|
+
accessToken,
|
|
230
|
+
ledgerBaseUrl,
|
|
231
|
+
noticeUuid,
|
|
232
|
+
signal
|
|
233
|
+
}) => {
|
|
234
|
+
if (!accessToken || !ledgerBaseUrl || !noticeUuid) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
const decodedToken = decodeTokenSafely(accessToken);
|
|
238
|
+
if (!decodedToken) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
|
|
242
|
+
if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const response = await fetch(
|
|
247
|
+
`${ledgerBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeUuid}/check-consent`,
|
|
248
|
+
{
|
|
249
|
+
method: "POST",
|
|
250
|
+
headers: {
|
|
251
|
+
Authorization: `Bearer ${accessToken}`,
|
|
252
|
+
"Content-Type": "application/json"
|
|
253
|
+
},
|
|
254
|
+
body: "{}",
|
|
255
|
+
signal
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
if (!response.ok) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
const data = await response.json();
|
|
262
|
+
const body = data && typeof data === "object" && "detail" in data && data.detail ? data.detail : data;
|
|
263
|
+
if (!body || !Array.isArray(body.purposes)) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
return body;
|
|
267
|
+
} catch {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
var buildLedgerConsentOverlay = (status, configPurposes) => {
|
|
272
|
+
var _a, _b;
|
|
273
|
+
const byUuid = new Map(status.purposes.map((p) => [p.uuid, p]));
|
|
274
|
+
const hasHistory = status.purposes.some(
|
|
275
|
+
(p) => (p.status || "INACTIVE") !== "INACTIVE"
|
|
276
|
+
);
|
|
277
|
+
if (!hasHistory) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
const purpose_selections = {};
|
|
281
|
+
for (const cp of configPurposes) {
|
|
282
|
+
const lp = byUuid.get(cp.uuid);
|
|
283
|
+
const purposeStatus = (lp == null ? void 0 : lp.status) || "INACTIVE";
|
|
284
|
+
const selectedByUuid = new Map(
|
|
285
|
+
((lp == null ? void 0 : lp.data_elements) || []).map((de) => [de.uuid, de.selected])
|
|
286
|
+
);
|
|
287
|
+
const data_elements = {};
|
|
288
|
+
for (const de of cp.data_elements) {
|
|
289
|
+
data_elements[de.uuid] = {
|
|
290
|
+
selected: (_a = selectedByUuid.get(de.uuid)) != null ? _a : false,
|
|
291
|
+
enabled: de.enabled,
|
|
292
|
+
required: de.required
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
purpose_selections[cp.uuid] = {
|
|
296
|
+
selected: (_b = lp == null ? void 0 : lp.selected) != null ? _b : false,
|
|
297
|
+
status: purposeStatus,
|
|
298
|
+
needs_reconsent: purposeStatus !== "ACTIVE",
|
|
299
|
+
data_elements
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const reconsent_required = configPurposes.some(
|
|
303
|
+
(cp) => {
|
|
304
|
+
var _a2;
|
|
305
|
+
return (((_a2 = purpose_selections[cp.uuid]) == null ? void 0 : _a2.status) || "INACTIVE") !== "ACTIVE";
|
|
306
|
+
}
|
|
307
|
+
);
|
|
308
|
+
return { reconsent_required, purpose_selections };
|
|
309
|
+
};
|
|
225
310
|
var fetchTTSAudioUrls = async ({
|
|
226
311
|
accessToken,
|
|
227
312
|
baseUrl,
|
|
@@ -2241,6 +2326,7 @@ var RedactoNoticeConsent = ({
|
|
|
2241
2326
|
accessToken,
|
|
2242
2327
|
refreshToken,
|
|
2243
2328
|
baseUrl,
|
|
2329
|
+
ledgerBaseUrl,
|
|
2244
2330
|
language = "en",
|
|
2245
2331
|
blockUI = true,
|
|
2246
2332
|
onAccept,
|
|
@@ -2595,7 +2681,7 @@ var RedactoNoticeConsent = ({
|
|
|
2595
2681
|
return content.dpo_info[key] || defaultText;
|
|
2596
2682
|
};
|
|
2597
2683
|
const fetchNotice = async () => {
|
|
2598
|
-
var _a2;
|
|
2684
|
+
var _a2, _b2, _c2;
|
|
2599
2685
|
if (isRequestInProgressRef.current) {
|
|
2600
2686
|
return;
|
|
2601
2687
|
}
|
|
@@ -2636,8 +2722,24 @@ var RedactoNoticeConsent = ({
|
|
|
2636
2722
|
{}
|
|
2637
2723
|
);
|
|
2638
2724
|
setCollapsedPurposes(initialCollapsedState);
|
|
2639
|
-
|
|
2640
|
-
|
|
2725
|
+
let isReconsentRequired = consentContentData.detail.reconsent_required;
|
|
2726
|
+
let purposeSelections = consentContentData.detail.purpose_selections;
|
|
2727
|
+
if (ledgerBaseUrl && !applicationId) {
|
|
2728
|
+
const ledgerStatus = await fetchNoticeConsentStatus({
|
|
2729
|
+
accessToken,
|
|
2730
|
+
ledgerBaseUrl,
|
|
2731
|
+
noticeUuid: noticeId,
|
|
2732
|
+
signal: (_b2 = abortControllerRef.current) == null ? void 0 : _b2.signal
|
|
2733
|
+
});
|
|
2734
|
+
if (ledgerStatus) {
|
|
2735
|
+
const overlay = buildLedgerConsentOverlay(
|
|
2736
|
+
ledgerStatus,
|
|
2737
|
+
activeConfig.purposes
|
|
2738
|
+
);
|
|
2739
|
+
isReconsentRequired = (_c2 = overlay == null ? void 0 : overlay.reconsent_required) != null ? _c2 : false;
|
|
2740
|
+
purposeSelections = overlay == null ? void 0 : overlay.purpose_selections;
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2641
2743
|
const newCategorizedPurposes = isReconsentRequired ? {
|
|
2642
2744
|
alreadyConsented: activeConfig.purposes.filter(
|
|
2643
2745
|
(purpose) => {
|
|
@@ -2668,9 +2770,9 @@ var RedactoNoticeConsent = ({
|
|
|
2668
2770
|
const initialDataElementState = activeConfig.purposes.reduce(
|
|
2669
2771
|
(acc, purpose) => {
|
|
2670
2772
|
purpose.data_elements.forEach((element) => {
|
|
2671
|
-
var _a3,
|
|
2773
|
+
var _a3, _b3;
|
|
2672
2774
|
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
2673
|
-
if ((
|
|
2775
|
+
if ((_b3 = (_a3 = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid]) == null ? void 0 : _a3.data_elements) == null ? void 0 : _b3[element.uuid]) {
|
|
2674
2776
|
acc[combinedId] = purposeSelections[purpose.uuid].data_elements[element.uuid].selected;
|
|
2675
2777
|
} else {
|
|
2676
2778
|
acc[combinedId] = false;
|
|
@@ -2686,9 +2788,9 @@ var RedactoNoticeConsent = ({
|
|
|
2686
2788
|
const initialSelections = {};
|
|
2687
2789
|
newCategorizedPurposes.alreadyConsented.forEach((purpose) => {
|
|
2688
2790
|
purpose.data_elements.forEach((element) => {
|
|
2689
|
-
var _a3,
|
|
2791
|
+
var _a3, _b3;
|
|
2690
2792
|
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
2691
|
-
if ((
|
|
2793
|
+
if ((_b3 = (_a3 = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid]) == null ? void 0 : _a3.data_elements) == null ? void 0 : _b3[element.uuid]) {
|
|
2692
2794
|
initialSelections[combinedId] = purposeSelections[purpose.uuid].data_elements[element.uuid].selected;
|
|
2693
2795
|
} else {
|
|
2694
2796
|
initialSelections[combinedId] = false;
|
|
@@ -2709,9 +2811,9 @@ var RedactoNoticeConsent = ({
|
|
|
2709
2811
|
activeConfig.purposes.forEach(
|
|
2710
2812
|
(purpose) => {
|
|
2711
2813
|
purpose.data_elements.forEach((element) => {
|
|
2712
|
-
var _a3,
|
|
2814
|
+
var _a3, _b3;
|
|
2713
2815
|
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
2714
|
-
if ((
|
|
2816
|
+
if ((_b3 = (_a3 = purposeSelections[purpose.uuid]) == null ? void 0 : _a3.data_elements) == null ? void 0 : _b3[element.uuid]) {
|
|
2715
2817
|
initialSelections[combinedId] = purposeSelections[purpose.uuid].data_elements[element.uuid].selected;
|
|
2716
2818
|
} else {
|
|
2717
2819
|
initialSelections[combinedId] = false;
|
|
@@ -2842,7 +2944,7 @@ var RedactoNoticeConsent = ({
|
|
|
2842
2944
|
if (content) {
|
|
2843
2945
|
await submitConsentEvent({
|
|
2844
2946
|
accessToken,
|
|
2845
|
-
|
|
2947
|
+
ledgerBaseUrl,
|
|
2846
2948
|
noticeUuid: content.notice_uuid,
|
|
2847
2949
|
purposes: content.purposes.map((purpose) => {
|
|
2848
2950
|
const isAlreadyConsented = (categorizedPurposes == null ? void 0 : categorizedPurposes.alreadyConsented.some(
|
|
@@ -4623,13 +4725,16 @@ var submitConsentEvent2 = async ({
|
|
|
4623
4725
|
org_uuid,
|
|
4624
4726
|
workspace_uuid,
|
|
4625
4727
|
accessToken,
|
|
4626
|
-
|
|
4728
|
+
ledgerBaseUrl,
|
|
4627
4729
|
noticeUuid,
|
|
4628
4730
|
purposes,
|
|
4629
4731
|
declined,
|
|
4630
4732
|
meta_data
|
|
4631
4733
|
}) => {
|
|
4632
|
-
|
|
4734
|
+
if (!ledgerBaseUrl) {
|
|
4735
|
+
throw new Error("ledgerBaseUrl is required to submit consent");
|
|
4736
|
+
}
|
|
4737
|
+
const apiBaseUrl = ledgerBaseUrl;
|
|
4633
4738
|
const payload = {
|
|
4634
4739
|
notice_uuid: noticeUuid,
|
|
4635
4740
|
purposes: purposes.map((purpose) => {
|
|
@@ -5080,6 +5185,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
5080
5185
|
notice_uuid,
|
|
5081
5186
|
accessToken,
|
|
5082
5187
|
baseUrl,
|
|
5188
|
+
ledgerBaseUrl,
|
|
5083
5189
|
language = "en",
|
|
5084
5190
|
onAccept,
|
|
5085
5191
|
onError,
|
|
@@ -5313,7 +5419,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
5313
5419
|
org_uuid,
|
|
5314
5420
|
workspace_uuid,
|
|
5315
5421
|
accessToken: tokenToUse,
|
|
5316
|
-
|
|
5422
|
+
ledgerBaseUrl,
|
|
5317
5423
|
noticeUuid: content.notice_uuid,
|
|
5318
5424
|
purposes: content.purposes.map((purpose) => {
|
|
5319
5425
|
const hasSelectedRequiredElement = purpose.data_elements.some(
|
|
@@ -5352,6 +5458,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
5352
5458
|
org_uuid,
|
|
5353
5459
|
workspace_uuid,
|
|
5354
5460
|
baseUrl,
|
|
5461
|
+
ledgerBaseUrl,
|
|
5355
5462
|
selectedDataElements,
|
|
5356
5463
|
selectedPurposes,
|
|
5357
5464
|
applicationId,
|
|
@@ -31,9 +31,11 @@ type BaseRequest = {
|
|
|
31
31
|
/**
|
|
32
32
|
* Consent service client factory.
|
|
33
33
|
* Creates a client instance with a specific base URL.
|
|
34
|
-
* @param baseUrl - Consent server base URL
|
|
34
|
+
* @param baseUrl - Consent server base URL (Python service, e.g. http://host/consent)
|
|
35
|
+
* @param ledgerBaseUrl - Go ledger base URL (e.g. http://host:8090/consent-ledger).
|
|
36
|
+
* Used for user-consents reads which are served from the ledger's `/public/...` paths.
|
|
35
37
|
*/
|
|
36
|
-
declare function createConsentClient(baseUrl: string): {
|
|
38
|
+
declare function createConsentClient(baseUrl: string, ledgerBaseUrl: string): {
|
|
37
39
|
/**
|
|
38
40
|
* Get form data (privacy center)
|
|
39
41
|
*/
|
|
@@ -92,9 +94,21 @@ declare function createConsentClient(baseUrl: string): {
|
|
|
92
94
|
nominator_uuid?: string;
|
|
93
95
|
}, authToken?: string, options?: Omit<ApiFetchOptions, "getAuthToken">): Promise<unknown>;
|
|
94
96
|
/**
|
|
95
|
-
* Manage consent (privacy center) - revoke, regrant, or renew
|
|
97
|
+
* Manage consent (privacy center) - revoke, regrant, or renew.
|
|
98
|
+
*
|
|
99
|
+
* The Go ledger has no manage-consent route, so this is expressed as a
|
|
100
|
+
* `partial` submit-consent on the ledger — mirroring the Python dual-write
|
|
101
|
+
* relay (`build_consent_management_payload`): the affected purpose is
|
|
102
|
+
* re-submitted with `selected: false` to revoke or `selected: true` to
|
|
103
|
+
* regrant/renew, and `partial: true` so the rest of the notice's purposes
|
|
104
|
+
* are left untouched. The principal is resolved from the JWT, so no
|
|
105
|
+
* `contact`/identifiers are sent in the body, and `consent_event_uuid` is
|
|
106
|
+
* omitted so the ledger mints a fresh event.
|
|
96
107
|
*/
|
|
97
|
-
manageConsent(baseRequest: BaseRequest, purposeId: string, contact: string, status: "revoke" | "regrant" | "renew", authToken?: string, options?: Omit<ApiFetchOptions, "getAuthToken">, nominatorContact?: string, dataElementUuids?: string[], productUuid?: string
|
|
108
|
+
manageConsent(baseRequest: BaseRequest, purposeId: string, contact: string, status: "revoke" | "regrant" | "renew", authToken?: string, options?: Omit<ApiFetchOptions, "getAuthToken">, nominatorContact?: string, dataElementUuids?: string[], productUuid?: string, noticeUuid?: string, dataElements?: Array<{
|
|
109
|
+
uuid: string;
|
|
110
|
+
selected: boolean;
|
|
111
|
+
}>): Promise<unknown>;
|
|
98
112
|
/**
|
|
99
113
|
* Get activities (privacy center)
|
|
100
114
|
*/
|
|
@@ -358,6 +372,7 @@ type PurposeItem = {
|
|
|
358
372
|
method: string;
|
|
359
373
|
data_elements: ConsentDataElement[];
|
|
360
374
|
link_reason: string | null;
|
|
375
|
+
notice_uuid: string | null;
|
|
361
376
|
};
|
|
362
377
|
type ConsentGroup = {
|
|
363
378
|
product_uuid: string;
|
|
@@ -609,6 +624,7 @@ declare const useInternalNavigation: () => NavigationContextType;
|
|
|
609
624
|
|
|
610
625
|
interface RedactoPrivacyCenterProps {
|
|
611
626
|
baseUrl: string;
|
|
627
|
+
ledgerBaseUrl: string;
|
|
612
628
|
slug: string;
|
|
613
629
|
accessToken: string;
|
|
614
630
|
refreshToken: string;
|
|
@@ -616,7 +632,7 @@ interface RedactoPrivacyCenterProps {
|
|
|
616
632
|
initialPage?: InternalPage;
|
|
617
633
|
onBack?: 'back' | 'signout';
|
|
618
634
|
}
|
|
619
|
-
declare function RedactoPrivacyCenter({ baseUrl, slug, accessToken, refreshToken, onError, initialPage, onBack, }: RedactoPrivacyCenterProps): react_jsx_runtime.JSX.Element;
|
|
635
|
+
declare function RedactoPrivacyCenter({ baseUrl, ledgerBaseUrl, slug, accessToken, refreshToken, onError, initialPage, onBack, }: RedactoPrivacyCenterProps): react_jsx_runtime.JSX.Element;
|
|
620
636
|
|
|
621
637
|
interface PrivacyCenterLayoutProps {
|
|
622
638
|
children: ReactNode;
|
|
@@ -646,15 +662,18 @@ type AuthContextValue = Readonly<{
|
|
|
646
662
|
}>;
|
|
647
663
|
type BaseUrlContextValue = Readonly<{
|
|
648
664
|
baseUrl: string;
|
|
665
|
+
ledgerBaseUrl: string;
|
|
649
666
|
consentClient: ReturnType<typeof createConsentClient>;
|
|
650
667
|
}>;
|
|
651
668
|
|
|
652
|
-
declare const BaseUrlProvider: ({ children, baseUrl, }: {
|
|
669
|
+
declare const BaseUrlProvider: ({ children, baseUrl, ledgerBaseUrl, }: {
|
|
653
670
|
children: ReactNode;
|
|
654
671
|
baseUrl: string;
|
|
672
|
+
ledgerBaseUrl: string;
|
|
655
673
|
}) => react_jsx_runtime.JSX.Element;
|
|
656
674
|
declare const useBaseUrl: () => Readonly<{
|
|
657
675
|
baseUrl: string;
|
|
676
|
+
ledgerBaseUrl: string;
|
|
658
677
|
consentClient: ReturnType<typeof createConsentClient>;
|
|
659
678
|
}>;
|
|
660
679
|
|
|
@@ -801,7 +820,7 @@ type FetchGroupPurposesParams = {
|
|
|
801
820
|
consentClient?: BaseUrlContextValue['consentClient'];
|
|
802
821
|
};
|
|
803
822
|
declare const fetchGroupPurposes: (params: FetchGroupPurposesParams) => Promise<GroupPurposesOut | null>;
|
|
804
|
-
declare const manageConsent: ({ organizationId, workspaceId, purposeId, contact, action, authContext, consentClient, nominatorContact, dataElementUuids, productUuid, }: {
|
|
823
|
+
declare const manageConsent: ({ organizationId, workspaceId, purposeId, contact, action, authContext, consentClient, nominatorContact, dataElementUuids, productUuid, noticeUuid, dataElements, }: {
|
|
805
824
|
organizationId: string;
|
|
806
825
|
workspaceId: string;
|
|
807
826
|
purposeId: string;
|
|
@@ -812,6 +831,11 @@ declare const manageConsent: ({ organizationId, workspaceId, purposeId, contact,
|
|
|
812
831
|
nominatorContact?: string;
|
|
813
832
|
dataElementUuids?: string[];
|
|
814
833
|
productUuid?: string;
|
|
834
|
+
noticeUuid?: string;
|
|
835
|
+
dataElements?: Array<{
|
|
836
|
+
uuid: string;
|
|
837
|
+
selected: boolean;
|
|
838
|
+
}>;
|
|
815
839
|
}) => Promise<boolean | null>;
|
|
816
840
|
declare const fetchActivities: (organizationId: string, workspaceId: string, offset?: number, limit?: number, authContext?: AuthContext, consentClient?: BaseUrlContextValue["consentClient"], language?: string) => Promise<ActivityDetail | null>;
|
|
817
841
|
declare const fetchCaseHistory: (organizationId: string, workspaceId: string, contact: string, offset?: number, limit?: number, authContext?: AuthContext, consentClient?: BaseUrlContextValue["consentClient"], language?: string) => Promise<CaseHistoryDetail | null>;
|