@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.mjs
CHANGED
|
@@ -3,6 +3,21 @@ import { useCallback, useEffect as useEffect2, useMemo, useRef, useState as useS
|
|
|
3
3
|
|
|
4
4
|
// src/RedactoNoticeConsent/api/index.ts
|
|
5
5
|
import { jwtDecode } from "jwt-decode";
|
|
6
|
+
|
|
7
|
+
// src/utils/isLegacyApi.ts
|
|
8
|
+
function isLegacyApi(baseUrl) {
|
|
9
|
+
try {
|
|
10
|
+
return new URL(baseUrl).hostname.endsWith(".redacto.io");
|
|
11
|
+
} catch {
|
|
12
|
+
try {
|
|
13
|
+
return new URL(`https://${baseUrl}`).hostname.endsWith(".redacto.io");
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/RedactoNoticeConsent/api/index.ts
|
|
6
21
|
var BASE_URL = "https://api.redacto.io/consent";
|
|
7
22
|
var apiCache = /* @__PURE__ */ new Map();
|
|
8
23
|
var CACHE_TTL = 5 * 60 * 1e3;
|
|
@@ -27,14 +42,6 @@ function decodeTokenSafely(token) {
|
|
|
27
42
|
return null;
|
|
28
43
|
}
|
|
29
44
|
}
|
|
30
|
-
var storage = {
|
|
31
|
-
getItem: (key) => {
|
|
32
|
-
if (typeof window !== "undefined") {
|
|
33
|
-
return localStorage.getItem(key);
|
|
34
|
-
}
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
45
|
var clearApiCache = () => {
|
|
39
46
|
apiCache.clear();
|
|
40
47
|
};
|
|
@@ -108,7 +115,6 @@ var fetchConsentContent = async ({
|
|
|
108
115
|
}
|
|
109
116
|
return data;
|
|
110
117
|
} catch (error) {
|
|
111
|
-
console.error("Error fetching consent content:", error instanceof Error ? error.message : error);
|
|
112
118
|
throw error;
|
|
113
119
|
}
|
|
114
120
|
};
|
|
@@ -134,42 +140,62 @@ var submitConsentEvent = async ({
|
|
|
134
140
|
if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
|
|
135
141
|
throw new Error("Invalid token: missing organization or workspace UUID");
|
|
136
142
|
}
|
|
137
|
-
const primaryEmail = storage.getItem("userEmail");
|
|
138
|
-
const validatedPurposes = purposes.map((purpose) => {
|
|
139
|
-
if (!purpose.uuid || !purpose.name) {
|
|
140
|
-
throw new Error(`Invalid purpose data: missing uuid or name`);
|
|
141
|
-
}
|
|
142
|
-
return {
|
|
143
|
-
uuid: purpose.uuid,
|
|
144
|
-
name: purpose.name,
|
|
145
|
-
description: purpose.description || "",
|
|
146
|
-
industries: purpose.industries || "",
|
|
147
|
-
selected: Boolean(purpose.selected),
|
|
148
|
-
data_elements: (purpose.data_elements || []).map((element) => {
|
|
149
|
-
if (!element.uuid || !element.name) {
|
|
150
|
-
throw new Error(`Invalid data element: missing uuid or name`);
|
|
151
|
-
}
|
|
152
|
-
return {
|
|
153
|
-
uuid: element.uuid,
|
|
154
|
-
name: element.name,
|
|
155
|
-
enabled: Boolean(element.enabled),
|
|
156
|
-
required: Boolean(element.required),
|
|
157
|
-
selected: element.required ? true : Boolean(element.selected)
|
|
158
|
-
};
|
|
159
|
-
})
|
|
160
|
-
};
|
|
161
|
-
});
|
|
162
|
-
const payload = {
|
|
163
|
-
primary_email: primaryEmail || void 0,
|
|
164
|
-
notice_uuid: noticeUuid,
|
|
165
|
-
source: "WEB",
|
|
166
|
-
declined: Boolean(declined),
|
|
167
|
-
consents: {
|
|
168
|
-
purposes: validatedPurposes
|
|
169
|
-
},
|
|
170
|
-
meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
|
|
171
|
-
};
|
|
172
143
|
const apiBaseUrl = baseUrl || BASE_URL;
|
|
144
|
+
let payload;
|
|
145
|
+
if (isLegacyApi(apiBaseUrl)) {
|
|
146
|
+
const primaryEmail = typeof window !== "undefined" ? localStorage.getItem("userEmail") : null;
|
|
147
|
+
payload = {
|
|
148
|
+
primary_email: primaryEmail || void 0,
|
|
149
|
+
notice_uuid: noticeUuid,
|
|
150
|
+
source: "WEB",
|
|
151
|
+
declined: Boolean(declined),
|
|
152
|
+
consents: {
|
|
153
|
+
purposes: purposes.map((purpose) => {
|
|
154
|
+
if (!purpose.uuid) {
|
|
155
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
uuid: purpose.uuid,
|
|
159
|
+
name: purpose.name,
|
|
160
|
+
description: purpose.description || "",
|
|
161
|
+
industries: purpose.industries || "",
|
|
162
|
+
selected: Boolean(purpose.selected),
|
|
163
|
+
data_elements: (purpose.data_elements || []).map((element) => ({
|
|
164
|
+
uuid: element.uuid,
|
|
165
|
+
name: element.name,
|
|
166
|
+
enabled: Boolean(element.enabled),
|
|
167
|
+
required: Boolean(element.required),
|
|
168
|
+
selected: element.required ? true : Boolean(element.selected)
|
|
169
|
+
}))
|
|
170
|
+
};
|
|
171
|
+
})
|
|
172
|
+
},
|
|
173
|
+
meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
|
|
174
|
+
};
|
|
175
|
+
} else {
|
|
176
|
+
const validatedPurposes = purposes.map((purpose) => {
|
|
177
|
+
if (!purpose.uuid) {
|
|
178
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
179
|
+
}
|
|
180
|
+
const dataElements = (purpose.data_elements || []).filter((element) => element.enabled).map((element) => ({
|
|
181
|
+
uuid: element.uuid,
|
|
182
|
+
selected: element.required ? true : Boolean(element.selected)
|
|
183
|
+
}));
|
|
184
|
+
return {
|
|
185
|
+
purpose_uuid: purpose.uuid,
|
|
186
|
+
selected: Boolean(purpose.selected),
|
|
187
|
+
data_elements: dataElements.length > 0 ? dataElements : void 0
|
|
188
|
+
};
|
|
189
|
+
});
|
|
190
|
+
payload = {
|
|
191
|
+
notice_uuid: noticeUuid,
|
|
192
|
+
purposes: validatedPurposes,
|
|
193
|
+
select_all_mandatory: false,
|
|
194
|
+
source: "WEB",
|
|
195
|
+
declined: Boolean(declined),
|
|
196
|
+
meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
|
|
197
|
+
};
|
|
198
|
+
}
|
|
173
199
|
const response = await fetch(
|
|
174
200
|
`${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/submit-consent`,
|
|
175
201
|
{
|
|
@@ -202,7 +228,6 @@ var submitConsentEvent = async ({
|
|
|
202
228
|
}
|
|
203
229
|
apiCache.clear();
|
|
204
230
|
} catch (error) {
|
|
205
|
-
console.error("Error submitting consent event:", error instanceof Error ? error.message : error);
|
|
206
231
|
throw error;
|
|
207
232
|
}
|
|
208
233
|
};
|
|
@@ -334,7 +359,6 @@ var fetchTTSAudioUrls = async ({
|
|
|
334
359
|
const data = await response.json();
|
|
335
360
|
return data;
|
|
336
361
|
} catch (error) {
|
|
337
|
-
console.error("Error fetching TTS audio URLs:", error instanceof Error ? error.message : error);
|
|
338
362
|
throw error;
|
|
339
363
|
}
|
|
340
364
|
};
|
|
@@ -872,7 +896,8 @@ var PurposeItem = ({
|
|
|
872
896
|
onDataElementToggle,
|
|
873
897
|
getTranslatedText,
|
|
874
898
|
isAlreadyConsented,
|
|
875
|
-
selectedLanguage
|
|
899
|
+
selectedLanguage,
|
|
900
|
+
initialDataElementSelections = {}
|
|
876
901
|
}) => {
|
|
877
902
|
const headingStyle = useMemo(
|
|
878
903
|
() => ({
|
|
@@ -1087,46 +1112,68 @@ var PurposeItem = ({
|
|
|
1087
1112
|
)}${dataElement.required ? " (required)" : ""}`
|
|
1088
1113
|
}
|
|
1089
1114
|
),
|
|
1090
|
-
isAlreadyConsented && /* @__PURE__ */ jsx(
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
width: "16px",
|
|
1098
|
-
height: "16px",
|
|
1099
|
-
borderRadius: "50%",
|
|
1100
|
-
backgroundColor: "#10B981"
|
|
1101
|
-
},
|
|
1102
|
-
"aria-label": `Already consented to ${getTranslatedText(
|
|
1103
|
-
`data_elements.name`,
|
|
1104
|
-
dataElement.name,
|
|
1105
|
-
dataElement.uuid
|
|
1106
|
-
)}`,
|
|
1107
|
-
children: /* @__PURE__ */ jsx(
|
|
1108
|
-
"svg",
|
|
1115
|
+
isAlreadyConsented && /* @__PURE__ */ jsx(Fragment, { children: (() => {
|
|
1116
|
+
const combinedId = `${purpose.uuid}-${dataElement.uuid}`;
|
|
1117
|
+
const isCurrentlySelected = selectedDataElements[combinedId] || false;
|
|
1118
|
+
const wasOriginallySelected = initialDataElementSelections[combinedId] || false;
|
|
1119
|
+
if (isCurrentlySelected && wasOriginallySelected) {
|
|
1120
|
+
return /* @__PURE__ */ jsx(
|
|
1121
|
+
"div",
|
|
1109
1122
|
{
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1123
|
+
style: {
|
|
1124
|
+
display: "flex",
|
|
1125
|
+
alignItems: "center",
|
|
1126
|
+
justifyContent: "center",
|
|
1127
|
+
width: "16px",
|
|
1128
|
+
height: "16px",
|
|
1129
|
+
borderRadius: "50%",
|
|
1130
|
+
backgroundColor: "#10B981"
|
|
1131
|
+
},
|
|
1132
|
+
"aria-label": `Already consented to ${getTranslatedText(
|
|
1133
|
+
`data_elements.name`,
|
|
1134
|
+
dataElement.name,
|
|
1135
|
+
dataElement.uuid
|
|
1136
|
+
)}`,
|
|
1116
1137
|
children: /* @__PURE__ */ jsx(
|
|
1117
|
-
"
|
|
1138
|
+
"svg",
|
|
1118
1139
|
{
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1140
|
+
width: "10",
|
|
1141
|
+
height: "10",
|
|
1142
|
+
viewBox: "0 0 10 10",
|
|
1143
|
+
fill: "none",
|
|
1144
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1145
|
+
"aria-hidden": "true",
|
|
1146
|
+
children: /* @__PURE__ */ jsx(
|
|
1147
|
+
"path",
|
|
1148
|
+
{
|
|
1149
|
+
d: "M3 5L4.5 6.5L7.5 3.5",
|
|
1150
|
+
stroke: "white",
|
|
1151
|
+
strokeWidth: "1.5",
|
|
1152
|
+
strokeLinecap: "round",
|
|
1153
|
+
strokeLinejoin: "round"
|
|
1154
|
+
}
|
|
1155
|
+
)
|
|
1124
1156
|
}
|
|
1125
1157
|
)
|
|
1126
1158
|
}
|
|
1127
|
-
)
|
|
1159
|
+
);
|
|
1160
|
+
} else {
|
|
1161
|
+
return /* @__PURE__ */ jsx(
|
|
1162
|
+
"input",
|
|
1163
|
+
{
|
|
1164
|
+
className: "redacto-checkbox-small",
|
|
1165
|
+
type: "checkbox",
|
|
1166
|
+
checked: isCurrentlySelected,
|
|
1167
|
+
onChange: () => onDataElementToggle(dataElement.uuid, purpose.uuid),
|
|
1168
|
+
"aria-label": `Select ${getTranslatedText(
|
|
1169
|
+
`data_elements.name`,
|
|
1170
|
+
dataElement.name,
|
|
1171
|
+
dataElement.uuid
|
|
1172
|
+
)}${dataElement.required ? " (required)" : ""}`
|
|
1173
|
+
}
|
|
1174
|
+
);
|
|
1128
1175
|
}
|
|
1129
|
-
)
|
|
1176
|
+
})() })
|
|
1130
1177
|
]
|
|
1131
1178
|
},
|
|
1132
1179
|
`${dataElement.uuid}-${selectedLanguage}`
|
|
@@ -1565,10 +1612,13 @@ var RedactoNoticeConsent = ({
|
|
|
1565
1612
|
}
|
|
1566
1613
|
const [isLoading, setIsLoading] = useState2(true);
|
|
1567
1614
|
const [isSubmitting, setIsSubmitting] = useState2(false);
|
|
1615
|
+
const [isSubmittingAccept, setIsSubmittingAccept] = useState2(false);
|
|
1616
|
+
const [isSubmittingDecline, setIsSubmittingDecline] = useState2(false);
|
|
1568
1617
|
const [content, setContent] = useState2(null);
|
|
1569
1618
|
const [categorizedPurposes, setCategorizedPurposes] = useState2(null);
|
|
1570
1619
|
const [selectedPurposes, setSelectedPurposes] = useState2({});
|
|
1571
1620
|
const [selectedDataElements, setSelectedDataElements] = useState2({});
|
|
1621
|
+
const [initialDataElementSelections, setInitialDataElementSelections] = useState2({});
|
|
1572
1622
|
const [collapsedPurposes, setCollapsedPurposes] = useState2({});
|
|
1573
1623
|
const [hasAlreadyConsented, setHasAlreadyConsented] = useState2(false);
|
|
1574
1624
|
const [isLanguageDropdownOpen, setIsLanguageDropdownOpen] = useState2(false);
|
|
@@ -1709,11 +1759,14 @@ var RedactoNoticeConsent = ({
|
|
|
1709
1759
|
setCategorizedPurposes(null);
|
|
1710
1760
|
setSelectedPurposes({});
|
|
1711
1761
|
setSelectedDataElements({});
|
|
1762
|
+
setInitialDataElementSelections({});
|
|
1712
1763
|
setCollapsedPurposes({});
|
|
1713
1764
|
setHasAlreadyConsented(false);
|
|
1714
1765
|
setErrorMessage(null);
|
|
1715
1766
|
setFetchError(null);
|
|
1716
1767
|
setIsLoading(true);
|
|
1768
|
+
setIsSubmittingAccept(false);
|
|
1769
|
+
setIsSubmittingDecline(false);
|
|
1717
1770
|
setShowAgeVerification(false);
|
|
1718
1771
|
setShowGuardianForm(false);
|
|
1719
1772
|
setIsSubmittingGuardian(false);
|
|
@@ -1796,14 +1849,15 @@ var RedactoNoticeConsent = ({
|
|
|
1796
1849
|
validate_against: validateAgainst,
|
|
1797
1850
|
signal: (_a2 = abortControllerRef.current) == null ? void 0 : _a2.signal
|
|
1798
1851
|
});
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1852
|
+
const activeConfig = consentContentData.detail.active_config;
|
|
1853
|
+
setContent(activeConfig);
|
|
1854
|
+
if (activeConfig.default_language) {
|
|
1855
|
+
const defaultLang = activeConfig.default_language;
|
|
1802
1856
|
setSelectedLanguage(
|
|
1803
1857
|
defaultLang === "en" || defaultLang === "EN" ? "English" : defaultLang
|
|
1804
1858
|
);
|
|
1805
1859
|
}
|
|
1806
|
-
const initialCollapsedState =
|
|
1860
|
+
const initialCollapsedState = activeConfig.purposes.reduce(
|
|
1807
1861
|
(acc, purpose) => ({
|
|
1808
1862
|
...acc,
|
|
1809
1863
|
[purpose.uuid]: true
|
|
@@ -1814,13 +1868,13 @@ var RedactoNoticeConsent = ({
|
|
|
1814
1868
|
const isReconsentRequired = consentContentData.detail.reconsent_required;
|
|
1815
1869
|
const purposeSelections = consentContentData.detail.purpose_selections;
|
|
1816
1870
|
const newCategorizedPurposes = isReconsentRequired ? {
|
|
1817
|
-
alreadyConsented:
|
|
1871
|
+
alreadyConsented: activeConfig.purposes.filter(
|
|
1818
1872
|
(purpose) => {
|
|
1819
1873
|
const selection = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid];
|
|
1820
1874
|
return selection && (selection.status === "ACTIVE" || selection.status === "EXPIRED") && !selection.needs_reconsent;
|
|
1821
1875
|
}
|
|
1822
1876
|
),
|
|
1823
|
-
needsConsent:
|
|
1877
|
+
needsConsent: activeConfig.purposes.filter(
|
|
1824
1878
|
(purpose) => {
|
|
1825
1879
|
const selection = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid];
|
|
1826
1880
|
return !selection || selection.status !== "ACTIVE" || selection.needs_reconsent;
|
|
@@ -1828,7 +1882,7 @@ var RedactoNoticeConsent = ({
|
|
|
1828
1882
|
)
|
|
1829
1883
|
} : null;
|
|
1830
1884
|
setCategorizedPurposes(newCategorizedPurposes);
|
|
1831
|
-
const initialPurposeState =
|
|
1885
|
+
const initialPurposeState = activeConfig.purposes.reduce(
|
|
1832
1886
|
(acc, purpose) => {
|
|
1833
1887
|
if (isReconsentRequired && (purposeSelections == null ? void 0 : purposeSelections[purpose.uuid])) {
|
|
1834
1888
|
acc[purpose.uuid] = purposeSelections[purpose.uuid].selected;
|
|
@@ -1840,7 +1894,7 @@ var RedactoNoticeConsent = ({
|
|
|
1840
1894
|
{}
|
|
1841
1895
|
);
|
|
1842
1896
|
setSelectedPurposes(initialPurposeState);
|
|
1843
|
-
const initialDataElementState =
|
|
1897
|
+
const initialDataElementState = activeConfig.purposes.reduce(
|
|
1844
1898
|
(acc, purpose) => {
|
|
1845
1899
|
purpose.data_elements.forEach((element) => {
|
|
1846
1900
|
var _a3, _b2;
|
|
@@ -1856,6 +1910,23 @@ var RedactoNoticeConsent = ({
|
|
|
1856
1910
|
{}
|
|
1857
1911
|
);
|
|
1858
1912
|
setSelectedDataElements(initialDataElementState);
|
|
1913
|
+
if (isReconsentRequired && newCategorizedPurposes) {
|
|
1914
|
+
const initialSelections = {};
|
|
1915
|
+
newCategorizedPurposes.alreadyConsented.forEach((purpose) => {
|
|
1916
|
+
purpose.data_elements.forEach((element) => {
|
|
1917
|
+
var _a3, _b2;
|
|
1918
|
+
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
1919
|
+
if ((_b2 = (_a3 = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid]) == null ? void 0 : _a3.data_elements) == null ? void 0 : _b2[element.uuid]) {
|
|
1920
|
+
initialSelections[combinedId] = purposeSelections[purpose.uuid].data_elements[element.uuid].selected;
|
|
1921
|
+
} else {
|
|
1922
|
+
initialSelections[combinedId] = false;
|
|
1923
|
+
}
|
|
1924
|
+
});
|
|
1925
|
+
});
|
|
1926
|
+
setInitialDataElementSelections(initialSelections);
|
|
1927
|
+
} else {
|
|
1928
|
+
setInitialDataElementSelections({});
|
|
1929
|
+
}
|
|
1859
1930
|
if (consentContentData.detail.is_minor) {
|
|
1860
1931
|
setShowAgeVerification(true);
|
|
1861
1932
|
}
|
|
@@ -1864,7 +1935,6 @@ var RedactoNoticeConsent = ({
|
|
|
1864
1935
|
if (err instanceof Error && err.name === "AbortError") {
|
|
1865
1936
|
return;
|
|
1866
1937
|
}
|
|
1867
|
-
console.error(err);
|
|
1868
1938
|
const error = err;
|
|
1869
1939
|
setFetchError(error);
|
|
1870
1940
|
if (error.status === 409) {
|
|
@@ -1956,6 +2026,7 @@ var RedactoNoticeConsent = ({
|
|
|
1956
2026
|
const handleAccept = async () => {
|
|
1957
2027
|
const submitController = new AbortController();
|
|
1958
2028
|
try {
|
|
2029
|
+
setIsSubmittingAccept(true);
|
|
1959
2030
|
setIsSubmitting(true);
|
|
1960
2031
|
setErrorMessage(null);
|
|
1961
2032
|
if (content) {
|
|
@@ -1963,14 +2034,31 @@ var RedactoNoticeConsent = ({
|
|
|
1963
2034
|
accessToken,
|
|
1964
2035
|
baseUrl,
|
|
1965
2036
|
noticeUuid: content.notice_uuid,
|
|
1966
|
-
purposes: content.purposes.map((purpose) =>
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
2037
|
+
purposes: content.purposes.map((purpose) => {
|
|
2038
|
+
const isAlreadyConsented = (categorizedPurposes == null ? void 0 : categorizedPurposes.alreadyConsented.some(
|
|
2039
|
+
(p) => p.uuid === purpose.uuid
|
|
2040
|
+
)) || false;
|
|
2041
|
+
let purposeSelected = selectedPurposes[purpose.uuid] || false;
|
|
2042
|
+
if (isAlreadyConsented) {
|
|
2043
|
+
const wasModified = purpose.data_elements.some((element) => {
|
|
2044
|
+
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
2045
|
+
const currentSelection = selectedDataElements[combinedId] || false;
|
|
2046
|
+
const initialSelection = initialDataElementSelections[combinedId] || false;
|
|
2047
|
+
return currentSelection !== initialSelection;
|
|
2048
|
+
});
|
|
2049
|
+
if (wasModified) {
|
|
2050
|
+
purposeSelected = true;
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
return {
|
|
2054
|
+
...purpose,
|
|
2055
|
+
selected: purposeSelected,
|
|
2056
|
+
data_elements: purpose.data_elements.map((element) => ({
|
|
2057
|
+
...element,
|
|
2058
|
+
selected: element.required ? true : selectedDataElements[`${purpose.uuid}-${element.uuid}`] || false
|
|
2059
|
+
}))
|
|
2060
|
+
};
|
|
2061
|
+
}),
|
|
1974
2062
|
declined: false,
|
|
1975
2063
|
meta_data: applicationId ? { specific_uuid: applicationId } : void 0,
|
|
1976
2064
|
signal: submitController.signal
|
|
@@ -1981,20 +2069,24 @@ var RedactoNoticeConsent = ({
|
|
|
1981
2069
|
if (error instanceof Error && error.name === "AbortError") {
|
|
1982
2070
|
return;
|
|
1983
2071
|
}
|
|
1984
|
-
console.error("Error submitting consent:", error);
|
|
1985
2072
|
const err = error;
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
"An error occurred while submitting your consent. Please try again later."
|
|
1989
|
-
);
|
|
1990
|
-
}
|
|
2073
|
+
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.";
|
|
2074
|
+
setErrorMessage(message);
|
|
1991
2075
|
onError == null ? void 0 : onError(error);
|
|
1992
2076
|
} finally {
|
|
2077
|
+
setIsSubmittingAccept(false);
|
|
1993
2078
|
setIsSubmitting(false);
|
|
1994
2079
|
}
|
|
1995
2080
|
};
|
|
1996
2081
|
const handleDecline = useCallback(async () => {
|
|
1997
|
-
|
|
2082
|
+
try {
|
|
2083
|
+
setIsSubmittingDecline(true);
|
|
2084
|
+
setIsSubmitting(true);
|
|
2085
|
+
onDecline == null ? void 0 : onDecline();
|
|
2086
|
+
} finally {
|
|
2087
|
+
setIsSubmittingDecline(false);
|
|
2088
|
+
setIsSubmitting(false);
|
|
2089
|
+
}
|
|
1998
2090
|
}, [onDecline]);
|
|
1999
2091
|
const handleGuardianFormChange = useCallback(
|
|
2000
2092
|
(field, value) => {
|
|
@@ -2361,7 +2453,6 @@ var RedactoNoticeConsent = ({
|
|
|
2361
2453
|
setIsTTSAvailable(true);
|
|
2362
2454
|
}).catch((error) => {
|
|
2363
2455
|
if (error instanceof Error && error.name !== "AbortError") {
|
|
2364
|
-
console.warn("Failed to fetch TTS audio URLs:", error.message);
|
|
2365
2456
|
setIsTTSAvailable(false);
|
|
2366
2457
|
setTtsAudioUrls(null);
|
|
2367
2458
|
}
|
|
@@ -2968,7 +3059,8 @@ var RedactoNoticeConsent = ({
|
|
|
2968
3059
|
onDataElementToggle: handleDataElementCheckboxChange,
|
|
2969
3060
|
getTranslatedText,
|
|
2970
3061
|
isAlreadyConsented: true,
|
|
2971
|
-
selectedLanguage
|
|
3062
|
+
selectedLanguage,
|
|
3063
|
+
initialDataElementSelections
|
|
2972
3064
|
},
|
|
2973
3065
|
`${purpose.uuid}-${selectedLanguage}`
|
|
2974
3066
|
)),
|
|
@@ -3038,12 +3130,12 @@ var RedactoNoticeConsent = ({
|
|
|
3038
3130
|
opacity: acceptDisabled ? 0.5 : 1
|
|
3039
3131
|
},
|
|
3040
3132
|
onClick: handleAccept,
|
|
3041
|
-
disabled: acceptDisabled,
|
|
3133
|
+
disabled: acceptDisabled || isSubmittingDecline,
|
|
3042
3134
|
"aria-label": getTranslatedText(
|
|
3043
3135
|
"confirm_button_text",
|
|
3044
3136
|
(content == null ? void 0 : content.confirm_button_text) || "Accept"
|
|
3045
3137
|
),
|
|
3046
|
-
children:
|
|
3138
|
+
children: isSubmittingAccept ? "Processing..." : getTranslatedText(
|
|
3047
3139
|
"confirm_button_text",
|
|
3048
3140
|
(content == null ? void 0 : content.confirm_button_text) || "Accept"
|
|
3049
3141
|
)
|
|
@@ -3057,15 +3149,16 @@ var RedactoNoticeConsent = ({
|
|
|
3057
3149
|
...styles.button,
|
|
3058
3150
|
...responsiveStyles.button,
|
|
3059
3151
|
...styles.cancelButton,
|
|
3060
|
-
...declineButtonStyle
|
|
3152
|
+
...declineButtonStyle,
|
|
3153
|
+
opacity: isSubmittingAccept ? 0.5 : 1
|
|
3061
3154
|
},
|
|
3062
3155
|
onClick: handleDecline,
|
|
3063
|
-
disabled:
|
|
3156
|
+
disabled: isSubmittingDecline || isSubmittingAccept,
|
|
3064
3157
|
"aria-label": getTranslatedText(
|
|
3065
3158
|
"decline_button_text",
|
|
3066
3159
|
(content == null ? void 0 : content.decline_button_text) || "Decline"
|
|
3067
3160
|
),
|
|
3068
|
-
children:
|
|
3161
|
+
children: isSubmittingDecline ? "Processing..." : getTranslatedText(
|
|
3069
3162
|
"decline_button_text",
|
|
3070
3163
|
(content == null ? void 0 : content.decline_button_text) || "Decline"
|
|
3071
3164
|
)
|
|
@@ -3125,7 +3218,6 @@ var fetchConsentContent2 = async ({
|
|
|
3125
3218
|
const data = await response.json();
|
|
3126
3219
|
return data;
|
|
3127
3220
|
} catch (error) {
|
|
3128
|
-
console.error("Error fetching consent content:", error);
|
|
3129
3221
|
throw error;
|
|
3130
3222
|
}
|
|
3131
3223
|
};
|
|
@@ -3141,31 +3233,61 @@ var submitConsentEvent2 = async ({
|
|
|
3141
3233
|
}) => {
|
|
3142
3234
|
var _a, _b;
|
|
3143
3235
|
try {
|
|
3144
|
-
const primaryEmail = localStorage.getItem("userEmail");
|
|
3145
|
-
const payload = {
|
|
3146
|
-
primary_email: primaryEmail || void 0,
|
|
3147
|
-
notice_uuid: noticeUuid,
|
|
3148
|
-
source: "WEB",
|
|
3149
|
-
declined,
|
|
3150
|
-
consents: {
|
|
3151
|
-
purposes: purposes.map((purpose) => ({
|
|
3152
|
-
uuid: purpose.uuid,
|
|
3153
|
-
name: purpose.name,
|
|
3154
|
-
description: purpose.description,
|
|
3155
|
-
industries: purpose.industries || "",
|
|
3156
|
-
selected: purpose.selected,
|
|
3157
|
-
data_elements: purpose.data_elements.map((element) => ({
|
|
3158
|
-
uuid: element.uuid,
|
|
3159
|
-
name: element.name,
|
|
3160
|
-
enabled: element.enabled,
|
|
3161
|
-
required: element.required,
|
|
3162
|
-
selected: element.required ? true : element.selected
|
|
3163
|
-
}))
|
|
3164
|
-
}))
|
|
3165
|
-
},
|
|
3166
|
-
meta_data
|
|
3167
|
-
};
|
|
3168
3236
|
const apiBaseUrl = baseUrl || BASE_URL2;
|
|
3237
|
+
let payload;
|
|
3238
|
+
if (isLegacyApi(apiBaseUrl)) {
|
|
3239
|
+
const primaryEmail = typeof window !== "undefined" ? localStorage.getItem("userEmail") : null;
|
|
3240
|
+
payload = {
|
|
3241
|
+
primary_email: primaryEmail || void 0,
|
|
3242
|
+
notice_uuid: noticeUuid,
|
|
3243
|
+
source: "WEB",
|
|
3244
|
+
declined: Boolean(declined),
|
|
3245
|
+
consents: {
|
|
3246
|
+
purposes: purposes.map((purpose) => {
|
|
3247
|
+
if (!purpose.uuid) {
|
|
3248
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
3249
|
+
}
|
|
3250
|
+
return {
|
|
3251
|
+
uuid: purpose.uuid,
|
|
3252
|
+
name: purpose.name,
|
|
3253
|
+
description: purpose.description || "",
|
|
3254
|
+
industries: purpose.industries || "",
|
|
3255
|
+
selected: Boolean(purpose.selected),
|
|
3256
|
+
data_elements: (purpose.data_elements || []).map((element) => ({
|
|
3257
|
+
uuid: element.uuid,
|
|
3258
|
+
name: element.name,
|
|
3259
|
+
enabled: Boolean(element.enabled),
|
|
3260
|
+
required: Boolean(element.required),
|
|
3261
|
+
selected: element.required ? true : Boolean(element.selected)
|
|
3262
|
+
}))
|
|
3263
|
+
};
|
|
3264
|
+
})
|
|
3265
|
+
},
|
|
3266
|
+
meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
|
|
3267
|
+
};
|
|
3268
|
+
} else {
|
|
3269
|
+
payload = {
|
|
3270
|
+
notice_uuid: noticeUuid,
|
|
3271
|
+
purposes: purposes.map((purpose) => {
|
|
3272
|
+
if (!purpose.uuid) {
|
|
3273
|
+
throw new Error(`Invalid purpose data: missing uuid`);
|
|
3274
|
+
}
|
|
3275
|
+
const dataElements = purpose.data_elements.filter((element) => element.enabled).map((element) => ({
|
|
3276
|
+
uuid: element.uuid,
|
|
3277
|
+
selected: element.required ? true : Boolean(element.selected)
|
|
3278
|
+
}));
|
|
3279
|
+
return {
|
|
3280
|
+
purpose_uuid: purpose.uuid,
|
|
3281
|
+
selected: Boolean(purpose.selected),
|
|
3282
|
+
data_elements: dataElements.length > 0 ? dataElements : void 0
|
|
3283
|
+
};
|
|
3284
|
+
}),
|
|
3285
|
+
select_all_mandatory: false,
|
|
3286
|
+
source: "WEB",
|
|
3287
|
+
declined,
|
|
3288
|
+
meta_data
|
|
3289
|
+
};
|
|
3290
|
+
}
|
|
3169
3291
|
const response = await fetch(
|
|
3170
3292
|
`${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/submit-consent`,
|
|
3171
3293
|
{
|
|
@@ -3202,7 +3324,6 @@ var submitConsentEvent2 = async ({
|
|
|
3202
3324
|
throw error;
|
|
3203
3325
|
}
|
|
3204
3326
|
} catch (error) {
|
|
3205
|
-
console.error("Error submitting consent event:", error);
|
|
3206
3327
|
throw error;
|
|
3207
3328
|
}
|
|
3208
3329
|
};
|
|
@@ -3720,13 +3841,12 @@ var RedactoConsentInlineComponent = ({
|
|
|
3720
3841
|
language,
|
|
3721
3842
|
specific_uuid: applicationId
|
|
3722
3843
|
});
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
);
|
|
3844
|
+
const activeConfig = consentContentData.detail.active_config;
|
|
3845
|
+
setContent(activeConfig);
|
|
3846
|
+
if (activeConfig.default_language) {
|
|
3847
|
+
setSelectedLanguage(activeConfig.default_language);
|
|
3728
3848
|
}
|
|
3729
|
-
const initialCollapsedState =
|
|
3849
|
+
const initialCollapsedState = activeConfig.purposes.reduce(
|
|
3730
3850
|
(acc, purpose) => ({
|
|
3731
3851
|
...acc,
|
|
3732
3852
|
[purpose.uuid]: true
|
|
@@ -3734,7 +3854,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
3734
3854
|
{}
|
|
3735
3855
|
);
|
|
3736
3856
|
setCollapsedPurposes(initialCollapsedState);
|
|
3737
|
-
const initialDataElementState =
|
|
3857
|
+
const initialDataElementState = activeConfig.purposes.reduce(
|
|
3738
3858
|
(acc, purpose) => {
|
|
3739
3859
|
purpose.data_elements.forEach((element) => {
|
|
3740
3860
|
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
@@ -3745,7 +3865,7 @@ var RedactoConsentInlineComponent = ({
|
|
|
3745
3865
|
{}
|
|
3746
3866
|
);
|
|
3747
3867
|
setSelectedDataElements(initialDataElementState);
|
|
3748
|
-
const initialPurposeState =
|
|
3868
|
+
const initialPurposeState = activeConfig.purposes.reduce(
|
|
3749
3869
|
(acc, purpose) => {
|
|
3750
3870
|
return {
|
|
3751
3871
|
...acc,
|
|
@@ -3756,7 +3876,6 @@ var RedactoConsentInlineComponent = ({
|
|
|
3756
3876
|
);
|
|
3757
3877
|
setSelectedPurposes(initialPurposeState);
|
|
3758
3878
|
} catch (err) {
|
|
3759
|
-
console.error(err);
|
|
3760
3879
|
const error = err;
|
|
3761
3880
|
setFetchError(error);
|
|
3762
3881
|
if (error.status === 409) {
|
|
@@ -3871,13 +3990,9 @@ var RedactoConsentInlineComponent = ({
|
|
|
3871
3990
|
onAccept == null ? void 0 : onAccept();
|
|
3872
3991
|
hasSubmittedRef.current = false;
|
|
3873
3992
|
} catch (error) {
|
|
3874
|
-
console.error("Error submitting consent:", error);
|
|
3875
3993
|
const err = error;
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
"An error occurred while submitting your consent. Please try again later."
|
|
3879
|
-
);
|
|
3880
|
-
}
|
|
3994
|
+
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.";
|
|
3995
|
+
setErrorMessage(message);
|
|
3881
3996
|
hasSubmittedRef.current = false;
|
|
3882
3997
|
throw error;
|
|
3883
3998
|
} finally {
|
|
@@ -3902,7 +4017,6 @@ var RedactoConsentInlineComponent = ({
|
|
|
3902
4017
|
try {
|
|
3903
4018
|
await handleAcceptWithToken(accessToken);
|
|
3904
4019
|
} catch (err) {
|
|
3905
|
-
console.error("Failed to auto-submit consent:", err);
|
|
3906
4020
|
hasSubmittedRef.current = false;
|
|
3907
4021
|
onError == null ? void 0 : onError(err);
|
|
3908
4022
|
}
|