@redacto.io/consent-sdk-react-native 1.0.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/dist/index.js ADDED
@@ -0,0 +1,2428 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ RedactoNoticeConsent: () => RedactoNoticeConsent,
34
+ RedactoNoticeConsentInline: () => RedactoConsentInline
35
+ });
36
+ module.exports = __toCommonJS(src_exports);
37
+
38
+ // src/RedactoNoticeConsent/RedactoNoticeConsent.tsx
39
+ var import_react = require("react");
40
+ var import_react_native4 = require("react-native");
41
+ var import_react_native_svg2 = __toESM(require("react-native-svg"));
42
+
43
+ // src/RedactoNoticeConsent/api/index.ts
44
+ var import_jwt_decode = require("jwt-decode");
45
+
46
+ // src/constants.ts
47
+ var DEFAULT_CONSENT_API_BASE_URL = "https://api.redacto.io/consent";
48
+
49
+ // src/RedactoNoticeConsent/api/index.ts
50
+ var apiCache = /* @__PURE__ */ new Map();
51
+ var CACHE_TTL = 5 * 60 * 1e3;
52
+ function getCachedData(key) {
53
+ const cached = apiCache.get(key);
54
+ if (cached && Date.now() - cached.timestamp < cached.ttl) {
55
+ return cached.data;
56
+ }
57
+ if (cached) {
58
+ apiCache.delete(key);
59
+ }
60
+ return null;
61
+ }
62
+ function setCachedData(key, data, ttl = CACHE_TTL) {
63
+ apiCache.set(key, { data, timestamp: Date.now(), ttl });
64
+ }
65
+ function decodeTokenSafely(token) {
66
+ try {
67
+ return (0, import_jwt_decode.jwtDecode)(token);
68
+ } catch (error) {
69
+ console.warn("Failed to decode JWT token:", error);
70
+ return null;
71
+ }
72
+ }
73
+ var clearApiCache = () => {
74
+ apiCache.clear();
75
+ };
76
+ var fetchConsentContent = async ({
77
+ noticeId,
78
+ accessToken,
79
+ baseUrl,
80
+ language = "en",
81
+ specific_uuid,
82
+ validate_against = "all",
83
+ include_fully_consented_data = false,
84
+ signal
85
+ }) => {
86
+ if (!noticeId || !accessToken || !validate_against) {
87
+ throw new Error("noticeId and accessToken are required");
88
+ }
89
+ const decodedToken = decodeTokenSafely(accessToken);
90
+ if (!decodedToken) {
91
+ throw new Error("Invalid access token");
92
+ }
93
+ const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
94
+ if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
95
+ throw new Error("Invalid token: missing organization or workspace UUID");
96
+ }
97
+ const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
98
+ const cacheKey = `${accessToken}-${noticeId}-${validate_against}-${language}-${specific_uuid || ""}-${include_fully_consented_data}`;
99
+ if (validate_against === "all" && !specific_uuid) {
100
+ const cachedData = getCachedData(cacheKey);
101
+ if (cachedData) {
102
+ return cachedData;
103
+ }
104
+ }
105
+ const url = new URL(
106
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeId}`
107
+ );
108
+ if (specific_uuid) {
109
+ url.searchParams.append("specific_uuid", specific_uuid);
110
+ }
111
+ url.searchParams.append("validate_against", validate_against);
112
+ if (include_fully_consented_data) {
113
+ url.searchParams.append("include_fully_consented_data", "true");
114
+ }
115
+ const response = await fetch(url.toString(), {
116
+ method: "GET",
117
+ headers: {
118
+ Authorization: `Bearer ${accessToken}`,
119
+ "Accept-Language": language,
120
+ "Content-Type": "application/json"
121
+ },
122
+ signal
123
+ });
124
+ if (!response.ok) {
125
+ let errorMessage = `Failed to fetch consent content: ${response.status} ${response.statusText}`;
126
+ if (response.status === 401) {
127
+ errorMessage = "Unauthorized: Invalid or expired token";
128
+ } else if (response.status === 403) {
129
+ errorMessage = "Forbidden: Access denied";
130
+ } else if (response.status === 404) {
131
+ errorMessage = "Notice not found";
132
+ } else if (response.status === 409) {
133
+ errorMessage = "User has already provided consent";
134
+ } else if (response.status >= 500) {
135
+ errorMessage = "Server error: Please try again later";
136
+ }
137
+ const error = new Error(errorMessage);
138
+ error.status = response.status;
139
+ throw error;
140
+ }
141
+ const data = await response.json();
142
+ if (validate_against === "all" && !specific_uuid) {
143
+ setCachedData(cacheKey, data);
144
+ }
145
+ return data;
146
+ };
147
+ var submitConsentEvent = async ({
148
+ accessToken,
149
+ baseUrl,
150
+ noticeUuid,
151
+ purposes,
152
+ declined,
153
+ meta_data,
154
+ signal
155
+ }) => {
156
+ if (!noticeUuid || !accessToken || !Array.isArray(purposes)) {
157
+ throw new Error("noticeUuid, accessToken, and purposes array are required");
158
+ }
159
+ const decodedToken = decodeTokenSafely(accessToken);
160
+ if (!decodedToken) {
161
+ throw new Error("Invalid access token");
162
+ }
163
+ const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
164
+ if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
165
+ throw new Error("Invalid token: missing organization or workspace UUID");
166
+ }
167
+ const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
168
+ const validatedPurposes = purposes.map((purpose) => {
169
+ if (!purpose.uuid) {
170
+ throw new Error("Invalid purpose data: missing uuid");
171
+ }
172
+ const dataElements = (purpose.data_elements || []).filter((element) => element.enabled).map((element) => ({
173
+ uuid: element.uuid,
174
+ selected: element.required ? true : Boolean(element.selected)
175
+ }));
176
+ return {
177
+ purpose_uuid: purpose.uuid,
178
+ selected: Boolean(purpose.selected),
179
+ data_elements: dataElements.length > 0 ? dataElements : void 0
180
+ };
181
+ });
182
+ const payload = {
183
+ notice_uuid: noticeUuid,
184
+ purposes: validatedPurposes,
185
+ select_all_mandatory: false,
186
+ source: "MOBILE",
187
+ declined: Boolean(declined),
188
+ meta_data: meta_data ? { specific_uuid: meta_data.specific_uuid } : void 0
189
+ };
190
+ const response = await fetch(
191
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/submit-consent`,
192
+ {
193
+ method: "POST",
194
+ headers: {
195
+ Authorization: `Bearer ${accessToken}`,
196
+ "Content-Type": "application/json"
197
+ },
198
+ body: JSON.stringify(payload),
199
+ signal
200
+ }
201
+ );
202
+ if (!response.ok) {
203
+ let errorMessage = `Failed to submit consent: ${response.status} ${response.statusText}`;
204
+ if (response.status === 400) {
205
+ errorMessage = "Invalid request data";
206
+ } else if (response.status === 401) {
207
+ errorMessage = "Unauthorized: Invalid or expired token";
208
+ } else if (response.status === 403) {
209
+ errorMessage = "Forbidden: Access denied";
210
+ } else if (response.status === 404) {
211
+ errorMessage = "Notice not found";
212
+ } else if (response.status >= 500) {
213
+ errorMessage = "Server error: Please try again later";
214
+ }
215
+ const error = new Error(errorMessage);
216
+ error.status = response.status;
217
+ throw error;
218
+ }
219
+ apiCache.clear();
220
+ };
221
+ var submitGuardianInfo = async ({
222
+ accessToken,
223
+ baseUrl,
224
+ guardianName,
225
+ guardianContact,
226
+ guardianRelationship,
227
+ signal
228
+ }) => {
229
+ if (!accessToken) {
230
+ throw new Error("accessToken is required");
231
+ }
232
+ if (!(guardianName == null ? void 0 : guardianName.trim())) {
233
+ throw new Error("guardianName is required and cannot be empty");
234
+ }
235
+ if (!(guardianContact == null ? void 0 : guardianContact.trim())) {
236
+ throw new Error("guardianContact is required and cannot be empty");
237
+ }
238
+ if (!(guardianRelationship == null ? void 0 : guardianRelationship.trim())) {
239
+ throw new Error("guardianRelationship is required and cannot be empty");
240
+ }
241
+ const decodedToken = decodeTokenSafely(accessToken);
242
+ if (!decodedToken) {
243
+ throw new Error("Invalid access token");
244
+ }
245
+ const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
246
+ if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
247
+ throw new Error("Invalid token: missing organization or workspace UUID");
248
+ }
249
+ const payload = {
250
+ guardian_name: guardianName.trim(),
251
+ guardian_contact: guardianContact.trim(),
252
+ guardian_relationship: guardianRelationship.trim()
253
+ };
254
+ const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
255
+ const response = await fetch(
256
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/guardian-info`,
257
+ {
258
+ method: "POST",
259
+ headers: {
260
+ Authorization: `Bearer ${accessToken}`,
261
+ "Content-Type": "application/json"
262
+ },
263
+ body: JSON.stringify(payload),
264
+ signal
265
+ }
266
+ );
267
+ if (!response.ok) {
268
+ let errorMessage = `Failed to submit guardian info: ${response.status} ${response.statusText}`;
269
+ if (response.status === 400) {
270
+ errorMessage = "Invalid request data";
271
+ } else if (response.status === 401) {
272
+ errorMessage = "Unauthorized: Invalid or expired token";
273
+ } else if (response.status === 403) {
274
+ errorMessage = "Forbidden: Access denied";
275
+ } else if (response.status === 404) {
276
+ errorMessage = "Organization or workspace not found";
277
+ } else if (response.status === 422) {
278
+ try {
279
+ const errorData = await response.json();
280
+ errorMessage = errorData.message || "Validation error";
281
+ } catch {
282
+ errorMessage = "Validation error: Please check your input";
283
+ }
284
+ } else if (response.status >= 500) {
285
+ errorMessage = "Server error: Please try again later";
286
+ }
287
+ const error = new Error(errorMessage);
288
+ error.status = response.status;
289
+ throw error;
290
+ }
291
+ };
292
+ var fetchTTSAudioUrls = async ({
293
+ accessToken,
294
+ baseUrl,
295
+ noticeUuid,
296
+ language,
297
+ signal
298
+ }) => {
299
+ if (!accessToken || !noticeUuid || !language) {
300
+ throw new Error("accessToken, noticeUuid, and language are required");
301
+ }
302
+ const decodedToken = decodeTokenSafely(accessToken);
303
+ if (!decodedToken) {
304
+ throw new Error("Invalid access token");
305
+ }
306
+ const { organisation_uuid: ORGANISATION_UUID, workspace_uuid: WORKSPACE_UUID } = decodedToken;
307
+ if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
308
+ throw new Error("Invalid token: missing organization or workspace UUID");
309
+ }
310
+ const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
311
+ const url = `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeUuid}/audio/${language}`;
312
+ const response = await fetch(url, {
313
+ method: "GET",
314
+ headers: {
315
+ Authorization: `Bearer ${accessToken}`,
316
+ Accept: "application/json",
317
+ "Content-Type": "application/json"
318
+ },
319
+ signal
320
+ });
321
+ if (!response.ok) {
322
+ let errorMessage = `Failed to fetch TTS audio URLs: ${response.status} ${response.statusText}`;
323
+ if (response.status === 401) {
324
+ errorMessage = "Unauthorized: Invalid or expired token";
325
+ } else if (response.status === 403) {
326
+ errorMessage = "Forbidden: Access denied";
327
+ } else if (response.status === 404) {
328
+ errorMessage = "Notice or audio not found";
329
+ } else if (response.status >= 500) {
330
+ errorMessage = "Server error: Please try again later";
331
+ }
332
+ const error = new Error(errorMessage);
333
+ error.status = response.status;
334
+ throw error;
335
+ }
336
+ return response.json();
337
+ };
338
+
339
+ // src/RedactoNoticeConsent/components/Checkbox.tsx
340
+ var import_react_native = require("react-native");
341
+ var import_react_native_svg = __toESM(require("react-native-svg"));
342
+ var import_jsx_runtime = require("react/jsx-runtime");
343
+ var Checkbox = ({
344
+ checked,
345
+ onChange,
346
+ size = "large",
347
+ disabled = false,
348
+ accessibilityLabel
349
+ }) => {
350
+ const isLarge = size === "large";
351
+ const boxSize = isLarge ? 20 : 16;
352
+ const iconSize = isLarge ? 10 : 8;
353
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
354
+ import_react_native.TouchableOpacity,
355
+ {
356
+ onPress: onChange,
357
+ disabled,
358
+ accessibilityRole: "checkbox",
359
+ accessibilityState: { checked, disabled },
360
+ accessibilityLabel,
361
+ hitSlop: { top: 6, bottom: 6, left: 6, right: 6 },
362
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
363
+ import_react_native.View,
364
+ {
365
+ style: [
366
+ styles.box,
367
+ { width: boxSize, height: boxSize, borderRadius: 5 },
368
+ checked ? styles.checked : styles.unchecked,
369
+ disabled && styles.disabled
370
+ ],
371
+ children: checked && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
372
+ import_react_native_svg.default,
373
+ {
374
+ width: iconSize,
375
+ height: iconSize,
376
+ viewBox: "0 0 10 10",
377
+ fill: "none",
378
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
379
+ import_react_native_svg.Path,
380
+ {
381
+ d: "M1.5 5L4 7.5L8.5 2.5",
382
+ stroke: "white",
383
+ strokeWidth: 1.8,
384
+ strokeLinecap: "round",
385
+ strokeLinejoin: "round"
386
+ }
387
+ )
388
+ }
389
+ )
390
+ }
391
+ )
392
+ }
393
+ );
394
+ };
395
+ var styles = import_react_native.StyleSheet.create({
396
+ box: {
397
+ alignItems: "center",
398
+ justifyContent: "center",
399
+ borderWidth: 2
400
+ },
401
+ checked: {
402
+ backgroundColor: "#4f87ff",
403
+ borderColor: "#4f87ff"
404
+ },
405
+ unchecked: {
406
+ backgroundColor: "transparent",
407
+ borderColor: "#d0d5dd"
408
+ },
409
+ disabled: {
410
+ opacity: 0.5
411
+ }
412
+ });
413
+
414
+ // src/RedactoNoticeConsent/styles.ts
415
+ var import_react_native2 = require("react-native");
416
+ var styles2 = import_react_native2.StyleSheet.create({
417
+ overlay: {
418
+ flex: 1,
419
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
420
+ alignItems: "center",
421
+ justifyContent: "center",
422
+ padding: 16
423
+ },
424
+ modal: {
425
+ width: "100%",
426
+ maxWidth: 700,
427
+ height: "90%",
428
+ borderRadius: 8,
429
+ backgroundColor: "#ffffff",
430
+ ...import_react_native2.Platform.select({
431
+ ios: {
432
+ shadowColor: "#000",
433
+ shadowOffset: { width: 0, height: 2 },
434
+ shadowOpacity: 0.25,
435
+ shadowRadius: 4
436
+ },
437
+ android: {
438
+ elevation: 5
439
+ }
440
+ }),
441
+ maxHeight: "90%",
442
+ minHeight: 320
443
+ },
444
+ content: {
445
+ padding: 22,
446
+ flex: 1,
447
+ minHeight: 0
448
+ },
449
+ topSection: {
450
+ flexDirection: "row",
451
+ justifyContent: "space-between",
452
+ alignItems: "center",
453
+ paddingBottom: 15,
454
+ backgroundColor: "#ffffff",
455
+ flexShrink: 0
456
+ },
457
+ topLeft: {
458
+ flexDirection: "row",
459
+ alignItems: "center",
460
+ gap: 10,
461
+ flex: 1
462
+ },
463
+ logo: {
464
+ height: 32,
465
+ width: 80,
466
+ resizeMode: "contain"
467
+ },
468
+ title: {
469
+ fontSize: 18,
470
+ fontWeight: "700",
471
+ lineHeight: 27,
472
+ letterSpacing: 0.2,
473
+ color: "#101828",
474
+ flexShrink: 1
475
+ },
476
+ topRight: {
477
+ borderRadius: 8,
478
+ paddingVertical: 3,
479
+ paddingHorizontal: 9,
480
+ borderWidth: 1,
481
+ borderColor: "#d0d5dd",
482
+ flexDirection: "row",
483
+ alignItems: "center",
484
+ justifyContent: "center",
485
+ backgroundColor: "#ffffff",
486
+ gap: 5
487
+ },
488
+ topRightText: {
489
+ fontWeight: "400",
490
+ fontSize: 12,
491
+ color: "#344054"
492
+ },
493
+ middleSection: {
494
+ flex: 1,
495
+ gap: 12,
496
+ minHeight: 0
497
+ },
498
+ privacyText: {
499
+ fontSize: 16,
500
+ fontWeight: "400",
501
+ lineHeight: 24,
502
+ color: "#344054"
503
+ },
504
+ link: {
505
+ color: "#4f87ff",
506
+ textDecorationLine: "underline"
507
+ },
508
+ subTitle: {
509
+ fontWeight: "600",
510
+ fontSize: 16,
511
+ lineHeight: 24,
512
+ letterSpacing: 0.2,
513
+ color: "#101828"
514
+ },
515
+ optionsContainer: {
516
+ gap: 10
517
+ },
518
+ optionItem: {
519
+ flexDirection: "row",
520
+ justifyContent: "space-between",
521
+ alignItems: "center"
522
+ },
523
+ optionLeft: {
524
+ flexDirection: "row",
525
+ gap: 12,
526
+ alignItems: "center",
527
+ flex: 1
528
+ },
529
+ optionTextContainer: {
530
+ flex: 1
531
+ },
532
+ optionTitle: {
533
+ fontWeight: "500",
534
+ fontSize: 16,
535
+ lineHeight: 24,
536
+ letterSpacing: 0.2,
537
+ color: "#101828"
538
+ },
539
+ optionDescription: {
540
+ fontWeight: "400",
541
+ fontSize: 12,
542
+ lineHeight: 18,
543
+ letterSpacing: 0.2,
544
+ color: "#475467"
545
+ },
546
+ dataElementsContainer: {
547
+ paddingLeft: 22
548
+ },
549
+ dataElementItem: {
550
+ flexDirection: "row",
551
+ alignItems: "center",
552
+ gap: 10,
553
+ justifyContent: "space-between",
554
+ minHeight: 24,
555
+ paddingVertical: 2
556
+ },
557
+ dataElementText: {
558
+ fontWeight: "400",
559
+ fontSize: 14,
560
+ lineHeight: 21,
561
+ letterSpacing: 0.2,
562
+ color: "#344054",
563
+ flex: 1
564
+ },
565
+ bottomSection: {
566
+ flexDirection: "row",
567
+ justifyContent: "space-between",
568
+ gap: 12,
569
+ paddingTop: 15,
570
+ backgroundColor: "#ffffff",
571
+ flexShrink: 0
572
+ },
573
+ button: {
574
+ flex: 1,
575
+ borderRadius: 8,
576
+ paddingVertical: 12,
577
+ paddingHorizontal: 20,
578
+ alignItems: "center",
579
+ justifyContent: "center"
580
+ },
581
+ buttonText: {
582
+ fontWeight: "400",
583
+ fontSize: 16,
584
+ lineHeight: 24,
585
+ textAlign: "center"
586
+ },
587
+ acceptButton: {
588
+ backgroundColor: "#4f87ff"
589
+ },
590
+ acceptButtonText: {
591
+ color: "#ffffff"
592
+ },
593
+ cancelButton: {
594
+ borderWidth: 1,
595
+ borderColor: "#d0d5dd",
596
+ backgroundColor: "#ffffff"
597
+ },
598
+ cancelButtonText: {
599
+ color: "#000000"
600
+ },
601
+ languageSelectorContainer: {
602
+ position: "relative"
603
+ },
604
+ languageDropdown: {
605
+ position: "absolute",
606
+ top: "100%",
607
+ right: 0,
608
+ backgroundColor: "#ffffff",
609
+ borderWidth: 1,
610
+ borderColor: "#d0d5dd",
611
+ borderRadius: 4,
612
+ zIndex: 10,
613
+ minWidth: 120,
614
+ maxHeight: 200,
615
+ marginTop: 4,
616
+ ...import_react_native2.Platform.select({
617
+ ios: {
618
+ shadowColor: "#000",
619
+ shadowOffset: { width: 0, height: 2 },
620
+ shadowOpacity: 0.1,
621
+ shadowRadius: 4
622
+ },
623
+ android: {
624
+ elevation: 4
625
+ }
626
+ })
627
+ },
628
+ languageItem: {
629
+ paddingVertical: 8,
630
+ paddingHorizontal: 12,
631
+ borderBottomWidth: 1,
632
+ borderBottomColor: "#e5e7eb"
633
+ },
634
+ languageItemText: {
635
+ fontSize: 12,
636
+ color: "#344054"
637
+ },
638
+ selectedLanguageItem: {
639
+ backgroundColor: "#f3f4f6"
640
+ },
641
+ selectedLanguageItemText: {
642
+ fontWeight: "600"
643
+ },
644
+ loadingContainer: {
645
+ flex: 1,
646
+ alignItems: "center",
647
+ justifyContent: "center",
648
+ padding: 32,
649
+ minHeight: 200
650
+ },
651
+ loadingText: {
652
+ marginTop: 16,
653
+ fontSize: 16,
654
+ color: "#344054"
655
+ },
656
+ errorContainer: {
657
+ backgroundColor: "#FEE2E2",
658
+ borderRadius: 6,
659
+ padding: 12,
660
+ marginBottom: 16,
661
+ borderWidth: 1,
662
+ borderColor: "#FCA5A5",
663
+ flexDirection: "row",
664
+ alignItems: "center",
665
+ justifyContent: "space-between"
666
+ },
667
+ errorText: {
668
+ color: "#DC2626",
669
+ fontSize: 14,
670
+ flex: 1
671
+ },
672
+ requiredAsterisk: {
673
+ color: "red"
674
+ },
675
+ divider: {
676
+ height: 1,
677
+ backgroundColor: "#e5e7eb",
678
+ marginVertical: 8
679
+ },
680
+ inputContainer: {
681
+ marginBottom: 12
682
+ },
683
+ inputLabel: {
684
+ fontSize: 13,
685
+ fontWeight: "500",
686
+ color: "#344054",
687
+ marginBottom: 6
688
+ },
689
+ textInput: {
690
+ borderWidth: 1,
691
+ borderColor: "#d0d5dd",
692
+ borderRadius: 8,
693
+ paddingVertical: 10,
694
+ paddingHorizontal: 12,
695
+ fontSize: 13,
696
+ color: "#344054",
697
+ backgroundColor: "#ffffff"
698
+ },
699
+ textInputError: {
700
+ borderColor: "#DC2626"
701
+ },
702
+ inputError: {
703
+ color: "#DC2626",
704
+ fontSize: 12,
705
+ marginTop: 4
706
+ },
707
+ consentedCheckmark: {
708
+ width: 20,
709
+ height: 20,
710
+ borderRadius: 10,
711
+ backgroundColor: "#10B981",
712
+ alignItems: "center",
713
+ justifyContent: "center",
714
+ marginLeft: 12
715
+ },
716
+ consentedCheckmarkSmall: {
717
+ width: 16,
718
+ height: 16,
719
+ borderRadius: 8,
720
+ backgroundColor: "#10B981",
721
+ alignItems: "center",
722
+ justifyContent: "center"
723
+ },
724
+ notConsentedCircle: {
725
+ width: 16,
726
+ height: 16,
727
+ borderRadius: 8,
728
+ borderWidth: 2,
729
+ borderColor: "#d0d5dd",
730
+ backgroundColor: "transparent"
731
+ },
732
+ purposeChevron: {
733
+ marginLeft: 5,
734
+ alignItems: "center",
735
+ justifyContent: "center"
736
+ }
737
+ });
738
+
739
+ // src/RedactoNoticeConsent/useResponsive.ts
740
+ var import_react_native3 = require("react-native");
741
+ var useResponsive = () => {
742
+ const { width, height } = (0, import_react_native3.useWindowDimensions)();
743
+ return {
744
+ isMobile: width < 768,
745
+ width,
746
+ height
747
+ };
748
+ };
749
+
750
+ // src/RedactoNoticeConsent/RedactoNoticeConsent.tsx
751
+ var import_jsx_runtime2 = require("react/jsx-runtime");
752
+ function stripHtml(html) {
753
+ return html.replace(/<[^>]*>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").trim();
754
+ }
755
+ var expoAv = null;
756
+ try {
757
+ expoAv = require("expo-av");
758
+ } catch {
759
+ }
760
+ var PurposeItem = ({
761
+ purpose,
762
+ selectedPurposes,
763
+ collapsedPurposes,
764
+ selectedDataElements,
765
+ settings,
766
+ onPurposeToggle,
767
+ onPurposeCollapse,
768
+ onDataElementToggle,
769
+ getTranslatedText,
770
+ isAlreadyConsented,
771
+ initialDataElementSelections = {}
772
+ }) => {
773
+ const headingColor = (settings == null ? void 0 : settings.headingColor) || "#101828";
774
+ const textColor = (settings == null ? void 0 : settings.textColor) || "#344054";
775
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { children: [
776
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.optionItem, children: [
777
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
778
+ import_react_native4.TouchableOpacity,
779
+ {
780
+ style: styles2.optionLeft,
781
+ onPress: () => onPurposeCollapse(purpose.uuid),
782
+ accessibilityRole: "button",
783
+ accessibilityLabel: `${collapsedPurposes[purpose.uuid] ? "Expand" : "Collapse"} ${getTranslatedText("purposes.name", purpose.name, purpose.uuid)} details`,
784
+ children: [
785
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.purposeChevron, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.default, { width: 7, height: 12, viewBox: "0 0 7 12", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
786
+ import_react_native_svg2.Path,
787
+ {
788
+ d: "M1 1L6 6L1 11",
789
+ stroke: (settings == null ? void 0 : settings.headingColor) || "#323B4B",
790
+ strokeWidth: 2,
791
+ strokeLinecap: "round",
792
+ strokeLinejoin: "round",
793
+ transform: !collapsedPurposes[purpose.uuid] ? "rotate(90 3.5 6)" : void 0
794
+ }
795
+ ) }) }),
796
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.optionTextContainer, children: [
797
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.optionTitle, { color: headingColor }], children: getTranslatedText("purposes.name", purpose.name, purpose.uuid) }),
798
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.optionDescription, { color: textColor }], children: getTranslatedText("purposes.description", purpose.description, purpose.uuid) })
799
+ ] })
800
+ ]
801
+ }
802
+ ),
803
+ !isAlreadyConsented && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
804
+ Checkbox,
805
+ {
806
+ checked: selectedPurposes[purpose.uuid] || false,
807
+ onChange: () => onPurposeToggle(purpose.uuid),
808
+ size: "large",
809
+ accessibilityLabel: `Select all data elements for ${getTranslatedText("purposes.name", purpose.name, purpose.uuid)}`
810
+ }
811
+ ),
812
+ isAlreadyConsented && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.consentedCheckmark, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.default, { width: 12, height: 12, viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
813
+ import_react_native_svg2.Path,
814
+ {
815
+ d: "M4 6L5.5 7.5L8.5 4.5",
816
+ stroke: "white",
817
+ strokeWidth: 2,
818
+ strokeLinecap: "round",
819
+ strokeLinejoin: "round"
820
+ }
821
+ ) }) })
822
+ ] }),
823
+ !collapsedPurposes[purpose.uuid] && purpose.data_elements && purpose.data_elements.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.dataElementsContainer, children: purpose.data_elements.map((dataElement) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.dataElementItem, children: [
824
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.Text, { style: [styles2.dataElementText, { color: textColor }], children: [
825
+ getTranslatedText("data_elements.name", dataElement.name, dataElement.uuid),
826
+ dataElement.required && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles2.requiredAsterisk, children: " *" })
827
+ ] }),
828
+ !isAlreadyConsented && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
829
+ Checkbox,
830
+ {
831
+ checked: selectedDataElements[`${purpose.uuid}-${dataElement.uuid}`] || false,
832
+ onChange: () => onDataElementToggle(dataElement.uuid, purpose.uuid),
833
+ size: "small",
834
+ accessibilityLabel: `Select ${getTranslatedText("data_elements.name", dataElement.name, dataElement.uuid)}${dataElement.required ? " (required)" : ""}`
835
+ }
836
+ ),
837
+ isAlreadyConsented && (() => {
838
+ const wasSelected = initialDataElementSelections[`${purpose.uuid}-${dataElement.uuid}`] || false;
839
+ return wasSelected ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.consentedCheckmarkSmall, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.default, { width: 10, height: 10, viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
840
+ import_react_native_svg2.Path,
841
+ {
842
+ d: "M3 5L4.5 6.5L7.5 3.5",
843
+ stroke: "white",
844
+ strokeWidth: 1.5,
845
+ strokeLinecap: "round",
846
+ strokeLinejoin: "round"
847
+ }
848
+ ) }) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.notConsentedCircle });
849
+ })()
850
+ ] }, dataElement.uuid)) })
851
+ ] });
852
+ };
853
+ var GuardianForm = ({ formData, errors, isSubmitting, onChange, onNext, onDecline, settings, logoUrl }) => {
854
+ var _a, _b, _c, _d;
855
+ const borderColor = (settings == null ? void 0 : settings.borderColor) || "#d0d5dd";
856
+ const textColor = (settings == null ? void 0 : settings.textColor) || "#344054";
857
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
858
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.topSection, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.topLeft, children: [
859
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Image, { style: styles2.logo, source: { uri: logoUrl } }) : null,
860
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.title, { color: (settings == null ? void 0 : settings.headingColor) || "#101828" }], children: "Guardian Information Required" })
861
+ ] }) }),
862
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.ScrollView, { style: styles2.middleSection, showsVerticalScrollIndicator: false, children: [
863
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.privacyText, { color: textColor, fontSize: 14, lineHeight: 20 }], children: "As you are under the age of consent, we need to collect information about your legal guardian to proceed." }),
864
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: { marginTop: 16, gap: 12 }, children: [
865
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.inputContainer, children: [
866
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.inputLabel, { color: textColor }], children: "Name of Guardian *" }),
867
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
868
+ import_react_native4.TextInput,
869
+ {
870
+ value: formData.guardianName,
871
+ onChangeText: (v) => onChange("guardianName", v),
872
+ style: [
873
+ styles2.textInput,
874
+ { borderColor: errors.guardianName ? "#DC2626" : borderColor, color: textColor }
875
+ ],
876
+ placeholder: "Enter guardian's full name",
877
+ placeholderTextColor: "#9CA3AF"
878
+ }
879
+ ),
880
+ errors.guardianName ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles2.inputError, children: errors.guardianName }) : null
881
+ ] }),
882
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.inputContainer, children: [
883
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.inputLabel, { color: textColor }], children: "Contact of Guardian *" }),
884
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
885
+ import_react_native4.TextInput,
886
+ {
887
+ value: formData.guardianContact,
888
+ onChangeText: (v) => onChange("guardianContact", v),
889
+ style: [
890
+ styles2.textInput,
891
+ { borderColor: errors.guardianContact ? "#DC2626" : borderColor, color: textColor }
892
+ ],
893
+ placeholder: "Enter guardian's email or phone number",
894
+ placeholderTextColor: "#9CA3AF",
895
+ keyboardType: "email-address",
896
+ autoCapitalize: "none"
897
+ }
898
+ ),
899
+ errors.guardianContact ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles2.inputError, children: errors.guardianContact }) : null
900
+ ] }),
901
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.inputContainer, children: [
902
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.inputLabel, { color: textColor }], children: "Relationship to Guardian *" }),
903
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
904
+ import_react_native4.TextInput,
905
+ {
906
+ value: formData.guardianRelationship,
907
+ onChangeText: (v) => onChange("guardianRelationship", v),
908
+ style: [
909
+ styles2.textInput,
910
+ { borderColor: errors.guardianRelationship ? "#DC2626" : borderColor, color: textColor }
911
+ ],
912
+ placeholder: "e.g., Parent, Legal Guardian, etc.",
913
+ placeholderTextColor: "#9CA3AF"
914
+ }
915
+ ),
916
+ errors.guardianRelationship ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles2.inputError, children: errors.guardianRelationship }) : null
917
+ ] }),
918
+ errors.general ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.errorContainer, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles2.errorText, children: errors.general }) }) : null
919
+ ] })
920
+ ] }),
921
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.bottomSection, children: [
922
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
923
+ import_react_native4.TouchableOpacity,
924
+ {
925
+ style: [
926
+ styles2.button,
927
+ styles2.acceptButton,
928
+ ((_a = settings == null ? void 0 : settings.button) == null ? void 0 : _a.accept) ? { backgroundColor: settings.button.accept.backgroundColor } : null
929
+ ],
930
+ onPress: onNext,
931
+ disabled: isSubmitting,
932
+ accessibilityLabel: "Submit guardian information and proceed",
933
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [
934
+ styles2.buttonText,
935
+ styles2.acceptButtonText,
936
+ ((_b = settings == null ? void 0 : settings.button) == null ? void 0 : _b.accept) ? { color: settings.button.accept.textColor } : null
937
+ ], children: isSubmitting ? "Submitting..." : "Next" })
938
+ }
939
+ ),
940
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
941
+ import_react_native4.TouchableOpacity,
942
+ {
943
+ style: [
944
+ styles2.button,
945
+ styles2.cancelButton,
946
+ ((_c = settings == null ? void 0 : settings.button) == null ? void 0 : _c.decline) ? { backgroundColor: settings.button.decline.backgroundColor, borderColor: settings.button.decline.backgroundColor } : null
947
+ ],
948
+ onPress: onDecline,
949
+ accessibilityLabel: "Cancel guardian information form",
950
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [
951
+ styles2.buttonText,
952
+ styles2.cancelButtonText,
953
+ ((_d = settings == null ? void 0 : settings.button) == null ? void 0 : _d.decline) ? { color: settings.button.decline.textColor } : null
954
+ ], children: "Cancel" })
955
+ }
956
+ )
957
+ ] })
958
+ ] });
959
+ };
960
+ var AgeVerification = ({ onYes, onNo, settings, logoUrl }) => {
961
+ var _a, _b, _c, _d;
962
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
963
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.topSection, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.topLeft, children: [
964
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Image, { style: styles2.logo, source: { uri: logoUrl } }) : null,
965
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.title, { color: (settings == null ? void 0 : settings.headingColor) || "#101828" }], children: "Age Verification" })
966
+ ] }) }),
967
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.ScrollView, { style: styles2.middleSection, showsVerticalScrollIndicator: false, children: [
968
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.privacyText, { color: (settings == null ? void 0 : settings.textColor) || "#344054" }], children: "To proceed, we need to verify your age." }),
969
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.privacyText, { color: (settings == null ? void 0 : settings.textColor) || "#344054", marginTop: 12, fontWeight: "600" }], children: "Are you 18 years of age or older?" })
970
+ ] }),
971
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.bottomSection, children: [
972
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
973
+ import_react_native4.TouchableOpacity,
974
+ {
975
+ style: [
976
+ styles2.button,
977
+ styles2.acceptButton,
978
+ ((_a = settings == null ? void 0 : settings.button) == null ? void 0 : _a.accept) ? { backgroundColor: settings.button.accept.backgroundColor } : null
979
+ ],
980
+ onPress: onYes,
981
+ accessibilityLabel: "Yes, I am 18 or older",
982
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [
983
+ styles2.buttonText,
984
+ styles2.acceptButtonText,
985
+ ((_b = settings == null ? void 0 : settings.button) == null ? void 0 : _b.accept) ? { color: settings.button.accept.textColor } : null
986
+ ], children: "Yes" })
987
+ }
988
+ ),
989
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
990
+ import_react_native4.TouchableOpacity,
991
+ {
992
+ style: [
993
+ styles2.button,
994
+ styles2.cancelButton,
995
+ ((_c = settings == null ? void 0 : settings.button) == null ? void 0 : _c.decline) ? { backgroundColor: settings.button.decline.backgroundColor, borderColor: settings.button.decline.backgroundColor } : null
996
+ ],
997
+ onPress: onNo,
998
+ accessibilityLabel: "No, I am under 18",
999
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [
1000
+ styles2.buttonText,
1001
+ styles2.cancelButtonText,
1002
+ ((_d = settings == null ? void 0 : settings.button) == null ? void 0 : _d.decline) ? { color: settings.button.decline.textColor } : null
1003
+ ], children: "No" })
1004
+ }
1005
+ )
1006
+ ] })
1007
+ ] });
1008
+ };
1009
+ var RedactoNoticeConsent = ({
1010
+ noticeId,
1011
+ accessToken,
1012
+ refreshToken: _refreshToken,
1013
+ baseUrl,
1014
+ settings,
1015
+ language = "en",
1016
+ blockUI = false,
1017
+ onAccept,
1018
+ onDecline,
1019
+ onError,
1020
+ applicationId,
1021
+ validateAgainst = "all",
1022
+ includeFullyConsentedData = false,
1023
+ reviewModeButtonText
1024
+ }) => {
1025
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
1026
+ const { isMobile } = useResponsive();
1027
+ const [content, setContent] = (0, import_react.useState)(null);
1028
+ const [isLoading, setIsLoading] = (0, import_react.useState)(true);
1029
+ const [isSubmitting, setIsSubmitting] = (0, import_react.useState)(false);
1030
+ const [selectedLanguage, setSelectedLanguage] = (0, import_react.useState)(language);
1031
+ const [collapsedPurposes, setCollapsedPurposes] = (0, import_react.useState)({});
1032
+ const [selectedPurposes, setSelectedPurposes] = (0, import_react.useState)({});
1033
+ const [selectedDataElements, setSelectedDataElements] = (0, import_react.useState)({});
1034
+ const [initialDataElementSelections, setInitialDataElementSelections] = (0, import_react.useState)({});
1035
+ const [errorMessage, setErrorMessage] = (0, import_react.useState)(null);
1036
+ const [isLanguageDropdownOpen, setIsLanguageDropdownOpen] = (0, import_react.useState)(false);
1037
+ const [isVisible, setIsVisible] = (0, import_react.useState)(false);
1038
+ const [isReconsentMode, setIsReconsentMode] = (0, import_react.useState)(false);
1039
+ const [isReviewMode, setIsReviewMode] = (0, import_react.useState)(false);
1040
+ const [showAgeVerification, setShowAgeVerification] = (0, import_react.useState)(false);
1041
+ const [showGuardianForm, setShowGuardianForm] = (0, import_react.useState)(false);
1042
+ const [isMinor, setIsMinor] = (0, import_react.useState)(false);
1043
+ const [guardianFormData, setGuardianFormData] = (0, import_react.useState)({ guardianName: "", guardianContact: "", guardianRelationship: "" });
1044
+ const [guardianFormErrors, setGuardianFormErrors] = (0, import_react.useState)({});
1045
+ const [isSubmittingGuardian, setIsSubmittingGuardian] = (0, import_react.useState)(false);
1046
+ const [isTTSAvailable, setIsTTSAvailable] = (0, import_react.useState)(false);
1047
+ const [ttsAudioUrls, setTtsAudioUrls] = (0, import_react.useState)({});
1048
+ const [isPlaying, setIsPlaying] = (0, import_react.useState)(false);
1049
+ const [isPaused, setIsPaused] = (0, import_react.useState)(false);
1050
+ const soundRef = (0, import_react.useRef)(null);
1051
+ const ttsQueueRef = (0, import_react.useRef)([]);
1052
+ const ttsIndexRef = (0, import_react.useRef)(0);
1053
+ const abortControllerRef = (0, import_react.useRef)(null);
1054
+ const hasBootstrappedLanguageRef = (0, import_react.useRef)(false);
1055
+ const fetchContent = (0, import_react.useCallback)(async () => {
1056
+ if (abortControllerRef.current) {
1057
+ abortControllerRef.current.abort();
1058
+ }
1059
+ abortControllerRef.current = new AbortController();
1060
+ setIsLoading(true);
1061
+ setErrorMessage(null);
1062
+ try {
1063
+ const data = await fetchConsentContent({
1064
+ noticeId,
1065
+ accessToken,
1066
+ baseUrl,
1067
+ language: selectedLanguage,
1068
+ validate_against: validateAgainst,
1069
+ include_fully_consented_data: includeFullyConsentedData,
1070
+ specific_uuid: applicationId,
1071
+ signal: abortControllerRef.current.signal
1072
+ });
1073
+ const activeConfig2 = data.detail.active_config;
1074
+ const purposeSelections = data.detail.purpose_selections;
1075
+ const reconsentRequired = data.detail.reconsent_required || false;
1076
+ const noticeIsMinor = data.detail.is_minor || false;
1077
+ setIsMinor(noticeIsMinor);
1078
+ const initialCollapsed = {};
1079
+ const initialPurposeState = {};
1080
+ const initialDataElementState = {};
1081
+ const initialDataElementSelectionsMap = {};
1082
+ activeConfig2.purposes.forEach((purpose) => {
1083
+ initialCollapsed[purpose.uuid] = true;
1084
+ const sel = purposeSelections == null ? void 0 : purposeSelections[purpose.uuid];
1085
+ const purposeSelected = sel ? sel.selected : false;
1086
+ initialPurposeState[purpose.uuid] = purposeSelected;
1087
+ purpose.data_elements.forEach((el) => {
1088
+ var _a2, _b2, _c2;
1089
+ const combinedId = `${purpose.uuid}-${el.uuid}`;
1090
+ const elementSel = (_c2 = (_b2 = (_a2 = sel == null ? void 0 : sel.data_elements) == null ? void 0 : _a2[el.uuid]) == null ? void 0 : _b2.selected) != null ? _c2 : false;
1091
+ initialDataElementState[combinedId] = elementSel;
1092
+ initialDataElementSelectionsMap[combinedId] = elementSel;
1093
+ });
1094
+ });
1095
+ setCollapsedPurposes(initialCollapsed);
1096
+ setSelectedPurposes(initialPurposeState);
1097
+ setSelectedDataElements(initialDataElementState);
1098
+ setInitialDataElementSelections(initialDataElementSelectionsMap);
1099
+ if (!hasBootstrappedLanguageRef.current) {
1100
+ hasBootstrappedLanguageRef.current = true;
1101
+ if (activeConfig2.default_language && activeConfig2.default_language !== selectedLanguage) {
1102
+ setSelectedLanguage(activeConfig2.default_language);
1103
+ }
1104
+ }
1105
+ setContent(data);
1106
+ setIsReconsentMode(reconsentRequired);
1107
+ if (noticeIsMinor) {
1108
+ setShowAgeVerification(true);
1109
+ }
1110
+ setIsVisible(true);
1111
+ } catch (err) {
1112
+ const error = err;
1113
+ if (error.name === "AbortError") return;
1114
+ if (error.status === 409) {
1115
+ onAccept();
1116
+ return;
1117
+ }
1118
+ if (error.status === 401) {
1119
+ setErrorMessage("Unauthorized: Invalid or expired token");
1120
+ } else {
1121
+ setErrorMessage(error.message || "Failed to load consent content");
1122
+ }
1123
+ onError == null ? void 0 : onError(error);
1124
+ } finally {
1125
+ setIsLoading(false);
1126
+ }
1127
+ }, [noticeId, accessToken, baseUrl, selectedLanguage, validateAgainst, includeFullyConsentedData, applicationId, onAccept, onError]);
1128
+ (0, import_react.useEffect)(() => {
1129
+ hasBootstrappedLanguageRef.current = false;
1130
+ }, [noticeId, accessToken]);
1131
+ (0, import_react.useEffect)(() => {
1132
+ fetchContent();
1133
+ return () => {
1134
+ var _a2;
1135
+ (_a2 = abortControllerRef.current) == null ? void 0 : _a2.abort();
1136
+ };
1137
+ }, [fetchContent]);
1138
+ const fetchTTS = (0, import_react.useCallback)(async () => {
1139
+ if (!expoAv || !content) return;
1140
+ try {
1141
+ const data = await fetchTTSAudioUrls({
1142
+ accessToken,
1143
+ baseUrl,
1144
+ noticeUuid: content.detail.active_config.notice_uuid,
1145
+ language: selectedLanguage
1146
+ });
1147
+ const urls = {
1148
+ notice_text: data.detail.notice_text_audio_url,
1149
+ additional_text: data.detail.additional_text_audio_url,
1150
+ notice_banner_heading: data.detail.notice_banner_heading_audio_url,
1151
+ purpose_section_heading: data.detail.purpose_section_heading_audio_url
1152
+ };
1153
+ content.detail.active_config.purposes.forEach((p) => {
1154
+ var _a2;
1155
+ const pa = (_a2 = data.detail.purposes_audio) == null ? void 0 : _a2[p.uuid];
1156
+ if (pa) {
1157
+ urls[`purpose_name_${p.uuid}`] = pa.name_audio_url;
1158
+ urls[`purpose_desc_${p.uuid}`] = pa.description_audio_url;
1159
+ }
1160
+ p.data_elements.forEach((el) => {
1161
+ var _a3;
1162
+ const ea = (_a3 = data.detail.data_elements_audio) == null ? void 0 : _a3[el.uuid];
1163
+ if (ea) urls[`element_${el.uuid}`] = ea.name_audio_url;
1164
+ });
1165
+ });
1166
+ setTtsAudioUrls(urls);
1167
+ setIsTTSAvailable(true);
1168
+ } catch {
1169
+ setIsTTSAvailable(false);
1170
+ }
1171
+ }, [content, accessToken, baseUrl, selectedLanguage]);
1172
+ (0, import_react.useEffect)(() => {
1173
+ if (content && expoAv) {
1174
+ fetchTTS();
1175
+ }
1176
+ }, [content, fetchTTS]);
1177
+ const stopAudio = (0, import_react.useCallback)(async () => {
1178
+ if (soundRef.current) {
1179
+ await soundRef.current.stopAsync();
1180
+ await soundRef.current.unloadAsync();
1181
+ soundRef.current = null;
1182
+ }
1183
+ setIsPlaying(false);
1184
+ setIsPaused(false);
1185
+ ttsIndexRef.current = 0;
1186
+ }, []);
1187
+ const playNextInQueue = (0, import_react.useCallback)(async () => {
1188
+ if (!expoAv) return;
1189
+ const queue = ttsQueueRef.current;
1190
+ if (ttsIndexRef.current >= queue.length) {
1191
+ await stopAudio();
1192
+ return;
1193
+ }
1194
+ const url = queue[ttsIndexRef.current];
1195
+ ttsIndexRef.current += 1;
1196
+ try {
1197
+ const { sound } = await expoAv.Audio.Sound.createAsync(
1198
+ { uri: url },
1199
+ { shouldPlay: true },
1200
+ (status) => {
1201
+ if (status.isLoaded && status.didJustFinish) {
1202
+ playNextInQueue();
1203
+ }
1204
+ }
1205
+ );
1206
+ soundRef.current = sound;
1207
+ } catch {
1208
+ playNextInQueue();
1209
+ }
1210
+ }, [stopAudio]);
1211
+ const startAudio = (0, import_react.useCallback)(async () => {
1212
+ if (!expoAv || !content) return;
1213
+ const ac = content.detail.active_config;
1214
+ const queue = [];
1215
+ if (ttsAudioUrls.notice_banner_heading) queue.push(ttsAudioUrls.notice_banner_heading);
1216
+ if (ttsAudioUrls.notice_text) queue.push(ttsAudioUrls.notice_text);
1217
+ if (ttsAudioUrls.additional_text) queue.push(ttsAudioUrls.additional_text);
1218
+ if (ttsAudioUrls.purpose_section_heading) queue.push(ttsAudioUrls.purpose_section_heading);
1219
+ ac.purposes.forEach((p) => {
1220
+ if (ttsAudioUrls[`purpose_name_${p.uuid}`]) queue.push(ttsAudioUrls[`purpose_name_${p.uuid}`]);
1221
+ if (ttsAudioUrls[`purpose_desc_${p.uuid}`]) queue.push(ttsAudioUrls[`purpose_desc_${p.uuid}`]);
1222
+ p.data_elements.forEach((el) => {
1223
+ if (ttsAudioUrls[`element_${el.uuid}`]) queue.push(ttsAudioUrls[`element_${el.uuid}`]);
1224
+ });
1225
+ });
1226
+ ttsQueueRef.current = queue;
1227
+ ttsIndexRef.current = 0;
1228
+ setIsPlaying(true);
1229
+ setIsPaused(false);
1230
+ await playNextInQueue();
1231
+ }, [content, ttsAudioUrls, playNextInQueue]);
1232
+ const toggleAudio = (0, import_react.useCallback)(async () => {
1233
+ var _a2, _b2;
1234
+ if (isPlaying && !isPaused) {
1235
+ await ((_a2 = soundRef.current) == null ? void 0 : _a2.pauseAsync());
1236
+ setIsPaused(true);
1237
+ } else if (isPaused) {
1238
+ await ((_b2 = soundRef.current) == null ? void 0 : _b2.playAsync());
1239
+ setIsPaused(false);
1240
+ } else {
1241
+ await startAudio();
1242
+ }
1243
+ }, [isPlaying, isPaused, startAudio]);
1244
+ (0, import_react.useEffect)(() => {
1245
+ return () => {
1246
+ stopAudio();
1247
+ };
1248
+ }, [stopAudio]);
1249
+ const getTranslatedText = (0, import_react.useCallback)(
1250
+ (key, defaultText, itemId) => {
1251
+ var _a2, _b2, _c2;
1252
+ if (!content) return defaultText;
1253
+ const activeConfig2 = content.detail.active_config;
1254
+ const translationMap = (_a2 = activeConfig2.supported_languages_and_translations) == null ? void 0 : _a2[selectedLanguage];
1255
+ if (!translationMap) return defaultText;
1256
+ if (itemId) {
1257
+ if (key === "purposes.name" || key === "purposes.description") {
1258
+ const purposeData = (_b2 = translationMap.purposes) == null ? void 0 : _b2[itemId];
1259
+ if (purposeData) {
1260
+ if (typeof purposeData === "string") {
1261
+ return key === "purposes.name" ? purposeData : defaultText;
1262
+ }
1263
+ return key === "purposes.name" ? purposeData.name || defaultText : purposeData.description || defaultText;
1264
+ }
1265
+ return defaultText;
1266
+ }
1267
+ if (key.startsWith("data_elements.")) {
1268
+ return ((_c2 = translationMap.data_elements) == null ? void 0 : _c2[itemId]) || defaultText;
1269
+ }
1270
+ }
1271
+ const value = translationMap[key];
1272
+ if (typeof value === "string" && value) return value;
1273
+ return defaultText;
1274
+ },
1275
+ [content, selectedLanguage]
1276
+ );
1277
+ const handlePurposeToggle = (0, import_react.useCallback)((purposeUuid) => {
1278
+ setSelectedPurposes((prev) => {
1279
+ const newState = !prev[purposeUuid];
1280
+ setSelectedDataElements((prevEl) => {
1281
+ var _a2;
1282
+ const updated = { ...prevEl };
1283
+ (_a2 = content == null ? void 0 : content.detail.active_config.purposes.find((p) => p.uuid === purposeUuid)) == null ? void 0 : _a2.data_elements.forEach((el) => {
1284
+ updated[`${purposeUuid}-${el.uuid}`] = newState;
1285
+ });
1286
+ return updated;
1287
+ });
1288
+ return { ...prev, [purposeUuid]: newState };
1289
+ });
1290
+ }, [content]);
1291
+ const handlePurposeCollapse = (0, import_react.useCallback)((purposeUuid) => {
1292
+ setCollapsedPurposes((prev) => ({ ...prev, [purposeUuid]: !prev[purposeUuid] }));
1293
+ }, []);
1294
+ const handleDataElementToggle = (0, import_react.useCallback)((elementUuid, purposeUuid) => {
1295
+ if (!content) return;
1296
+ const purpose = content.detail.active_config.purposes.find((p) => p.uuid === purposeUuid);
1297
+ if (!purpose) return;
1298
+ const combinedId = `${purposeUuid}-${elementUuid}`;
1299
+ setSelectedDataElements((prev) => {
1300
+ const newState = { ...prev, [combinedId]: !prev[combinedId] };
1301
+ const requiredElements = purpose.data_elements.filter((el) => el.required);
1302
+ const shouldCheckPurpose = requiredElements.length > 0 ? requiredElements.every((el) => newState[`${purposeUuid}-${el.uuid}`]) : purpose.data_elements.some((el) => newState[`${purposeUuid}-${el.uuid}`]);
1303
+ setSelectedPurposes((prev2) => ({ ...prev2, [purposeUuid]: shouldCheckPurpose }));
1304
+ return newState;
1305
+ });
1306
+ }, [content]);
1307
+ const handleAccept = (0, import_react.useCallback)(async () => {
1308
+ if (!content) return;
1309
+ try {
1310
+ setIsSubmitting(true);
1311
+ setErrorMessage(null);
1312
+ const activeConfig2 = content.detail.active_config;
1313
+ await submitConsentEvent({
1314
+ accessToken,
1315
+ baseUrl,
1316
+ noticeUuid: activeConfig2.notice_uuid,
1317
+ purposes: activeConfig2.purposes.map((purpose) => ({
1318
+ ...purpose,
1319
+ selected: selectedPurposes[purpose.uuid] || false,
1320
+ data_elements: purpose.data_elements.map((el) => ({
1321
+ ...el,
1322
+ selected: selectedDataElements[`${purpose.uuid}-${el.uuid}`] || false
1323
+ }))
1324
+ })),
1325
+ declined: false,
1326
+ meta_data: applicationId ? { specific_uuid: applicationId } : void 0
1327
+ });
1328
+ await stopAudio();
1329
+ clearApiCache();
1330
+ setIsVisible(false);
1331
+ onAccept();
1332
+ } catch (err) {
1333
+ const error = err;
1334
+ setErrorMessage(
1335
+ error.status === 500 ? "An error occurred. Please try again later." : error.message || "Failed to submit consent."
1336
+ );
1337
+ onError == null ? void 0 : onError(error);
1338
+ } finally {
1339
+ setIsSubmitting(false);
1340
+ }
1341
+ }, [content, accessToken, baseUrl, applicationId, selectedPurposes, selectedDataElements, stopAudio, onAccept, onError]);
1342
+ const handleDecline = (0, import_react.useCallback)(async () => {
1343
+ if (!content) return;
1344
+ if (blockUI) return;
1345
+ try {
1346
+ setIsSubmitting(true);
1347
+ const activeConfig2 = content.detail.active_config;
1348
+ await submitConsentEvent({
1349
+ accessToken,
1350
+ baseUrl,
1351
+ noticeUuid: activeConfig2.notice_uuid,
1352
+ purposes: activeConfig2.purposes.map((purpose) => ({
1353
+ ...purpose,
1354
+ selected: false,
1355
+ data_elements: purpose.data_elements.map((el) => ({ ...el, selected: false }))
1356
+ })),
1357
+ declined: true
1358
+ });
1359
+ await stopAudio();
1360
+ clearApiCache();
1361
+ setIsVisible(false);
1362
+ onDecline();
1363
+ } catch (err) {
1364
+ const error = err;
1365
+ setErrorMessage(error.message || "Failed to decline consent.");
1366
+ onError == null ? void 0 : onError(error);
1367
+ } finally {
1368
+ setIsSubmitting(false);
1369
+ }
1370
+ }, [content, accessToken, baseUrl, blockUI, stopAudio, onDecline, onError]);
1371
+ const handleGuardianFormChange = (0, import_react.useCallback)((field, value) => {
1372
+ setGuardianFormData((prev) => ({ ...prev, [field]: value }));
1373
+ setGuardianFormErrors((prev) => ({ ...prev, [field]: "" }));
1374
+ }, []);
1375
+ const handleGuardianFormNext = (0, import_react.useCallback)(async () => {
1376
+ const errors = {};
1377
+ if (!guardianFormData.guardianName.trim()) errors.guardianName = "Guardian name is required";
1378
+ if (!guardianFormData.guardianContact.trim()) errors.guardianContact = "Guardian contact is required";
1379
+ if (!guardianFormData.guardianRelationship.trim()) errors.guardianRelationship = "Relationship is required";
1380
+ if (Object.keys(errors).length > 0) {
1381
+ setGuardianFormErrors(errors);
1382
+ return;
1383
+ }
1384
+ try {
1385
+ setIsSubmittingGuardian(true);
1386
+ await submitGuardianInfo({
1387
+ accessToken,
1388
+ baseUrl,
1389
+ guardianName: guardianFormData.guardianName,
1390
+ guardianContact: guardianFormData.guardianContact,
1391
+ guardianRelationship: guardianFormData.guardianRelationship
1392
+ });
1393
+ setShowGuardianForm(false);
1394
+ } catch (err) {
1395
+ const error = err;
1396
+ setGuardianFormErrors({ general: error.message || "Failed to submit guardian info." });
1397
+ } finally {
1398
+ setIsSubmittingGuardian(false);
1399
+ }
1400
+ }, [guardianFormData, accessToken, baseUrl]);
1401
+ const activeConfig = content == null ? void 0 : content.detail.active_config;
1402
+ const logoUrl = activeConfig == null ? void 0 : activeConfig.logo_url;
1403
+ const supportedLanguages = (0, import_react.useMemo)(
1404
+ () => Object.keys((activeConfig == null ? void 0 : activeConfig.supported_languages_and_translations) || {}),
1405
+ [activeConfig]
1406
+ );
1407
+ const acceptButtonStyle = ((_a = settings == null ? void 0 : settings.button) == null ? void 0 : _a.accept) ? { backgroundColor: settings.button.accept.backgroundColor } : {};
1408
+ const acceptButtonTextStyle = ((_b = settings == null ? void 0 : settings.button) == null ? void 0 : _b.accept) ? { color: settings.button.accept.textColor } : {};
1409
+ const declineButtonStyle = ((_c = settings == null ? void 0 : settings.button) == null ? void 0 : _c.decline) ? { backgroundColor: settings.button.decline.backgroundColor, borderColor: settings.button.decline.backgroundColor } : {};
1410
+ const declineButtonTextStyle = ((_d = settings == null ? void 0 : settings.button) == null ? void 0 : _d.decline) ? { color: settings.button.decline.textColor } : {};
1411
+ const modalBg = (settings == null ? void 0 : settings.backgroundColor) ? { backgroundColor: settings.backgroundColor } : {};
1412
+ const translatedNoticeText = activeConfig ? stripHtml(getTranslatedText("notice_text", activeConfig.notice_text || "")) : "";
1413
+ const translatedAdditionalText = activeConfig ? stripHtml(getTranslatedText("additional_text", activeConfig.additional_text || "")) : "";
1414
+ if (!isVisible && !isLoading) return null;
1415
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1416
+ import_react_native4.Modal,
1417
+ {
1418
+ visible: isVisible || isLoading,
1419
+ transparent: true,
1420
+ animationType: "fade",
1421
+ onRequestClose: blockUI ? void 0 : handleDecline,
1422
+ accessibilityViewIsModal: true,
1423
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.overlay, children: [
1424
+ isLanguageDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1425
+ import_react_native4.Pressable,
1426
+ {
1427
+ style: [import_react_native4.StyleSheet.absoluteFillObject, { zIndex: 1 }],
1428
+ onPress: () => setIsLanguageDropdownOpen(false)
1429
+ }
1430
+ ),
1431
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1432
+ import_react_native4.View,
1433
+ {
1434
+ style: [
1435
+ styles2.modal,
1436
+ modalBg,
1437
+ { zIndex: 2 },
1438
+ (settings == null ? void 0 : settings.borderRadius) ? { borderRadius: parseInt(settings.borderRadius, 10) } : null
1439
+ ],
1440
+ children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.loadingContainer, children: [
1441
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.ActivityIndicator, { size: "large", color: "#4f87ff" }),
1442
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles2.loadingText, children: "Loading..." })
1443
+ ] }) : showGuardianForm ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.content, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1444
+ GuardianForm,
1445
+ {
1446
+ formData: guardianFormData,
1447
+ errors: guardianFormErrors,
1448
+ isSubmitting: isSubmittingGuardian,
1449
+ onChange: handleGuardianFormChange,
1450
+ onNext: handleGuardianFormNext,
1451
+ onDecline: handleDecline,
1452
+ settings,
1453
+ logoUrl
1454
+ }
1455
+ ) }) : showAgeVerification ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.content, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1456
+ AgeVerification,
1457
+ {
1458
+ onYes: () => {
1459
+ setShowAgeVerification(false);
1460
+ },
1461
+ onNo: () => {
1462
+ setShowAgeVerification(false);
1463
+ if (isMinor) setShowGuardianForm(true);
1464
+ },
1465
+ settings,
1466
+ logoUrl
1467
+ }
1468
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.content, children: [
1469
+ errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.errorContainer, children: [
1470
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles2.errorText, children: errorMessage }),
1471
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.TouchableOpacity, { onPress: () => setErrorMessage(null), hitSlop: { top: 8, bottom: 8, left: 8, right: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.default, { width: 16, height: 16, viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Path, { d: "M12 4L4 12M4 4L12 12", stroke: "#DC2626", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }) }) })
1472
+ ] }) : null,
1473
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.topSection, children: [
1474
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.topLeft, children: [
1475
+ logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Image, { style: styles2.logo, source: { uri: logoUrl } }) : null,
1476
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1477
+ import_react_native4.Text,
1478
+ {
1479
+ style: [
1480
+ styles2.title,
1481
+ { color: (settings == null ? void 0 : settings.headingColor) || "#101828" },
1482
+ isMobile ? { fontSize: 16 } : null
1483
+ ],
1484
+ numberOfLines: 2,
1485
+ children: getTranslatedText(
1486
+ "notice_banner_heading",
1487
+ (activeConfig == null ? void 0 : activeConfig.notice_banner_heading) || "Privacy Notice"
1488
+ )
1489
+ }
1490
+ )
1491
+ ] }),
1492
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: { flexDirection: "row", gap: 8, alignItems: "center" }, children: [
1493
+ isTTSAvailable && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1494
+ import_react_native4.TouchableOpacity,
1495
+ {
1496
+ style: [styles2.topRight, ((_e = settings == null ? void 0 : settings.button) == null ? void 0 : _e.language) ? { backgroundColor: settings.button.language.backgroundColor, borderColor: settings.button.language.backgroundColor } : null],
1497
+ onPress: toggleAudio,
1498
+ accessibilityLabel: isPlaying && !isPaused ? "Pause audio" : isPaused ? "Resume audio" : "Start audio",
1499
+ children: isPlaying && !isPaused ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native_svg2.default, { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", children: [
1500
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Rect, { x: "6", y: "4", width: "4", height: "16", fill: ((_g = (_f = settings == null ? void 0 : settings.button) == null ? void 0 : _f.language) == null ? void 0 : _g.textColor) || "#344054" }),
1501
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.Rect, { x: "14", y: "4", width: "4", height: "16", fill: ((_i = (_h = settings == null ? void 0 : settings.button) == null ? void 0 : _h.language) == null ? void 0 : _i.textColor) || "#344054" })
1502
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native_svg2.default, { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", children: [
1503
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1504
+ import_react_native_svg2.Path,
1505
+ {
1506
+ d: "M11 5L6 9H2V15H6L11 19V5Z",
1507
+ stroke: ((_k = (_j = settings == null ? void 0 : settings.button) == null ? void 0 : _j.language) == null ? void 0 : _k.textColor) || "#344054",
1508
+ strokeWidth: 2,
1509
+ strokeLinecap: "round",
1510
+ strokeLinejoin: "round"
1511
+ }
1512
+ ),
1513
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1514
+ import_react_native_svg2.Path,
1515
+ {
1516
+ d: "M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07",
1517
+ stroke: ((_m = (_l = settings == null ? void 0 : settings.button) == null ? void 0 : _l.language) == null ? void 0 : _m.textColor) || "#344054",
1518
+ strokeWidth: 2,
1519
+ strokeLinecap: "round",
1520
+ strokeLinejoin: "round"
1521
+ }
1522
+ )
1523
+ ] })
1524
+ }
1525
+ ),
1526
+ supportedLanguages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.View, { style: styles2.languageSelectorContainer, children: [
1527
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1528
+ import_react_native4.TouchableOpacity,
1529
+ {
1530
+ style: [
1531
+ styles2.topRight,
1532
+ ((_n = settings == null ? void 0 : settings.button) == null ? void 0 : _n.language) ? { backgroundColor: settings.button.language.backgroundColor, borderColor: settings.button.language.backgroundColor } : null
1533
+ ],
1534
+ onPress: () => setIsLanguageDropdownOpen((v) => !v),
1535
+ accessibilityLabel: `Select language. Current: ${selectedLanguage}`,
1536
+ children: [
1537
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.topRightText, ((_o = settings == null ? void 0 : settings.button) == null ? void 0 : _o.language) ? { color: settings.button.language.textColor } : null], children: selectedLanguage }),
1538
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg2.default, { width: 12, height: 12, viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1539
+ import_react_native_svg2.Path,
1540
+ {
1541
+ d: "M4 6L8 10L12 6",
1542
+ stroke: ((_q = (_p = settings == null ? void 0 : settings.button) == null ? void 0 : _p.language) == null ? void 0 : _q.textColor) || "#344054",
1543
+ strokeWidth: 2,
1544
+ strokeLinecap: "round",
1545
+ strokeLinejoin: "round"
1546
+ }
1547
+ ) })
1548
+ ]
1549
+ }
1550
+ ),
1551
+ isLanguageDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.languageDropdown, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.ScrollView, { children: supportedLanguages.map((lang) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1552
+ import_react_native4.TouchableOpacity,
1553
+ {
1554
+ style: [
1555
+ styles2.languageItem,
1556
+ lang === selectedLanguage ? styles2.selectedLanguageItem : null
1557
+ ],
1558
+ onPress: () => {
1559
+ setSelectedLanguage(lang);
1560
+ setIsLanguageDropdownOpen(false);
1561
+ },
1562
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1563
+ import_react_native4.Text,
1564
+ {
1565
+ style: [
1566
+ styles2.languageItemText,
1567
+ lang === selectedLanguage ? styles2.selectedLanguageItemText : null
1568
+ ],
1569
+ children: lang
1570
+ }
1571
+ )
1572
+ },
1573
+ lang
1574
+ )) }) })
1575
+ ] })
1576
+ ] })
1577
+ ] }),
1578
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.ScrollView, { style: styles2.middleSection, showsVerticalScrollIndicator: false, children: [
1579
+ translatedNoticeText ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.privacyText, (settings == null ? void 0 : settings.textColor) ? { color: settings.textColor } : null], children: translatedNoticeText }) : null,
1580
+ translatedAdditionalText ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.privacyText, { marginTop: 8 }, (settings == null ? void 0 : settings.textColor) ? { color: settings.textColor } : null], children: translatedAdditionalText }) : null,
1581
+ (activeConfig == null ? void 0 : activeConfig.privacy_policy_url) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1582
+ import_react_native4.TouchableOpacity,
1583
+ {
1584
+ onPress: () => import_react_native4.Linking.openURL(activeConfig.privacy_policy_url),
1585
+ style: { marginTop: 8 },
1586
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.Text, { style: styles2.link, children: [
1587
+ getTranslatedText("privacy_policy_prefix_text", activeConfig.privacy_policy_prefix_text || ""),
1588
+ " ",
1589
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: styles2.link, children: getTranslatedText("privacy_policy_anchor_text", activeConfig.privacy_policy_anchor_text || "Privacy Policy") })
1590
+ ] })
1591
+ }
1592
+ ) : null,
1593
+ (activeConfig == null ? void 0 : activeConfig.purposes) && activeConfig.purposes.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.subTitle, { marginTop: 16, marginBottom: 8 }, (settings == null ? void 0 : settings.headingColor) ? { color: settings.headingColor } : null], children: getTranslatedText("purpose_section_heading", activeConfig.purpose_section_heading || "Data Purposes") }) : null,
1594
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.optionsContainer, children: activeConfig == null ? void 0 : activeConfig.purposes.map((purpose) => {
1595
+ var _a2;
1596
+ const purposeSelection = (_a2 = content == null ? void 0 : content.detail.purpose_selections) == null ? void 0 : _a2[purpose.uuid];
1597
+ const isAlreadyConsented = !isReconsentMode && ((purposeSelection == null ? void 0 : purposeSelection.selected) || false) && !(purposeSelection == null ? void 0 : purposeSelection.needs_reconsent);
1598
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1599
+ PurposeItem,
1600
+ {
1601
+ purpose,
1602
+ selectedPurposes,
1603
+ collapsedPurposes,
1604
+ selectedDataElements,
1605
+ settings: { headingColor: settings == null ? void 0 : settings.headingColor, textColor: settings == null ? void 0 : settings.textColor, font: settings == null ? void 0 : settings.font },
1606
+ onPurposeToggle: handlePurposeToggle,
1607
+ onPurposeCollapse: handlePurposeCollapse,
1608
+ onDataElementToggle: handleDataElementToggle,
1609
+ getTranslatedText,
1610
+ isAlreadyConsented,
1611
+ initialDataElementSelections,
1612
+ selectedLanguage
1613
+ },
1614
+ purpose.uuid
1615
+ );
1616
+ }) }),
1617
+ (activeConfig == null ? void 0 : activeConfig.dpo_info) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: { marginTop: 16, gap: 4 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native4.Text, { style: [styles2.privacyText, { fontSize: 13 }, (settings == null ? void 0 : settings.textColor) ? { color: settings.textColor } : null], children: [
1618
+ activeConfig.dpo_info.grievance_text,
1619
+ " ",
1620
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1621
+ import_react_native4.Text,
1622
+ {
1623
+ style: styles2.link,
1624
+ onPress: () => import_react_native4.Linking.openURL(activeConfig.dpo_info.grievance_url),
1625
+ children: activeConfig.dpo_info.grievance_anchor_text
1626
+ }
1627
+ )
1628
+ ] }) }) : null
1629
+ ] }),
1630
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.View, { style: styles2.bottomSection, children: isReviewMode ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1631
+ import_react_native4.TouchableOpacity,
1632
+ {
1633
+ style: [styles2.button, styles2.acceptButton, acceptButtonStyle],
1634
+ onPress: () => setIsReviewMode(false),
1635
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.buttonText, styles2.acceptButtonText, acceptButtonTextStyle], children: reviewModeButtonText || "Update Consent" })
1636
+ }
1637
+ ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1638
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1639
+ import_react_native4.TouchableOpacity,
1640
+ {
1641
+ style: [
1642
+ styles2.button,
1643
+ styles2.acceptButton,
1644
+ acceptButtonStyle,
1645
+ isSubmitting ? { opacity: 0.6 } : null
1646
+ ],
1647
+ onPress: handleAccept,
1648
+ disabled: isSubmitting,
1649
+ accessibilityLabel: isSubmitting ? "Submitting consent" : getTranslatedText("confirm_button_text", (activeConfig == null ? void 0 : activeConfig.confirm_button_text) || "Accept"),
1650
+ children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.ActivityIndicator, { size: "small", color: ((_s = (_r = settings == null ? void 0 : settings.button) == null ? void 0 : _r.accept) == null ? void 0 : _s.textColor) || "#ffffff" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.buttonText, styles2.acceptButtonText, acceptButtonTextStyle], children: getTranslatedText("confirm_button_text", (activeConfig == null ? void 0 : activeConfig.confirm_button_text) || "Accept") })
1651
+ }
1652
+ ),
1653
+ !blockUI && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1654
+ import_react_native4.TouchableOpacity,
1655
+ {
1656
+ style: [styles2.button, styles2.cancelButton, declineButtonStyle],
1657
+ onPress: handleDecline,
1658
+ disabled: isSubmitting,
1659
+ accessibilityLabel: getTranslatedText("decline_button_text", (activeConfig == null ? void 0 : activeConfig.decline_button_text) || "Decline"),
1660
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native4.Text, { style: [styles2.buttonText, styles2.cancelButtonText, declineButtonTextStyle], children: getTranslatedText("decline_button_text", (activeConfig == null ? void 0 : activeConfig.decline_button_text) || "Decline") })
1661
+ }
1662
+ )
1663
+ ] }) })
1664
+ ] })
1665
+ }
1666
+ )
1667
+ ] })
1668
+ }
1669
+ );
1670
+ };
1671
+
1672
+ // src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx
1673
+ var import_react2 = require("react");
1674
+ var import_react_native6 = require("react-native");
1675
+ var import_react_native_svg3 = __toESM(require("react-native-svg"));
1676
+
1677
+ // src/RedactoNoticeConsentInline/api/index.ts
1678
+ var fetchConsentContent2 = async ({
1679
+ org_uuid,
1680
+ workspace_uuid,
1681
+ notice_uuid,
1682
+ baseUrl,
1683
+ language = "en",
1684
+ specific_uuid,
1685
+ signal
1686
+ }) => {
1687
+ const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
1688
+ const url = new URL(
1689
+ `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/notices/get-notice/${notice_uuid}`
1690
+ );
1691
+ if (specific_uuid) {
1692
+ url.searchParams.append("specific_uuid", specific_uuid);
1693
+ }
1694
+ const response = await fetch(url.toString(), {
1695
+ method: "GET",
1696
+ headers: {
1697
+ "Content-Type": "application/json",
1698
+ "Accept-Language": language
1699
+ },
1700
+ signal
1701
+ });
1702
+ if (!response.ok) {
1703
+ let errorMessage = `Failed to fetch consent content: ${response.status} ${response.statusText}`;
1704
+ if (response.status === 400) {
1705
+ errorMessage = "Invalid request data";
1706
+ } else if (response.status === 401) {
1707
+ errorMessage = "Unauthorized: Invalid or expired token";
1708
+ } else if (response.status === 403) {
1709
+ errorMessage = "Forbidden: Access denied";
1710
+ } else if (response.status === 404) {
1711
+ errorMessage = "Notice not found";
1712
+ } else if (response.status === 409) {
1713
+ errorMessage = "User has already provided consent";
1714
+ } else if (response.status >= 500) {
1715
+ errorMessage = "Server error: Please try again later";
1716
+ }
1717
+ const error = new Error(errorMessage);
1718
+ error.status = response.status;
1719
+ throw error;
1720
+ }
1721
+ return response.json();
1722
+ };
1723
+ var submitConsentEvent2 = async ({
1724
+ org_uuid,
1725
+ workspace_uuid,
1726
+ accessToken,
1727
+ baseUrl,
1728
+ noticeUuid,
1729
+ purposes,
1730
+ declined,
1731
+ meta_data
1732
+ }) => {
1733
+ var _a, _b;
1734
+ const apiBaseUrl = baseUrl || DEFAULT_CONSENT_API_BASE_URL;
1735
+ const payload = {
1736
+ notice_uuid: noticeUuid,
1737
+ purposes: purposes.map((purpose) => {
1738
+ if (!purpose.uuid) {
1739
+ throw new Error("Invalid purpose data: missing uuid");
1740
+ }
1741
+ const dataElements = purpose.data_elements.filter((element) => element.enabled).map((element) => ({
1742
+ uuid: element.uuid,
1743
+ selected: element.required ? true : Boolean(element.selected)
1744
+ }));
1745
+ return {
1746
+ purpose_uuid: purpose.uuid,
1747
+ selected: Boolean(purpose.selected),
1748
+ data_elements: dataElements.length > 0 ? dataElements : void 0
1749
+ };
1750
+ }),
1751
+ select_all_mandatory: false,
1752
+ source: "MOBILE",
1753
+ declined,
1754
+ meta_data
1755
+ };
1756
+ const response = await fetch(
1757
+ `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/submit-consent`,
1758
+ {
1759
+ method: "POST",
1760
+ headers: {
1761
+ Authorization: `Bearer ${accessToken}`,
1762
+ "Content-Type": "application/json"
1763
+ },
1764
+ body: JSON.stringify(payload)
1765
+ }
1766
+ );
1767
+ if (!response.ok) {
1768
+ let errorData;
1769
+ try {
1770
+ errorData = await response.json();
1771
+ } catch {
1772
+ errorData = { message: response.statusText };
1773
+ }
1774
+ if (response.status === 409) {
1775
+ const error2 = new Error(
1776
+ ((_a = errorData.detail) == null ? void 0 : _a.message) || errorData.message || "User has already provided consent"
1777
+ );
1778
+ error2.status = 409;
1779
+ error2.code = errorData.code || 409;
1780
+ error2.detail = errorData.detail;
1781
+ throw error2;
1782
+ }
1783
+ const error = new Error(
1784
+ ((_b = errorData.detail) == null ? void 0 : _b.message) || errorData.message || `Failed to submit consent event: ${response.statusText}`
1785
+ );
1786
+ error.status = response.status;
1787
+ error.code = errorData.code;
1788
+ error.detail = errorData.detail;
1789
+ throw error;
1790
+ }
1791
+ };
1792
+
1793
+ // src/RedactoNoticeConsentInline/styles.ts
1794
+ var import_react_native5 = require("react-native");
1795
+ var styles3 = import_react_native5.StyleSheet.create({
1796
+ container: {
1797
+ width: "100%",
1798
+ borderRadius: 8,
1799
+ backgroundColor: "#ffffff",
1800
+ borderWidth: 1,
1801
+ borderColor: "#e5e7eb",
1802
+ ...import_react_native5.Platform.select({
1803
+ ios: {
1804
+ shadowColor: "#000",
1805
+ shadowOffset: { width: 0, height: 1 },
1806
+ shadowOpacity: 0.1,
1807
+ shadowRadius: 3
1808
+ },
1809
+ android: {
1810
+ elevation: 2
1811
+ }
1812
+ })
1813
+ },
1814
+ content: {
1815
+ padding: 22
1816
+ },
1817
+ topSection: {
1818
+ flexDirection: "row",
1819
+ justifyContent: "space-between",
1820
+ alignItems: "center",
1821
+ paddingBottom: 15,
1822
+ borderBottomWidth: 1,
1823
+ borderBottomColor: "#e5e7eb",
1824
+ backgroundColor: "#ffffff"
1825
+ },
1826
+ topLeft: {
1827
+ flexDirection: "row",
1828
+ alignItems: "center",
1829
+ gap: 10,
1830
+ flex: 1
1831
+ },
1832
+ logo: {
1833
+ height: 32,
1834
+ width: 80,
1835
+ resizeMode: "contain"
1836
+ },
1837
+ title: {
1838
+ fontSize: 18,
1839
+ fontWeight: "700",
1840
+ lineHeight: 27,
1841
+ letterSpacing: 0.2,
1842
+ color: "#101828",
1843
+ flexShrink: 1
1844
+ },
1845
+ topRight: {
1846
+ borderRadius: 8,
1847
+ paddingVertical: 3,
1848
+ paddingHorizontal: 9,
1849
+ borderWidth: 1,
1850
+ borderColor: "#d0d5dd",
1851
+ flexDirection: "row",
1852
+ alignItems: "center",
1853
+ justifyContent: "center",
1854
+ backgroundColor: "#ffffff"
1855
+ },
1856
+ topRightText: {
1857
+ fontWeight: "400",
1858
+ fontSize: 12,
1859
+ color: "#344054"
1860
+ },
1861
+ middleSection: {
1862
+ marginTop: 20,
1863
+ gap: 12
1864
+ },
1865
+ privacyText: {
1866
+ fontSize: 16,
1867
+ fontWeight: "400",
1868
+ lineHeight: 24,
1869
+ letterSpacing: 0.2,
1870
+ color: "#344054"
1871
+ },
1872
+ link: {
1873
+ color: "#4f87ff",
1874
+ textDecorationLine: "underline"
1875
+ },
1876
+ subTitle: {
1877
+ fontWeight: "600",
1878
+ fontSize: 16,
1879
+ lineHeight: 24,
1880
+ letterSpacing: 0.2,
1881
+ color: "#101828"
1882
+ },
1883
+ optionsContainer: {
1884
+ gap: 14
1885
+ },
1886
+ optionItem: {
1887
+ flexDirection: "row",
1888
+ justifyContent: "space-between",
1889
+ alignItems: "center"
1890
+ },
1891
+ optionLeft: {
1892
+ flexDirection: "row",
1893
+ gap: 12,
1894
+ alignItems: "center",
1895
+ flex: 1
1896
+ },
1897
+ optionTextContainer: {
1898
+ flex: 1
1899
+ },
1900
+ optionTitle: {
1901
+ fontWeight: "500",
1902
+ fontSize: 16,
1903
+ lineHeight: 24,
1904
+ letterSpacing: 0.2,
1905
+ color: "#101828"
1906
+ },
1907
+ optionDescription: {
1908
+ fontWeight: "400",
1909
+ fontSize: 12,
1910
+ lineHeight: 18,
1911
+ letterSpacing: 0.2,
1912
+ color: "#475467"
1913
+ },
1914
+ dataElementsContainer: {
1915
+ paddingLeft: 22,
1916
+ marginTop: 4
1917
+ },
1918
+ dataElementItem: {
1919
+ flexDirection: "row",
1920
+ alignItems: "center",
1921
+ gap: 10,
1922
+ justifyContent: "space-between",
1923
+ minHeight: 24,
1924
+ paddingVertical: 2
1925
+ },
1926
+ dataElementText: {
1927
+ fontWeight: "400",
1928
+ fontSize: 14,
1929
+ lineHeight: 21,
1930
+ letterSpacing: 0.2,
1931
+ color: "#344054",
1932
+ flex: 1
1933
+ },
1934
+ bottomSection: {
1935
+ flexDirection: "row",
1936
+ justifyContent: "space-between",
1937
+ gap: 12,
1938
+ paddingTop: 15,
1939
+ marginTop: 16,
1940
+ borderTopWidth: 1,
1941
+ borderTopColor: "#e5e7eb",
1942
+ backgroundColor: "#ffffff"
1943
+ },
1944
+ button: {
1945
+ flex: 1,
1946
+ borderRadius: 8,
1947
+ paddingVertical: 12,
1948
+ paddingHorizontal: 20,
1949
+ alignItems: "center",
1950
+ justifyContent: "center"
1951
+ },
1952
+ buttonText: {
1953
+ fontWeight: "400",
1954
+ fontSize: 16,
1955
+ lineHeight: 24,
1956
+ textAlign: "center"
1957
+ },
1958
+ acceptButton: {
1959
+ backgroundColor: "#4f87ff"
1960
+ },
1961
+ acceptButtonText: {
1962
+ color: "#ffffff"
1963
+ },
1964
+ cancelButton: {
1965
+ borderWidth: 1,
1966
+ borderColor: "#d0d5dd",
1967
+ backgroundColor: "#ffffff"
1968
+ },
1969
+ cancelButtonText: {
1970
+ color: "#000000"
1971
+ },
1972
+ loadingContainer: {
1973
+ alignItems: "center",
1974
+ justifyContent: "center",
1975
+ padding: 32,
1976
+ minHeight: 200
1977
+ },
1978
+ loadingText: {
1979
+ marginTop: 16,
1980
+ fontSize: 16,
1981
+ color: "#344054"
1982
+ },
1983
+ errorContainer: {
1984
+ backgroundColor: "#FEE2E2",
1985
+ borderRadius: 6,
1986
+ padding: 12,
1987
+ marginBottom: 12,
1988
+ borderWidth: 1,
1989
+ borderColor: "#FCA5A5"
1990
+ },
1991
+ errorText: {
1992
+ color: "#DC2626",
1993
+ fontSize: 14
1994
+ },
1995
+ requiredAsterisk: {
1996
+ color: "red"
1997
+ },
1998
+ purposeChevron: {
1999
+ marginLeft: 5,
2000
+ alignItems: "center",
2001
+ justifyContent: "center"
2002
+ },
2003
+ languageSelectorContainer: {
2004
+ position: "relative"
2005
+ },
2006
+ languageDropdown: {
2007
+ position: "absolute",
2008
+ top: "100%",
2009
+ right: 0,
2010
+ backgroundColor: "#ffffff",
2011
+ borderWidth: 1,
2012
+ borderColor: "#d0d5dd",
2013
+ borderRadius: 4,
2014
+ zIndex: 10,
2015
+ minWidth: 120,
2016
+ maxHeight: 200,
2017
+ marginTop: 4,
2018
+ ...import_react_native5.Platform.select({
2019
+ ios: {
2020
+ shadowColor: "#000",
2021
+ shadowOffset: { width: 0, height: 2 },
2022
+ shadowOpacity: 0.1,
2023
+ shadowRadius: 4
2024
+ },
2025
+ android: {
2026
+ elevation: 4
2027
+ }
2028
+ })
2029
+ },
2030
+ languageItem: {
2031
+ paddingVertical: 8,
2032
+ paddingHorizontal: 12,
2033
+ borderBottomWidth: 1,
2034
+ borderBottomColor: "#e5e7eb"
2035
+ },
2036
+ languageItemText: {
2037
+ fontSize: 12,
2038
+ color: "#344054"
2039
+ },
2040
+ selectedLanguageItem: {
2041
+ backgroundColor: "#f3f4f6"
2042
+ },
2043
+ selectedLanguageItemText: {
2044
+ fontWeight: "600"
2045
+ }
2046
+ });
2047
+
2048
+ // src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx
2049
+ var import_jsx_runtime3 = require("react/jsx-runtime");
2050
+ var RedactoConsentInlineComponent = ({
2051
+ org_uuid,
2052
+ workspace_uuid,
2053
+ notice_uuid,
2054
+ accessToken,
2055
+ baseUrl,
2056
+ language = "en",
2057
+ onAccept,
2058
+ onDecline: _onDecline,
2059
+ onError,
2060
+ onValidationChange,
2061
+ settings,
2062
+ applicationId
2063
+ }) => {
2064
+ var _a, _b, _c, _d;
2065
+ const { isMobile } = useResponsive();
2066
+ const [content, setContent] = (0, import_react2.useState)(null);
2067
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
2068
+ const [isSubmitting, setIsSubmitting] = (0, import_react2.useState)(false);
2069
+ const [selectedLanguage, setSelectedLanguage] = (0, import_react2.useState)(language);
2070
+ const [collapsedPurposes, setCollapsedPurposes] = (0, import_react2.useState)({});
2071
+ const [selectedPurposes, setSelectedPurposes] = (0, import_react2.useState)({});
2072
+ const [selectedDataElements, setSelectedDataElements] = (0, import_react2.useState)({});
2073
+ const [hasAlreadyConsented, setHasAlreadyConsented] = (0, import_react2.useState)(false);
2074
+ const [fetchError, setFetchError] = (0, import_react2.useState)(null);
2075
+ const [errorMessage, setErrorMessage] = (0, import_react2.useState)(null);
2076
+ const [isLanguageDropdownOpen, setIsLanguageDropdownOpen] = (0, import_react2.useState)(false);
2077
+ const hasSubmittedRef = (0, import_react2.useRef)(false);
2078
+ const getTranslatedText = (0, import_react2.useCallback)(
2079
+ (key, defaultText, itemId) => {
2080
+ var _a2, _b2, _c2;
2081
+ if (!content) return defaultText;
2082
+ if (["en", "EN", "English"].includes(selectedLanguage)) {
2083
+ if (key === "privacy_policy_anchor_text" && content.privacy_policy_anchor_text) {
2084
+ return content.privacy_policy_anchor_text;
2085
+ }
2086
+ return defaultText;
2087
+ }
2088
+ const translationMap = (_a2 = content.supported_languages_and_translations) == null ? void 0 : _a2[selectedLanguage];
2089
+ if (!translationMap) return defaultText;
2090
+ if (itemId) {
2091
+ if (key === "purposes.name" || key === "purposes.description") {
2092
+ const purposeData = (_b2 = translationMap.purposes) == null ? void 0 : _b2[itemId];
2093
+ if (purposeData) {
2094
+ if (typeof purposeData === "string") {
2095
+ return key === "purposes.name" ? purposeData : defaultText;
2096
+ }
2097
+ return key === "purposes.name" ? purposeData.name || defaultText : purposeData.description || defaultText;
2098
+ }
2099
+ return defaultText;
2100
+ }
2101
+ if (key.startsWith("data_elements.")) {
2102
+ return ((_c2 = translationMap.data_elements) == null ? void 0 : _c2[itemId]) || defaultText;
2103
+ }
2104
+ }
2105
+ const value = translationMap[key];
2106
+ if (typeof value === "string" && value) return value;
2107
+ return defaultText;
2108
+ },
2109
+ [content, selectedLanguage]
2110
+ );
2111
+ const areAllRequiredElementsChecked = (0, import_react2.useMemo)(() => {
2112
+ if (!content) return false;
2113
+ return content.purposes.every((purpose) => {
2114
+ const requiredElements = purpose.data_elements.filter((el) => el.required);
2115
+ return requiredElements.every(
2116
+ (el) => selectedDataElements[`${purpose.uuid}-${el.uuid}`]
2117
+ );
2118
+ });
2119
+ }, [content, selectedDataElements]);
2120
+ (0, import_react2.useEffect)(() => {
2121
+ onValidationChange == null ? void 0 : onValidationChange(areAllRequiredElementsChecked);
2122
+ }, [areAllRequiredElementsChecked, onValidationChange]);
2123
+ const acceptDisabled = isSubmitting || !areAllRequiredElementsChecked || !accessToken;
2124
+ (0, import_react2.useEffect)(() => {
2125
+ if (hasAlreadyConsented) {
2126
+ onAccept == null ? void 0 : onAccept();
2127
+ }
2128
+ }, [hasAlreadyConsented, onAccept]);
2129
+ const fetchNotice = (0, import_react2.useCallback)(async (signal) => {
2130
+ setIsLoading(true);
2131
+ setFetchError(null);
2132
+ try {
2133
+ const consentContentData = await fetchConsentContent2({
2134
+ org_uuid,
2135
+ workspace_uuid,
2136
+ notice_uuid,
2137
+ baseUrl,
2138
+ language,
2139
+ specific_uuid: applicationId,
2140
+ signal
2141
+ });
2142
+ if (signal == null ? void 0 : signal.aborted) {
2143
+ return;
2144
+ }
2145
+ const activeConfig = consentContentData.detail.active_config;
2146
+ setContent(activeConfig);
2147
+ if (activeConfig.default_language) {
2148
+ setSelectedLanguage(activeConfig.default_language);
2149
+ }
2150
+ const initialCollapsedState = activeConfig.purposes.reduce(
2151
+ (acc, purpose) => ({ ...acc, [purpose.uuid]: true }),
2152
+ {}
2153
+ );
2154
+ setCollapsedPurposes(initialCollapsedState);
2155
+ const initialDataElementState = activeConfig.purposes.reduce(
2156
+ (acc, purpose) => {
2157
+ purpose.data_elements.forEach((el) => {
2158
+ acc[`${purpose.uuid}-${el.uuid}`] = false;
2159
+ });
2160
+ return acc;
2161
+ },
2162
+ {}
2163
+ );
2164
+ setSelectedDataElements(initialDataElementState);
2165
+ const initialPurposeState = activeConfig.purposes.reduce(
2166
+ (acc, purpose) => ({ ...acc, [purpose.uuid]: false }),
2167
+ {}
2168
+ );
2169
+ setSelectedPurposes(initialPurposeState);
2170
+ } catch (err) {
2171
+ if ((signal == null ? void 0 : signal.aborted) || err instanceof Error && err.name === "AbortError") {
2172
+ return;
2173
+ }
2174
+ const error = err;
2175
+ setFetchError(error);
2176
+ if (error.status === 409) {
2177
+ setHasAlreadyConsented(true);
2178
+ } else {
2179
+ onError == null ? void 0 : onError(error);
2180
+ }
2181
+ } finally {
2182
+ if (!(signal == null ? void 0 : signal.aborted)) {
2183
+ setIsLoading(false);
2184
+ }
2185
+ }
2186
+ }, [org_uuid, workspace_uuid, notice_uuid, baseUrl, language, applicationId, onError]);
2187
+ (0, import_react2.useEffect)(() => {
2188
+ const controller = new AbortController();
2189
+ void fetchNotice(controller.signal);
2190
+ return () => {
2191
+ controller.abort();
2192
+ };
2193
+ }, [fetchNotice]);
2194
+ const togglePurposeCollapse = (0, import_react2.useCallback)((purposeUuid) => {
2195
+ setCollapsedPurposes((prev) => ({ ...prev, [purposeUuid]: !prev[purposeUuid] }));
2196
+ }, []);
2197
+ const handlePurposeCheckboxChange = (0, import_react2.useCallback)(
2198
+ (purposeUuid) => {
2199
+ if (!content) return;
2200
+ const purpose = content.purposes.find((p) => p.uuid === purposeUuid);
2201
+ if (!purpose) return;
2202
+ const newPurposeState = !selectedPurposes[purposeUuid];
2203
+ setSelectedPurposes((prev) => ({ ...prev, [purposeUuid]: newPurposeState }));
2204
+ setSelectedDataElements((prev) => {
2205
+ const updated = { ...prev };
2206
+ purpose.data_elements.forEach((el) => {
2207
+ updated[`${purposeUuid}-${el.uuid}`] = newPurposeState;
2208
+ });
2209
+ return updated;
2210
+ });
2211
+ },
2212
+ [content, selectedPurposes]
2213
+ );
2214
+ const handleDataElementCheckboxChange = (0, import_react2.useCallback)(
2215
+ (elementUuid, purposeUuid) => {
2216
+ if (!content) return;
2217
+ const purpose = content.purposes.find((p) => p.uuid === purposeUuid);
2218
+ if (!purpose) return;
2219
+ const combinedId = `${purposeUuid}-${elementUuid}`;
2220
+ setSelectedDataElements((prev) => {
2221
+ const newState = { ...prev, [combinedId]: !prev[combinedId] };
2222
+ const requiredElements = purpose.data_elements.filter((el) => el.required);
2223
+ const shouldCheckPurpose = requiredElements.length > 0 ? requiredElements.every((el) => newState[`${purposeUuid}-${el.uuid}`]) : purpose.data_elements.some((el) => newState[`${purposeUuid}-${el.uuid}`]);
2224
+ setSelectedPurposes((prev2) => ({ ...prev2, [purposeUuid]: shouldCheckPurpose }));
2225
+ return newState;
2226
+ });
2227
+ },
2228
+ [content]
2229
+ );
2230
+ const handleAcceptWithToken = (0, import_react2.useCallback)(
2231
+ async (tokenToUse) => {
2232
+ if (!tokenToUse || !content) {
2233
+ setErrorMessage("Unable to submit consent. Please try again.");
2234
+ throw new Error("Access token or content not available");
2235
+ }
2236
+ try {
2237
+ setIsSubmitting(true);
2238
+ setErrorMessage(null);
2239
+ await submitConsentEvent2({
2240
+ org_uuid,
2241
+ workspace_uuid,
2242
+ accessToken: tokenToUse,
2243
+ baseUrl,
2244
+ noticeUuid: content.notice_uuid,
2245
+ purposes: content.purposes.map((purpose) => {
2246
+ const hasSelectedRequiredElement = purpose.data_elements.some(
2247
+ (el) => el.required && (selectedDataElements[`${purpose.uuid}-${el.uuid}`] || false)
2248
+ );
2249
+ const hasSelectedDataElement = purpose.data_elements.some(
2250
+ (el) => selectedDataElements[`${purpose.uuid}-${el.uuid}`] || false
2251
+ );
2252
+ const purposeSelected = selectedPurposes[purpose.uuid] || hasSelectedRequiredElement || hasSelectedDataElement;
2253
+ return {
2254
+ ...purpose,
2255
+ selected: purposeSelected,
2256
+ data_elements: purpose.data_elements.map((el) => ({
2257
+ ...el,
2258
+ selected: selectedDataElements[`${purpose.uuid}-${el.uuid}`] || false
2259
+ }))
2260
+ };
2261
+ }),
2262
+ declined: false,
2263
+ meta_data: applicationId ? { specific_uuid: applicationId } : void 0
2264
+ });
2265
+ onAccept == null ? void 0 : onAccept();
2266
+ hasSubmittedRef.current = false;
2267
+ } catch (error) {
2268
+ const err = error;
2269
+ 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.";
2270
+ setErrorMessage(message);
2271
+ hasSubmittedRef.current = false;
2272
+ throw error;
2273
+ } finally {
2274
+ setIsSubmitting(false);
2275
+ }
2276
+ },
2277
+ [
2278
+ content,
2279
+ org_uuid,
2280
+ workspace_uuid,
2281
+ baseUrl,
2282
+ selectedDataElements,
2283
+ selectedPurposes,
2284
+ applicationId,
2285
+ onAccept
2286
+ ]
2287
+ );
2288
+ (0, import_react2.useEffect)(() => {
2289
+ if (accessToken && content && areAllRequiredElementsChecked && !isSubmitting && !hasSubmittedRef.current) {
2290
+ hasSubmittedRef.current = true;
2291
+ const autoSubmit = async () => {
2292
+ try {
2293
+ await handleAcceptWithToken(accessToken);
2294
+ } catch (err) {
2295
+ hasSubmittedRef.current = false;
2296
+ onError == null ? void 0 : onError(err);
2297
+ }
2298
+ };
2299
+ autoSubmit();
2300
+ }
2301
+ }, [accessToken, content, areAllRequiredElementsChecked, isSubmitting, handleAcceptWithToken, onError]);
2302
+ (0, import_react2.useEffect)(() => {
2303
+ if (!accessToken) {
2304
+ hasSubmittedRef.current = false;
2305
+ }
2306
+ }, [accessToken]);
2307
+ const headingColor = (settings == null ? void 0 : settings.headingColor) || "#101828";
2308
+ const textColor = (settings == null ? void 0 : settings.textColor) || "#344054";
2309
+ const supportedLanguages = (0, import_react2.useMemo)(
2310
+ () => Object.keys((content == null ? void 0 : content.supported_languages_and_translations) || {}),
2311
+ [content]
2312
+ );
2313
+ if (hasAlreadyConsented || fetchError) return null;
2314
+ if (isLoading) {
2315
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { style: styles3.loadingContainer, children: [
2316
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.ActivityIndicator, { size: "large", color: "#4f87ff" }),
2317
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: [styles3.loadingText, { color: textColor }], children: "Loading..." })
2318
+ ] });
2319
+ }
2320
+ if (!content) return null;
2321
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { style: { gap: 16 }, children: [
2322
+ errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.View, { style: styles3.errorContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: styles3.errorText, children: errorMessage }) }) : null,
2323
+ supportedLanguages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { style: [styles3.topSection, { borderBottomWidth: 0, paddingBottom: 0 }], children: [
2324
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.View, {}),
2325
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { style: styles3.languageSelectorContainer, children: [
2326
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2327
+ import_react_native6.TouchableOpacity,
2328
+ {
2329
+ style: [
2330
+ styles3.topRight,
2331
+ ((_a = settings == null ? void 0 : settings.button) == null ? void 0 : _a.language) ? { backgroundColor: settings.button.language.backgroundColor, borderColor: settings.button.language.backgroundColor } : null
2332
+ ],
2333
+ onPress: () => setIsLanguageDropdownOpen((v) => !v),
2334
+ children: [
2335
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: [styles3.topRightText, ((_b = settings == null ? void 0 : settings.button) == null ? void 0 : _b.language) ? { color: settings.button.language.textColor } : null], children: selectedLanguage }),
2336
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_svg3.default, { width: 12, height: 12, viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2337
+ import_react_native_svg3.Path,
2338
+ {
2339
+ d: "M4 6L8 10L12 6",
2340
+ stroke: ((_d = (_c = settings == null ? void 0 : settings.button) == null ? void 0 : _c.language) == null ? void 0 : _d.textColor) || "#344054",
2341
+ strokeWidth: 2,
2342
+ strokeLinecap: "round",
2343
+ strokeLinejoin: "round"
2344
+ }
2345
+ ) })
2346
+ ]
2347
+ }
2348
+ ),
2349
+ isLanguageDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.View, { style: styles3.languageDropdown, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.ScrollView, { children: supportedLanguages.map((lang) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2350
+ import_react_native6.TouchableOpacity,
2351
+ {
2352
+ style: [
2353
+ styles3.languageItem,
2354
+ lang === selectedLanguage ? styles3.selectedLanguageItem : null
2355
+ ],
2356
+ onPress: () => {
2357
+ setSelectedLanguage(lang);
2358
+ setIsLanguageDropdownOpen(false);
2359
+ },
2360
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: [styles3.languageItemText, lang === selectedLanguage ? styles3.selectedLanguageItemText : null], children: lang })
2361
+ },
2362
+ lang
2363
+ )) }) })
2364
+ ] })
2365
+ ] }),
2366
+ content.purposes.map((purpose) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { children: [
2367
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { style: styles3.optionItem, children: [
2368
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2369
+ import_react_native6.TouchableOpacity,
2370
+ {
2371
+ style: styles3.optionLeft,
2372
+ onPress: () => togglePurposeCollapse(purpose.uuid),
2373
+ accessibilityRole: "button",
2374
+ accessibilityLabel: `${collapsedPurposes[purpose.uuid] ? "Expand" : "Collapse"} ${getTranslatedText("purposes.name", purpose.name, purpose.uuid)}`,
2375
+ children: [
2376
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.View, { style: styles3.purposeChevron, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_svg3.default, { width: 7, height: 12, viewBox: "0 0 7 12", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2377
+ import_react_native_svg3.Path,
2378
+ {
2379
+ d: "M1 1L6 6L1 11",
2380
+ stroke: (settings == null ? void 0 : settings.headingColor) || "#323B4B",
2381
+ strokeWidth: 2,
2382
+ strokeLinecap: "round",
2383
+ strokeLinejoin: "round",
2384
+ transform: !collapsedPurposes[purpose.uuid] ? "rotate(90 3.5 6)" : void 0
2385
+ }
2386
+ ) }) }),
2387
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { style: styles3.optionTextContainer, children: [
2388
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: [styles3.optionTitle, { color: headingColor }, isMobile ? { fontSize: 14 } : null], children: getTranslatedText("purposes.name", purpose.name, purpose.uuid) }),
2389
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: [styles3.optionDescription, { color: textColor }, isMobile ? { fontSize: 11 } : null], children: getTranslatedText("purposes.description", purpose.description, purpose.uuid) })
2390
+ ] })
2391
+ ]
2392
+ }
2393
+ ),
2394
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2395
+ Checkbox,
2396
+ {
2397
+ checked: selectedPurposes[purpose.uuid] || false,
2398
+ onChange: () => handlePurposeCheckboxChange(purpose.uuid),
2399
+ size: "large",
2400
+ accessibilityLabel: `Select all data elements for ${getTranslatedText("purposes.name", purpose.name, purpose.uuid)}`
2401
+ }
2402
+ )
2403
+ ] }),
2404
+ !collapsedPurposes[purpose.uuid] && purpose.data_elements && purpose.data_elements.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.View, { style: styles3.dataElementsContainer, children: purpose.data_elements.map((dataElement) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.View, { style: styles3.dataElementItem, children: [
2405
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native6.Text, { style: [styles3.dataElementText, { color: textColor }, isMobile ? { fontSize: 12 } : null], children: [
2406
+ getTranslatedText("data_elements.name", dataElement.name, dataElement.uuid),
2407
+ dataElement.required && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Text, { style: styles3.requiredAsterisk, children: " *" })
2408
+ ] }),
2409
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2410
+ Checkbox,
2411
+ {
2412
+ checked: selectedDataElements[`${purpose.uuid}-${dataElement.uuid}`] || false,
2413
+ onChange: () => handleDataElementCheckboxChange(dataElement.uuid, purpose.uuid),
2414
+ size: "small",
2415
+ accessibilityLabel: `Select ${getTranslatedText("data_elements.name", dataElement.name, dataElement.uuid)}${dataElement.required ? " (required)" : ""}`
2416
+ }
2417
+ )
2418
+ ] }, dataElement.uuid)) })
2419
+ ] }, purpose.uuid))
2420
+ ] });
2421
+ };
2422
+ RedactoConsentInlineComponent.displayName = "RedactoConsentInline";
2423
+ var RedactoConsentInline = (0, import_react2.memo)(RedactoConsentInlineComponent);
2424
+ // Annotate the CommonJS export names for ESM import in node:
2425
+ 0 && (module.exports = {
2426
+ RedactoNoticeConsent,
2427
+ RedactoNoticeConsentInline
2428
+ });