@redacto.io/consent-sdk-react 3.2.0 → 3.3.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.js +144 -104
- package/dist/index.mjs +144 -104
- package/package.json +1 -1
- package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +14 -21
- package/src/RedactoNoticeConsent/api/index.ts +62 -52
- package/src/RedactoNoticeConsent/api/types.ts +20 -5
- package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +18 -23
- package/src/RedactoNoticeConsentInline/api/index.ts +65 -27
- package/src/RedactoNoticeConsentInline/api/types.ts +20 -5
- package/src/utils/isLegacyApi.ts +12 -0
|
@@ -157,9 +157,26 @@ export type FetchConsentContentParams = {
|
|
|
157
157
|
};
|
|
158
158
|
|
|
159
159
|
export type ConsentEventPayload = {
|
|
160
|
-
|
|
160
|
+
notice_uuid: string;
|
|
161
|
+
purposes: Array<{
|
|
162
|
+
purpose_uuid: string;
|
|
163
|
+
selected: boolean;
|
|
164
|
+
data_elements?: Array<{
|
|
165
|
+
uuid: string;
|
|
166
|
+
selected: boolean;
|
|
167
|
+
}>;
|
|
168
|
+
}>;
|
|
169
|
+
select_all_mandatory: boolean;
|
|
170
|
+
source?: string;
|
|
171
|
+
declined?: boolean;
|
|
172
|
+
meta_data?: {
|
|
173
|
+
specific_uuid: string;
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// @deprecated Remove when production backend supports the new payload format.
|
|
178
|
+
export type LegacyConsentEventPayload = {
|
|
161
179
|
primary_email?: string;
|
|
162
|
-
primary_mobile?: string;
|
|
163
180
|
notice_uuid: string;
|
|
164
181
|
source: string;
|
|
165
182
|
declined: boolean;
|
|
@@ -179,9 +196,7 @@ export type ConsentEventPayload = {
|
|
|
179
196
|
}>;
|
|
180
197
|
}>;
|
|
181
198
|
};
|
|
182
|
-
meta_data?: {
|
|
183
|
-
specific_uuid: string;
|
|
184
|
-
};
|
|
199
|
+
meta_data?: { specific_uuid: string };
|
|
185
200
|
};
|
|
186
201
|
|
|
187
202
|
export type DataElement = {
|
|
@@ -154,26 +154,24 @@ const RedactoConsentInlineComponent = ({
|
|
|
154
154
|
language,
|
|
155
155
|
specific_uuid: applicationId,
|
|
156
156
|
});
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
);
|
|
157
|
+
const activeConfig = consentContentData.detail.active_config;
|
|
158
|
+
setContent(activeConfig);
|
|
159
|
+
if (activeConfig.default_language) {
|
|
160
|
+
setSelectedLanguage(activeConfig.default_language);
|
|
162
161
|
}
|
|
163
|
-
const initialCollapsedState =
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
);
|
|
162
|
+
const initialCollapsedState = activeConfig.purposes.reduce(
|
|
163
|
+
(acc, purpose) => ({
|
|
164
|
+
...acc,
|
|
165
|
+
[purpose.uuid]: true,
|
|
166
|
+
}),
|
|
167
|
+
{}
|
|
168
|
+
);
|
|
171
169
|
setCollapsedPurposes(initialCollapsedState);
|
|
172
170
|
|
|
173
171
|
// Initialize selected states
|
|
174
172
|
// All elements start unchecked, but required elements cannot be unchecked once checked
|
|
175
173
|
const initialDataElementState: Record<string, boolean> =
|
|
176
|
-
|
|
174
|
+
activeConfig.purposes.reduce(
|
|
177
175
|
(acc: Record<string, boolean>, purpose) => {
|
|
178
176
|
purpose.data_elements.forEach((element) => {
|
|
179
177
|
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
@@ -187,7 +185,7 @@ const RedactoConsentInlineComponent = ({
|
|
|
187
185
|
|
|
188
186
|
// Initialize purpose states - all start unchecked
|
|
189
187
|
const initialPurposeState: Record<string, boolean> =
|
|
190
|
-
|
|
188
|
+
activeConfig.purposes.reduce(
|
|
191
189
|
(acc: Record<string, boolean>, purpose) => {
|
|
192
190
|
return {
|
|
193
191
|
...acc,
|
|
@@ -198,7 +196,6 @@ const RedactoConsentInlineComponent = ({
|
|
|
198
196
|
);
|
|
199
197
|
setSelectedPurposes(initialPurposeState);
|
|
200
198
|
} catch (err: unknown) {
|
|
201
|
-
console.error(err);
|
|
202
199
|
const error = err as Error & { status?: number };
|
|
203
200
|
setFetchError(error);
|
|
204
201
|
if (error.status === 409) {
|
|
@@ -360,13 +357,12 @@ const RedactoConsentInlineComponent = ({
|
|
|
360
357
|
// Reset ref on success to allow re-submission if needed
|
|
361
358
|
hasSubmittedRef.current = false;
|
|
362
359
|
} catch (error) {
|
|
363
|
-
console.error("Error submitting consent:", error);
|
|
364
360
|
const err = error as Error & { status?: number };
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
"An error occurred while submitting your consent. Please try again later."
|
|
368
|
-
|
|
369
|
-
|
|
361
|
+
const message =
|
|
362
|
+
err.status === 500
|
|
363
|
+
? "An error occurred while submitting your consent. Please try again later."
|
|
364
|
+
: err.message || "Failed to submit consent. Please try again.";
|
|
365
|
+
setErrorMessage(message);
|
|
370
366
|
// Reset ref on error to allow retry
|
|
371
367
|
hasSubmittedRef.current = false;
|
|
372
368
|
throw error;
|
|
@@ -400,7 +396,6 @@ const RedactoConsentInlineComponent = ({
|
|
|
400
396
|
try {
|
|
401
397
|
await handleAcceptWithToken(accessToken);
|
|
402
398
|
} catch (err) {
|
|
403
|
-
console.error("Failed to auto-submit consent:", err);
|
|
404
399
|
hasSubmittedRef.current = false;
|
|
405
400
|
onError?.(err as Error);
|
|
406
401
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ConsentContent,
|
|
3
3
|
ConsentEventPayload,
|
|
4
|
+
LegacyConsentEventPayload,
|
|
4
5
|
FetchConsentContentParams,
|
|
5
6
|
SubmitConsentEventParams,
|
|
6
7
|
} from "./types";
|
|
8
|
+
import { isLegacyApi } from "../../utils/isLegacyApi";
|
|
7
9
|
|
|
8
10
|
const BASE_URL = "https://api.redacto.tech/consent";
|
|
9
11
|
|
|
@@ -58,7 +60,6 @@ export const fetchConsentContent = async ({
|
|
|
58
60
|
const data = await response.json();
|
|
59
61
|
return data;
|
|
60
62
|
} catch (error) {
|
|
61
|
-
console.error("Error fetching consent content:", error);
|
|
62
63
|
throw error;
|
|
63
64
|
}
|
|
64
65
|
};
|
|
@@ -74,33 +75,71 @@ export const submitConsentEvent = async ({
|
|
|
74
75
|
meta_data,
|
|
75
76
|
}: SubmitConsentEventParams): Promise<void> => {
|
|
76
77
|
try {
|
|
77
|
-
const primaryEmail = localStorage.getItem("userEmail");
|
|
78
|
-
const payload: ConsentEventPayload = {
|
|
79
|
-
primary_email: primaryEmail || undefined,
|
|
80
|
-
notice_uuid: noticeUuid,
|
|
81
|
-
source: "WEB",
|
|
82
|
-
declined,
|
|
83
|
-
consents: {
|
|
84
|
-
purposes: purposes.map((purpose) => ({
|
|
85
|
-
uuid: purpose.uuid,
|
|
86
|
-
name: purpose.name,
|
|
87
|
-
description: purpose.description,
|
|
88
|
-
industries: purpose.industries || "",
|
|
89
|
-
selected: purpose.selected,
|
|
90
|
-
data_elements: purpose.data_elements.map((element) => ({
|
|
91
|
-
uuid: element.uuid,
|
|
92
|
-
name: element.name,
|
|
93
|
-
enabled: element.enabled,
|
|
94
|
-
required: element.required,
|
|
95
|
-
selected: element.required ? true : element.selected,
|
|
96
|
-
})),
|
|
97
|
-
})),
|
|
98
|
-
},
|
|
99
|
-
meta_data,
|
|
100
|
-
};
|
|
101
|
-
|
|
102
78
|
const apiBaseUrl = baseUrl || BASE_URL;
|
|
103
79
|
|
|
80
|
+
let payload: ConsentEventPayload | LegacyConsentEventPayload;
|
|
81
|
+
|
|
82
|
+
if (isLegacyApi(apiBaseUrl)) {
|
|
83
|
+
// @deprecated Legacy payload for production (.io) backend
|
|
84
|
+
const primaryEmail = typeof window !== "undefined" ? localStorage.getItem("userEmail") : null;
|
|
85
|
+
payload = {
|
|
86
|
+
primary_email: primaryEmail || undefined,
|
|
87
|
+
notice_uuid: noticeUuid,
|
|
88
|
+
source: "WEB",
|
|
89
|
+
declined: Boolean(declined),
|
|
90
|
+
consents: {
|
|
91
|
+
purposes: purposes.map((purpose) => {
|
|
92
|
+
if (!purpose.uuid) {
|
|
93
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
uuid: purpose.uuid,
|
|
97
|
+
name: purpose.name,
|
|
98
|
+
description: purpose.description || "",
|
|
99
|
+
industries: purpose.industries || "",
|
|
100
|
+
selected: Boolean(purpose.selected),
|
|
101
|
+
data_elements: (purpose.data_elements || []).map((element) => ({
|
|
102
|
+
uuid: element.uuid,
|
|
103
|
+
name: element.name,
|
|
104
|
+
enabled: Boolean(element.enabled),
|
|
105
|
+
required: Boolean(element.required),
|
|
106
|
+
selected: element.required ? true : Boolean(element.selected),
|
|
107
|
+
})),
|
|
108
|
+
};
|
|
109
|
+
}),
|
|
110
|
+
},
|
|
111
|
+
meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : undefined,
|
|
112
|
+
};
|
|
113
|
+
} else {
|
|
114
|
+
// New payload for staging (.tech) / localhost
|
|
115
|
+
payload = {
|
|
116
|
+
notice_uuid: noticeUuid,
|
|
117
|
+
purposes: purposes.map((purpose) => {
|
|
118
|
+
if (!purpose.uuid) {
|
|
119
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Only include enabled data elements (disabled elements are not selectable)
|
|
123
|
+
const dataElements = purpose.data_elements
|
|
124
|
+
.filter((element) => element.enabled)
|
|
125
|
+
.map((element) => ({
|
|
126
|
+
uuid: element.uuid,
|
|
127
|
+
selected: element.required ? true : Boolean(element.selected),
|
|
128
|
+
}));
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
purpose_uuid: purpose.uuid,
|
|
132
|
+
selected: Boolean(purpose.selected),
|
|
133
|
+
data_elements: dataElements.length > 0 ? dataElements : undefined,
|
|
134
|
+
};
|
|
135
|
+
}),
|
|
136
|
+
select_all_mandatory: false,
|
|
137
|
+
source: "WEB",
|
|
138
|
+
declined,
|
|
139
|
+
meta_data,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
104
143
|
const response = await fetch(
|
|
105
144
|
`${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/submit-consent`,
|
|
106
145
|
{
|
|
@@ -151,7 +190,6 @@ export const submitConsentEvent = async ({
|
|
|
151
190
|
throw error;
|
|
152
191
|
}
|
|
153
192
|
} catch (error) {
|
|
154
|
-
console.error("Error submitting consent event:", error);
|
|
155
193
|
throw error;
|
|
156
194
|
}
|
|
157
195
|
};
|
|
@@ -132,9 +132,26 @@ export type FetchConsentContentParams = {
|
|
|
132
132
|
};
|
|
133
133
|
|
|
134
134
|
export type ConsentEventPayload = {
|
|
135
|
-
|
|
135
|
+
notice_uuid: string;
|
|
136
|
+
purposes: Array<{
|
|
137
|
+
purpose_uuid: string;
|
|
138
|
+
selected: boolean;
|
|
139
|
+
data_elements?: Array<{
|
|
140
|
+
uuid: string;
|
|
141
|
+
selected: boolean;
|
|
142
|
+
}>;
|
|
143
|
+
}>;
|
|
144
|
+
select_all_mandatory: boolean;
|
|
145
|
+
source?: string;
|
|
146
|
+
declined?: boolean;
|
|
147
|
+
meta_data?: {
|
|
148
|
+
specific_uuid: string;
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// @deprecated Remove when production backend supports the new payload format.
|
|
153
|
+
export type LegacyConsentEventPayload = {
|
|
136
154
|
primary_email?: string;
|
|
137
|
-
primary_mobile?: string;
|
|
138
155
|
notice_uuid: string;
|
|
139
156
|
source: string;
|
|
140
157
|
declined: boolean;
|
|
@@ -154,9 +171,7 @@ export type ConsentEventPayload = {
|
|
|
154
171
|
}>;
|
|
155
172
|
}>;
|
|
156
173
|
};
|
|
157
|
-
meta_data?: {
|
|
158
|
-
specific_uuid: string;
|
|
159
|
-
};
|
|
174
|
+
meta_data?: { specific_uuid: string };
|
|
160
175
|
};
|
|
161
176
|
|
|
162
177
|
export type DataElement = {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @deprecated Remove when production backend supports the new payload format.
|
|
2
|
+
export function isLegacyApi(baseUrl: string): boolean {
|
|
3
|
+
try {
|
|
4
|
+
return new URL(baseUrl).hostname.endsWith(".redacto.io");
|
|
5
|
+
} catch {
|
|
6
|
+
try {
|
|
7
|
+
return new URL(`https://${baseUrl}`).hostname.endsWith(".redacto.io");
|
|
8
|
+
} catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|