@redacto.io/consent-sdk-react 3.1.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 +12 -0
- package/dist/index.js +267 -153
- package/dist/index.mjs +267 -153
- package/package.json +1 -1
- package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +191 -97
- 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
package/dist/index.js
CHANGED
|
@@ -30,6 +30,21 @@ var import_react2 = require("react");
|
|
|
30
30
|
|
|
31
31
|
// src/RedactoNoticeConsent/api/index.ts
|
|
32
32
|
var import_jwt_decode = require("jwt-decode");
|
|
33
|
+
|
|
34
|
+
// src/utils/isLegacyApi.ts
|
|
35
|
+
function isLegacyApi(baseUrl) {
|
|
36
|
+
try {
|
|
37
|
+
return new URL(baseUrl).hostname.endsWith(".redacto.io");
|
|
38
|
+
} catch {
|
|
39
|
+
try {
|
|
40
|
+
return new URL(`https://${baseUrl}`).hostname.endsWith(".redacto.io");
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/RedactoNoticeConsent/api/index.ts
|
|
33
48
|
var BASE_URL = "https://api.redacto.io/consent";
|
|
34
49
|
var apiCache = /* @__PURE__ */ new Map();
|
|
35
50
|
var CACHE_TTL = 5 * 60 * 1e3;
|
|
@@ -54,14 +69,6 @@ function decodeTokenSafely(token) {
|
|
|
54
69
|
return null;
|
|
55
70
|
}
|
|
56
71
|
}
|
|
57
|
-
var storage = {
|
|
58
|
-
getItem: (key) => {
|
|
59
|
-
if (typeof window !== "undefined") {
|
|
60
|
-
return localStorage.getItem(key);
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
72
|
var clearApiCache = () => {
|
|
66
73
|
apiCache.clear();
|
|
67
74
|
};
|
|
@@ -135,7 +142,6 @@ var fetchConsentContent = async ({
|
|
|
135
142
|
}
|
|
136
143
|
return data;
|
|
137
144
|
} catch (error) {
|
|
138
|
-
console.error("Error fetching consent content:", error instanceof Error ? error.message : error);
|
|
139
145
|
throw error;
|
|
140
146
|
}
|
|
141
147
|
};
|
|
@@ -161,42 +167,62 @@ var submitConsentEvent = async ({
|
|
|
161
167
|
if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
|
|
162
168
|
throw new Error("Invalid token: missing organization or workspace UUID");
|
|
163
169
|
}
|
|
164
|
-
const primaryEmail = storage.getItem("userEmail");
|
|
165
|
-
const validatedPurposes = purposes.map((purpose) => {
|
|
166
|
-
if (!purpose.uuid || !purpose.name) {
|
|
167
|
-
throw new Error(`Invalid purpose data: missing uuid or name`);
|
|
168
|
-
}
|
|
169
|
-
return {
|
|
170
|
-
uuid: purpose.uuid,
|
|
171
|
-
name: purpose.name,
|
|
172
|
-
description: purpose.description || "",
|
|
173
|
-
industries: purpose.industries || "",
|
|
174
|
-
selected: Boolean(purpose.selected),
|
|
175
|
-
data_elements: (purpose.data_elements || []).map((element) => {
|
|
176
|
-
if (!element.uuid || !element.name) {
|
|
177
|
-
throw new Error(`Invalid data element: missing uuid or name`);
|
|
178
|
-
}
|
|
179
|
-
return {
|
|
180
|
-
uuid: element.uuid,
|
|
181
|
-
name: element.name,
|
|
182
|
-
enabled: Boolean(element.enabled),
|
|
183
|
-
required: Boolean(element.required),
|
|
184
|
-
selected: element.required ? true : Boolean(element.selected)
|
|
185
|
-
};
|
|
186
|
-
})
|
|
187
|
-
};
|
|
188
|
-
});
|
|
189
|
-
const payload = {
|
|
190
|
-
primary_email: primaryEmail || void 0,
|
|
191
|
-
notice_uuid: noticeUuid,
|
|
192
|
-
source: "WEB",
|
|
193
|
-
declined: Boolean(declined),
|
|
194
|
-
consents: {
|
|
195
|
-
purposes: validatedPurposes
|
|
196
|
-
},
|
|
197
|
-
meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
|
|
198
|
-
};
|
|
199
170
|
const apiBaseUrl = baseUrl || BASE_URL;
|
|
171
|
+
let payload;
|
|
172
|
+
if (isLegacyApi(apiBaseUrl)) {
|
|
173
|
+
const primaryEmail = typeof window !== "undefined" ? localStorage.getItem("userEmail") : null;
|
|
174
|
+
payload = {
|
|
175
|
+
primary_email: primaryEmail || void 0,
|
|
176
|
+
notice_uuid: noticeUuid,
|
|
177
|
+
source: "WEB",
|
|
178
|
+
declined: Boolean(declined),
|
|
179
|
+
consents: {
|
|
180
|
+
purposes: purposes.map((purpose) => {
|
|
181
|
+
if (!purpose.uuid) {
|
|
182
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
uuid: purpose.uuid,
|
|
186
|
+
name: purpose.name,
|
|
187
|
+
description: purpose.description || "",
|
|
188
|
+
industries: purpose.industries || "",
|
|
189
|
+
selected: Boolean(purpose.selected),
|
|
190
|
+
data_elements: (purpose.data_elements || []).map((element) => ({
|
|
191
|
+
uuid: element.uuid,
|
|
192
|
+
name: element.name,
|
|
193
|
+
enabled: Boolean(element.enabled),
|
|
194
|
+
required: Boolean(element.required),
|
|
195
|
+
selected: element.required ? true : Boolean(element.selected)
|
|
196
|
+
}))
|
|
197
|
+
};
|
|
198
|
+
})
|
|
199
|
+
},
|
|
200
|
+
meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
|
|
201
|
+
};
|
|
202
|
+
} else {
|
|
203
|
+
const validatedPurposes = purposes.map((purpose) => {
|
|
204
|
+
if (!purpose.uuid) {
|
|
205
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
206
|
+
}
|
|
207
|
+
const dataElements = (purpose.data_elements || []).filter((element) => element.enabled).map((element) => ({
|
|
208
|
+
uuid: element.uuid,
|
|
209
|
+
selected: element.required ? true : Boolean(element.selected)
|
|
210
|
+
}));
|
|
211
|
+
return {
|
|
212
|
+
purpose_uuid: purpose.uuid,
|
|
213
|
+
selected: Boolean(purpose.selected),
|
|
214
|
+
data_elements: dataElements.length > 0 ? dataElements : void 0
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
payload = {
|
|
218
|
+
notice_uuid: noticeUuid,
|
|
219
|
+
purposes: validatedPurposes,
|
|
220
|
+
select_all_mandatory: false,
|
|
221
|
+
source: "WEB",
|
|
222
|
+
declined: Boolean(declined),
|
|
223
|
+
meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
|
|
224
|
+
};
|
|
225
|
+
}
|
|
200
226
|
const response = await fetch(
|
|
201
227
|
`${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/submit-consent`,
|
|
202
228
|
{
|
|
@@ -229,7 +255,6 @@ var submitConsentEvent = async ({
|
|
|
229
255
|
}
|
|
230
256
|
apiCache.clear();
|
|
231
257
|
} catch (error) {
|
|
232
|
-
console.error("Error submitting consent event:", error instanceof Error ? error.message : error);
|
|
233
258
|
throw error;
|
|
234
259
|
}
|
|
235
260
|
};
|
|
@@ -361,7 +386,6 @@ var fetchTTSAudioUrls = async ({
|
|
|
361
386
|
const data = await response.json();
|
|
362
387
|
return data;
|
|
363
388
|
} catch (error) {
|
|
364
|
-
console.error("Error fetching TTS audio URLs:", error instanceof Error ? error.message : error);
|
|
365
389
|
throw error;
|
|
366
390
|
}
|
|
367
391
|
};
|
|
@@ -899,7 +923,8 @@ var PurposeItem = ({
|
|
|
899
923
|
onDataElementToggle,
|
|
900
924
|
getTranslatedText,
|
|
901
925
|
isAlreadyConsented,
|
|
902
|
-
selectedLanguage
|
|
926
|
+
selectedLanguage,
|
|
927
|
+
initialDataElementSelections = {}
|
|
903
928
|
}) => {
|
|
904
929
|
const headingStyle = (0, import_react2.useMemo)(
|
|
905
930
|
() => ({
|
|
@@ -1114,46 +1139,68 @@ var PurposeItem = ({
|
|
|
1114
1139
|
)}${dataElement.required ? " (required)" : ""}`
|
|
1115
1140
|
}
|
|
1116
1141
|
),
|
|
1117
|
-
isAlreadyConsented && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
width: "16px",
|
|
1125
|
-
height: "16px",
|
|
1126
|
-
borderRadius: "50%",
|
|
1127
|
-
backgroundColor: "#10B981"
|
|
1128
|
-
},
|
|
1129
|
-
"aria-label": `Already consented to ${getTranslatedText(
|
|
1130
|
-
`data_elements.name`,
|
|
1131
|
-
dataElement.name,
|
|
1132
|
-
dataElement.uuid
|
|
1133
|
-
)}`,
|
|
1134
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1135
|
-
"svg",
|
|
1142
|
+
isAlreadyConsented && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: (() => {
|
|
1143
|
+
const combinedId = `${purpose.uuid}-${dataElement.uuid}`;
|
|
1144
|
+
const isCurrentlySelected = selectedDataElements[combinedId] || false;
|
|
1145
|
+
const wasOriginallySelected = initialDataElementSelections[combinedId] || false;
|
|
1146
|
+
if (isCurrentlySelected && wasOriginallySelected) {
|
|
1147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1148
|
+
"div",
|
|
1136
1149
|
{
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1150
|
+
style: {
|
|
1151
|
+
display: "flex",
|
|
1152
|
+
alignItems: "center",
|
|
1153
|
+
justifyContent: "center",
|
|
1154
|
+
width: "16px",
|
|
1155
|
+
height: "16px",
|
|
1156
|
+
borderRadius: "50%",
|
|
1157
|
+
backgroundColor: "#10B981"
|
|
1158
|
+
},
|
|
1159
|
+
"aria-label": `Already consented to ${getTranslatedText(
|
|
1160
|
+
`data_elements.name`,
|
|
1161
|
+
dataElement.name,
|
|
1162
|
+
dataElement.uuid
|
|
1163
|
+
)}`,
|
|
1143
1164
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1144
|
-
"
|
|
1165
|
+
"svg",
|
|
1145
1166
|
{
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1167
|
+
width: "10",
|
|
1168
|
+
height: "10",
|
|
1169
|
+
viewBox: "0 0 10 10",
|
|
1170
|
+
fill: "none",
|
|
1171
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1172
|
+
"aria-hidden": "true",
|
|
1173
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1174
|
+
"path",
|
|
1175
|
+
{
|
|
1176
|
+
d: "M3 5L4.5 6.5L7.5 3.5",
|
|
1177
|
+
stroke: "white",
|
|
1178
|
+
strokeWidth: "1.5",
|
|
1179
|
+
strokeLinecap: "round",
|
|
1180
|
+
strokeLinejoin: "round"
|
|
1181
|
+
}
|
|
1182
|
+
)
|
|
1151
1183
|
}
|
|
1152
1184
|
)
|
|
1153
1185
|
}
|
|
1154
|
-
)
|
|
1186
|
+
);
|
|
1187
|
+
} else {
|
|
1188
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1189
|
+
"input",
|
|
1190
|
+
{
|
|
1191
|
+
className: "redacto-checkbox-small",
|
|
1192
|
+
type: "checkbox",
|
|
1193
|
+
checked: isCurrentlySelected,
|
|
1194
|
+
onChange: () => onDataElementToggle(dataElement.uuid, purpose.uuid),
|
|
1195
|
+
"aria-label": `Select ${getTranslatedText(
|
|
1196
|
+
`data_elements.name`,
|
|
1197
|
+
dataElement.name,
|
|
1198
|
+
dataElement.uuid
|
|
1199
|
+
)}${dataElement.required ? " (required)" : ""}`
|
|
1200
|
+
}
|
|
1201
|
+
);
|
|
1155
1202
|
}
|
|
1156
|
-
)
|
|
1203
|
+
})() })
|
|
1157
1204
|
]
|
|
1158
1205
|
},
|
|
1159
1206
|
`${dataElement.uuid}-${selectedLanguage}`
|
|
@@ -1592,10 +1639,13 @@ var RedactoNoticeConsent = ({
|
|
|
1592
1639
|
}
|
|
1593
1640
|
const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
|
|
1594
1641
|
const [isSubmitting, setIsSubmitting] = (0, import_react2.useState)(false);
|
|
1642
|
+
const [isSubmittingAccept, setIsSubmittingAccept] = (0, import_react2.useState)(false);
|
|
1643
|
+
const [isSubmittingDecline, setIsSubmittingDecline] = (0, import_react2.useState)(false);
|
|
1595
1644
|
const [content, setContent] = (0, import_react2.useState)(null);
|
|
1596
1645
|
const [categorizedPurposes, setCategorizedPurposes] = (0, import_react2.useState)(null);
|
|
1597
1646
|
const [selectedPurposes, setSelectedPurposes] = (0, import_react2.useState)({});
|
|
1598
1647
|
const [selectedDataElements, setSelectedDataElements] = (0, import_react2.useState)({});
|
|
1648
|
+
const [initialDataElementSelections, setInitialDataElementSelections] = (0, import_react2.useState)({});
|
|
1599
1649
|
const [collapsedPurposes, setCollapsedPurposes] = (0, import_react2.useState)({});
|
|
1600
1650
|
const [hasAlreadyConsented, setHasAlreadyConsented] = (0, import_react2.useState)(false);
|
|
1601
1651
|
const [isLanguageDropdownOpen, setIsLanguageDropdownOpen] = (0, import_react2.useState)(false);
|
|
@@ -1736,11 +1786,14 @@ var RedactoNoticeConsent = ({
|
|
|
1736
1786
|
setCategorizedPurposes(null);
|
|
1737
1787
|
setSelectedPurposes({});
|
|
1738
1788
|
setSelectedDataElements({});
|
|
1789
|
+
setInitialDataElementSelections({});
|
|
1739
1790
|
setCollapsedPurposes({});
|
|
1740
1791
|
setHasAlreadyConsented(false);
|
|
1741
1792
|
setErrorMessage(null);
|
|
1742
1793
|
setFetchError(null);
|
|
1743
1794
|
setIsLoading(true);
|
|
1795
|
+
setIsSubmittingAccept(false);
|
|
1796
|
+
setIsSubmittingDecline(false);
|
|
1744
1797
|
setShowAgeVerification(false);
|
|
1745
1798
|
setShowGuardianForm(false);
|
|
1746
1799
|
setIsSubmittingGuardian(false);
|
|
@@ -1823,14 +1876,15 @@ var RedactoNoticeConsent = ({
|
|
|
1823
1876
|
validate_against: validateAgainst,
|
|
1824
1877
|
signal: (_a2 = abortControllerRef.current) == null ? void 0 : _a2.signal
|
|
1825
1878
|
});
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1879
|
+
const activeConfig = consentContentData.detail.active_config;
|
|
1880
|
+
setContent(activeConfig);
|
|
1881
|
+
if (activeConfig.default_language) {
|
|
1882
|
+
const defaultLang = activeConfig.default_language;
|
|
1829
1883
|
setSelectedLanguage(
|
|
1830
1884
|
defaultLang === "en" || defaultLang === "EN" ? "English" : defaultLang
|
|
1831
1885
|
);
|
|
1832
1886
|
}
|
|
1833
|
-
const initialCollapsedState =
|
|
1887
|
+
const initialCollapsedState = activeConfig.purposes.reduce(
|
|
1834
1888
|
(acc, purpose) => ({
|
|
1835
1889
|
...acc,
|
|
1836
1890
|
[purpose.uuid]: true
|
|
@@ -1841,13 +1895,13 @@ var RedactoNoticeConsent = ({
|
|
|
1841
1895
|
const isReconsentRequired = consentContentData.detail.reconsent_required;
|
|
1842
1896
|
const purposeSelections = consentContentData.detail.purpose_selections;
|
|
1843
1897
|
const newCategorizedPurposes = isReconsentRequired ? {
|
|
1844
|
-
alreadyConsented:
|
|
1898
|
+
alreadyConsented: activeConfig.purposes.filter(
|
|
1845
1899
|
(purpose) => {
|
|
1846
1900
|
const selection = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid];
|
|
1847
1901
|
return selection && (selection.status === "ACTIVE" || selection.status === "EXPIRED") && !selection.needs_reconsent;
|
|
1848
1902
|
}
|
|
1849
1903
|
),
|
|
1850
|
-
needsConsent:
|
|
1904
|
+
needsConsent: activeConfig.purposes.filter(
|
|
1851
1905
|
(purpose) => {
|
|
1852
1906
|
const selection = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid];
|
|
1853
1907
|
return !selection || selection.status !== "ACTIVE" || selection.needs_reconsent;
|
|
@@ -1855,7 +1909,7 @@ var RedactoNoticeConsent = ({
|
|
|
1855
1909
|
)
|
|
1856
1910
|
} : null;
|
|
1857
1911
|
setCategorizedPurposes(newCategorizedPurposes);
|
|
1858
|
-
const initialPurposeState =
|
|
1912
|
+
const initialPurposeState = activeConfig.purposes.reduce(
|
|
1859
1913
|
(acc, purpose) => {
|
|
1860
1914
|
if (isReconsentRequired && (purposeSelections == null ? void 0 : purposeSelections[purpose.uuid])) {
|
|
1861
1915
|
acc[purpose.uuid] = purposeSelections[purpose.uuid].selected;
|
|
@@ -1867,7 +1921,7 @@ var RedactoNoticeConsent = ({
|
|
|
1867
1921
|
{}
|
|
1868
1922
|
);
|
|
1869
1923
|
setSelectedPurposes(initialPurposeState);
|
|
1870
|
-
const initialDataElementState =
|
|
1924
|
+
const initialDataElementState = activeConfig.purposes.reduce(
|
|
1871
1925
|
(acc, purpose) => {
|
|
1872
1926
|
purpose.data_elements.forEach((element) => {
|
|
1873
1927
|
var _a3, _b2;
|
|
@@ -1883,6 +1937,23 @@ var RedactoNoticeConsent = ({
|
|
|
1883
1937
|
{}
|
|
1884
1938
|
);
|
|
1885
1939
|
setSelectedDataElements(initialDataElementState);
|
|
1940
|
+
if (isReconsentRequired && newCategorizedPurposes) {
|
|
1941
|
+
const initialSelections = {};
|
|
1942
|
+
newCategorizedPurposes.alreadyConsented.forEach((purpose) => {
|
|
1943
|
+
purpose.data_elements.forEach((element) => {
|
|
1944
|
+
var _a3, _b2;
|
|
1945
|
+
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
1946
|
+
if ((_b2 = (_a3 = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid]) == null ? void 0 : _a3.data_elements) == null ? void 0 : _b2[element.uuid]) {
|
|
1947
|
+
initialSelections[combinedId] = purposeSelections[purpose.uuid].data_elements[element.uuid].selected;
|
|
1948
|
+
} else {
|
|
1949
|
+
initialSelections[combinedId] = false;
|
|
1950
|
+
}
|
|
1951
|
+
});
|
|
1952
|
+
});
|
|
1953
|
+
setInitialDataElementSelections(initialSelections);
|
|
1954
|
+
} else {
|
|
1955
|
+
setInitialDataElementSelections({});
|
|
1956
|
+
}
|
|
1886
1957
|
if (consentContentData.detail.is_minor) {
|
|
1887
1958
|
setShowAgeVerification(true);
|
|
1888
1959
|
}
|
|
@@ -1891,7 +1962,6 @@ var RedactoNoticeConsent = ({
|
|
|
1891
1962
|
if (err instanceof Error && err.name === "AbortError") {
|
|
1892
1963
|
return;
|
|
1893
1964
|
}
|
|
1894
|
-
console.error(err);
|
|
1895
1965
|
const error = err;
|
|
1896
1966
|
setFetchError(error);
|
|
1897
1967
|
if (error.status === 409) {
|
|
@@ -1983,6 +2053,7 @@ var RedactoNoticeConsent = ({
|
|
|
1983
2053
|
const handleAccept = async () => {
|
|
1984
2054
|
const submitController = new AbortController();
|
|
1985
2055
|
try {
|
|
2056
|
+
setIsSubmittingAccept(true);
|
|
1986
2057
|
setIsSubmitting(true);
|
|
1987
2058
|
setErrorMessage(null);
|
|
1988
2059
|
if (content) {
|
|
@@ -1990,14 +2061,31 @@ var RedactoNoticeConsent = ({
|
|
|
1990
2061
|
accessToken,
|
|
1991
2062
|
baseUrl,
|
|
1992
2063
|
noticeUuid: content.notice_uuid,
|
|
1993
|
-
purposes: content.purposes.map((purpose) =>
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2064
|
+
purposes: content.purposes.map((purpose) => {
|
|
2065
|
+
const isAlreadyConsented = (categorizedPurposes == null ? void 0 : categorizedPurposes.alreadyConsented.some(
|
|
2066
|
+
(p) => p.uuid === purpose.uuid
|
|
2067
|
+
)) || false;
|
|
2068
|
+
let purposeSelected = selectedPurposes[purpose.uuid] || false;
|
|
2069
|
+
if (isAlreadyConsented) {
|
|
2070
|
+
const wasModified = purpose.data_elements.some((element) => {
|
|
2071
|
+
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
2072
|
+
const currentSelection = selectedDataElements[combinedId] || false;
|
|
2073
|
+
const initialSelection = initialDataElementSelections[combinedId] || false;
|
|
2074
|
+
return currentSelection !== initialSelection;
|
|
2075
|
+
});
|
|
2076
|
+
if (wasModified) {
|
|
2077
|
+
purposeSelected = true;
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
return {
|
|
2081
|
+
...purpose,
|
|
2082
|
+
selected: purposeSelected,
|
|
2083
|
+
data_elements: purpose.data_elements.map((element) => ({
|
|
2084
|
+
...element,
|
|
2085
|
+
selected: element.required ? true : selectedDataElements[`${purpose.uuid}-${element.uuid}`] || false
|
|
2086
|
+
}))
|
|
2087
|
+
};
|
|
2088
|
+
}),
|
|
2001
2089
|
declined: false,
|
|
2002
2090
|
meta_data: applicationId ? { specific_uuid: applicationId } : void 0,
|
|
2003
2091
|
signal: submitController.signal
|
|
@@ -2008,20 +2096,24 @@ var RedactoNoticeConsent = ({
|
|
|
2008
2096
|
if (error instanceof Error && error.name === "AbortError") {
|
|
2009
2097
|
return;
|
|
2010
2098
|
}
|
|
2011
|
-
console.error("Error submitting consent:", error);
|
|
2012
2099
|
const err = error;
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
"An error occurred while submitting your consent. Please try again later."
|
|
2016
|
-
);
|
|
2017
|
-
}
|
|
2100
|
+
const message = err.status === 500 ? "An error occurred while submitting your consent. Please try again later." : err.message || "Failed to submit consent. Please try again.";
|
|
2101
|
+
setErrorMessage(message);
|
|
2018
2102
|
onError == null ? void 0 : onError(error);
|
|
2019
2103
|
} finally {
|
|
2104
|
+
setIsSubmittingAccept(false);
|
|
2020
2105
|
setIsSubmitting(false);
|
|
2021
2106
|
}
|
|
2022
2107
|
};
|
|
2023
2108
|
const handleDecline = (0, import_react2.useCallback)(async () => {
|
|
2024
|
-
|
|
2109
|
+
try {
|
|
2110
|
+
setIsSubmittingDecline(true);
|
|
2111
|
+
setIsSubmitting(true);
|
|
2112
|
+
onDecline == null ? void 0 : onDecline();
|
|
2113
|
+
} finally {
|
|
2114
|
+
setIsSubmittingDecline(false);
|
|
2115
|
+
setIsSubmitting(false);
|
|
2116
|
+
}
|
|
2025
2117
|
}, [onDecline]);
|
|
2026
2118
|
const handleGuardianFormChange = (0, import_react2.useCallback)(
|
|
2027
2119
|
(field, value) => {
|
|
@@ -2388,7 +2480,6 @@ var RedactoNoticeConsent = ({
|
|
|
2388
2480
|
setIsTTSAvailable(true);
|
|
2389
2481
|
}).catch((error) => {
|
|
2390
2482
|
if (error instanceof Error && error.name !== "AbortError") {
|
|
2391
|
-
console.warn("Failed to fetch TTS audio URLs:", error.message);
|
|
2392
2483
|
setIsTTSAvailable(false);
|
|
2393
2484
|
setTtsAudioUrls(null);
|
|
2394
2485
|
}
|
|
@@ -2995,7 +3086,8 @@ var RedactoNoticeConsent = ({
|
|
|
2995
3086
|
onDataElementToggle: handleDataElementCheckboxChange,
|
|
2996
3087
|
getTranslatedText,
|
|
2997
3088
|
isAlreadyConsented: true,
|
|
2998
|
-
selectedLanguage
|
|
3089
|
+
selectedLanguage,
|
|
3090
|
+
initialDataElementSelections
|
|
2999
3091
|
},
|
|
3000
3092
|
`${purpose.uuid}-${selectedLanguage}`
|
|
3001
3093
|
)),
|
|
@@ -3065,12 +3157,12 @@ var RedactoNoticeConsent = ({
|
|
|
3065
3157
|
opacity: acceptDisabled ? 0.5 : 1
|
|
3066
3158
|
},
|
|
3067
3159
|
onClick: handleAccept,
|
|
3068
|
-
disabled: acceptDisabled,
|
|
3160
|
+
disabled: acceptDisabled || isSubmittingDecline,
|
|
3069
3161
|
"aria-label": getTranslatedText(
|
|
3070
3162
|
"confirm_button_text",
|
|
3071
3163
|
(content == null ? void 0 : content.confirm_button_text) || "Accept"
|
|
3072
3164
|
),
|
|
3073
|
-
children:
|
|
3165
|
+
children: isSubmittingAccept ? "Processing..." : getTranslatedText(
|
|
3074
3166
|
"confirm_button_text",
|
|
3075
3167
|
(content == null ? void 0 : content.confirm_button_text) || "Accept"
|
|
3076
3168
|
)
|
|
@@ -3084,15 +3176,16 @@ var RedactoNoticeConsent = ({
|
|
|
3084
3176
|
...styles.button,
|
|
3085
3177
|
...responsiveStyles.button,
|
|
3086
3178
|
...styles.cancelButton,
|
|
3087
|
-
...declineButtonStyle
|
|
3179
|
+
...declineButtonStyle,
|
|
3180
|
+
opacity: isSubmittingAccept ? 0.5 : 1
|
|
3088
3181
|
},
|
|
3089
3182
|
onClick: handleDecline,
|
|
3090
|
-
disabled:
|
|
3183
|
+
disabled: isSubmittingDecline || isSubmittingAccept,
|
|
3091
3184
|
"aria-label": getTranslatedText(
|
|
3092
3185
|
"decline_button_text",
|
|
3093
3186
|
(content == null ? void 0 : content.decline_button_text) || "Decline"
|
|
3094
3187
|
),
|
|
3095
|
-
children:
|
|
3188
|
+
children: isSubmittingDecline ? "Processing..." : getTranslatedText(
|
|
3096
3189
|
"decline_button_text",
|
|
3097
3190
|
(content == null ? void 0 : content.decline_button_text) || "Decline"
|
|
3098
3191
|
)
|
|
@@ -3152,7 +3245,6 @@ var fetchConsentContent2 = async ({
|
|
|
3152
3245
|
const data = await response.json();
|
|
3153
3246
|
return data;
|
|
3154
3247
|
} catch (error) {
|
|
3155
|
-
console.error("Error fetching consent content:", error);
|
|
3156
3248
|
throw error;
|
|
3157
3249
|
}
|
|
3158
3250
|
};
|
|
@@ -3168,31 +3260,61 @@ var submitConsentEvent2 = async ({
|
|
|
3168
3260
|
}) => {
|
|
3169
3261
|
var _a, _b;
|
|
3170
3262
|
try {
|
|
3171
|
-
const primaryEmail = localStorage.getItem("userEmail");
|
|
3172
|
-
const payload = {
|
|
3173
|
-
primary_email: primaryEmail || void 0,
|
|
3174
|
-
notice_uuid: noticeUuid,
|
|
3175
|
-
source: "WEB",
|
|
3176
|
-
declined,
|
|
3177
|
-
consents: {
|
|
3178
|
-
purposes: purposes.map((purpose) => ({
|
|
3179
|
-
uuid: purpose.uuid,
|
|
3180
|
-
name: purpose.name,
|
|
3181
|
-
description: purpose.description,
|
|
3182
|
-
industries: purpose.industries || "",
|
|
3183
|
-
selected: purpose.selected,
|
|
3184
|
-
data_elements: purpose.data_elements.map((element) => ({
|
|
3185
|
-
uuid: element.uuid,
|
|
3186
|
-
name: element.name,
|
|
3187
|
-
enabled: element.enabled,
|
|
3188
|
-
required: element.required,
|
|
3189
|
-
selected: element.required ? true : element.selected
|
|
3190
|
-
}))
|
|
3191
|
-
}))
|
|
3192
|
-
},
|
|
3193
|
-
meta_data
|
|
3194
|
-
};
|
|
3195
3263
|
const apiBaseUrl = baseUrl || BASE_URL2;
|
|
3264
|
+
let payload;
|
|
3265
|
+
if (isLegacyApi(apiBaseUrl)) {
|
|
3266
|
+
const primaryEmail = typeof window !== "undefined" ? localStorage.getItem("userEmail") : null;
|
|
3267
|
+
payload = {
|
|
3268
|
+
primary_email: primaryEmail || void 0,
|
|
3269
|
+
notice_uuid: noticeUuid,
|
|
3270
|
+
source: "WEB",
|
|
3271
|
+
declined: Boolean(declined),
|
|
3272
|
+
consents: {
|
|
3273
|
+
purposes: purposes.map((purpose) => {
|
|
3274
|
+
if (!purpose.uuid) {
|
|
3275
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
3276
|
+
}
|
|
3277
|
+
return {
|
|
3278
|
+
uuid: purpose.uuid,
|
|
3279
|
+
name: purpose.name,
|
|
3280
|
+
description: purpose.description || "",
|
|
3281
|
+
industries: purpose.industries || "",
|
|
3282
|
+
selected: Boolean(purpose.selected),
|
|
3283
|
+
data_elements: (purpose.data_elements || []).map((element) => ({
|
|
3284
|
+
uuid: element.uuid,
|
|
3285
|
+
name: element.name,
|
|
3286
|
+
enabled: Boolean(element.enabled),
|
|
3287
|
+
required: Boolean(element.required),
|
|
3288
|
+
selected: element.required ? true : Boolean(element.selected)
|
|
3289
|
+
}))
|
|
3290
|
+
};
|
|
3291
|
+
})
|
|
3292
|
+
},
|
|
3293
|
+
meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
|
|
3294
|
+
};
|
|
3295
|
+
} else {
|
|
3296
|
+
payload = {
|
|
3297
|
+
notice_uuid: noticeUuid,
|
|
3298
|
+
purposes: purposes.map((purpose) => {
|
|
3299
|
+
if (!purpose.uuid) {
|
|
3300
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
3301
|
+
}
|
|
3302
|
+
const dataElements = purpose.data_elements.filter((element) => element.enabled).map((element) => ({
|
|
3303
|
+
uuid: element.uuid,
|
|
3304
|
+
selected: element.required ? true : Boolean(element.selected)
|
|
3305
|
+
}));
|
|
3306
|
+
return {
|
|
3307
|
+
purpose_uuid: purpose.uuid,
|
|
3308
|
+
selected: Boolean(purpose.selected),
|
|
3309
|
+
data_elements: dataElements.length > 0 ? dataElements : void 0
|
|
3310
|
+
};
|
|
3311
|
+
}),
|
|
3312
|
+
select_all_mandatory: false,
|
|
3313
|
+
source: "WEB",
|
|
3314
|
+
declined,
|
|
3315
|
+
meta_data
|
|
3316
|
+
};
|
|
3317
|
+
}
|
|
3196
3318
|
const response = await fetch(
|
|
3197
3319
|
`${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/submit-consent`,
|
|
3198
3320
|
{
|
|
@@ -3229,7 +3351,6 @@ var submitConsentEvent2 = async ({
|
|
|
3229
3351
|
throw error;
|
|
3230
3352
|
}
|
|
3231
3353
|
} catch (error) {
|
|
3232
|
-
console.error("Error submitting consent event:", error);
|
|
3233
3354
|
throw error;
|
|
3234
3355
|
}
|
|
3235
3356
|
};
|
|
@@ -3747,13 +3868,12 @@ var RedactoConsentInlineComponent = ({
|
|
|
3747
3868
|
language,
|
|
3748
3869
|
specific_uuid: applicationId
|
|
3749
3870
|
});
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
);
|
|
3871
|
+
const activeConfig = consentContentData.detail.active_config;
|
|
3872
|
+
setContent(activeConfig);
|
|
3873
|
+
if (activeConfig.default_language) {
|
|
3874
|
+
setSelectedLanguage(activeConfig.default_language);
|
|
3755
3875
|
}
|
|
3756
|
-
const initialCollapsedState =
|
|
3876
|
+
const initialCollapsedState = activeConfig.purposes.reduce(
|
|
3757
3877
|
(acc, purpose) => ({
|
|
3758
3878
|
...acc,
|
|
3759
3879
|
[purpose.uuid]: true
|
|
@@ -3761,7 +3881,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
3761
3881
|
{}
|
|
3762
3882
|
);
|
|
3763
3883
|
setCollapsedPurposes(initialCollapsedState);
|
|
3764
|
-
const initialDataElementState =
|
|
3884
|
+
const initialDataElementState = activeConfig.purposes.reduce(
|
|
3765
3885
|
(acc, purpose) => {
|
|
3766
3886
|
purpose.data_elements.forEach((element) => {
|
|
3767
3887
|
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
@@ -3772,7 +3892,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
3772
3892
|
{}
|
|
3773
3893
|
);
|
|
3774
3894
|
setSelectedDataElements(initialDataElementState);
|
|
3775
|
-
const initialPurposeState =
|
|
3895
|
+
const initialPurposeState = activeConfig.purposes.reduce(
|
|
3776
3896
|
(acc, purpose) => {
|
|
3777
3897
|
return {
|
|
3778
3898
|
...acc,
|
|
@@ -3783,7 +3903,6 @@ var RedactoConsentInlineComponent = ({
|
|
|
3783
3903
|
);
|
|
3784
3904
|
setSelectedPurposes(initialPurposeState);
|
|
3785
3905
|
} catch (err) {
|
|
3786
|
-
console.error(err);
|
|
3787
3906
|
const error = err;
|
|
3788
3907
|
setFetchError(error);
|
|
3789
3908
|
if (error.status === 409) {
|
|
@@ -3898,13 +4017,9 @@ var RedactoConsentInlineComponent = ({
|
|
|
3898
4017
|
onAccept == null ? void 0 : onAccept();
|
|
3899
4018
|
hasSubmittedRef.current = false;
|
|
3900
4019
|
} catch (error) {
|
|
3901
|
-
console.error("Error submitting consent:", error);
|
|
3902
4020
|
const err = error;
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
"An error occurred while submitting your consent. Please try again later."
|
|
3906
|
-
);
|
|
3907
|
-
}
|
|
4021
|
+
const message = err.status === 500 ? "An error occurred while submitting your consent. Please try again later." : err.message || "Failed to submit consent. Please try again.";
|
|
4022
|
+
setErrorMessage(message);
|
|
3908
4023
|
hasSubmittedRef.current = false;
|
|
3909
4024
|
throw error;
|
|
3910
4025
|
} finally {
|
|
@@ -3929,7 +4044,6 @@ var RedactoConsentInlineComponent = ({
|
|
|
3929
4044
|
try {
|
|
3930
4045
|
await handleAcceptWithToken(accessToken);
|
|
3931
4046
|
} catch (err) {
|
|
3932
|
-
console.error("Failed to auto-submit consent:", err);
|
|
3933
4047
|
hasSubmittedRef.current = false;
|
|
3934
4048
|
onError == null ? void 0 : onError(err);
|
|
3935
4049
|
}
|