@redacto.io/consent-sdk-react 0.0.1 → 0.0.2

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 CHANGED
@@ -29,54 +29,37 @@ var import_react2 = require("react");
29
29
 
30
30
  // src/RedactoNoticeConsent/api/index.ts
31
31
  var import_jwt_decode = require("jwt-decode");
32
- var BASE_URL = "https://api.redacto.tech";
33
- var BACKEND_URL = "http://localhost:3000";
32
+ var BASE_URL = "https://api.redacto.tech/consent";
34
33
  var fetchConsentContent = async ({
35
34
  noticeId,
36
35
  accessToken,
37
- refreshToken,
38
- language = "en"
36
+ baseUrl,
37
+ language = "en",
38
+ specific_uuid
39
39
  }) => {
40
40
  try {
41
41
  const decodedToken = (0, import_jwt_decode.jwtDecode)(accessToken);
42
42
  const ORGANISATION_UUID = decodedToken == null ? void 0 : decodedToken.organisation_uuid;
43
43
  const WORKSPACE_UUID = decodedToken == null ? void 0 : decodedToken.workspace_uuid;
44
- const response = await fetch(
45
- `${BASE_URL}/consent/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeId}`,
46
- {
47
- method: "GET",
48
- headers: {
49
- Authorization: `Bearer ${accessToken}`,
50
- "Accept-Language": language,
51
- "Content-Type": "application/json"
52
- }
53
- }
44
+ const apiBaseUrl = baseUrl || BASE_URL;
45
+ const url = new URL(
46
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/notices/${noticeId}`
54
47
  );
55
- if (response.status === 401) {
56
- try {
57
- const response2 = await fetch(
58
- `${BACKEND_URL}/api/consent/refresh-token`,
59
- {
60
- method: "POST",
61
- headers: {
62
- "Content-Type": "application/json"
63
- },
64
- body: JSON.stringify({
65
- refreshToken
66
- })
67
- }
68
- );
69
- if (!response2.ok) {
70
- throw new Error("Failed to get consent tokens");
71
- }
72
- const data2 = await response2.json();
73
- localStorage.setItem("accessToken", data2.token);
74
- localStorage.setItem("refreshToken", data2.refresh_token);
75
- localStorage.setItem("tokenExpiresAt", data2.expires_at);
76
- } catch (error) {
77
- console.error("Failed to setup consent:", error);
78
- throw error;
48
+ if (specific_uuid) {
49
+ url.searchParams.append("specific_uuid", specific_uuid);
50
+ }
51
+ const response = await fetch(url.toString(), {
52
+ method: "GET",
53
+ headers: {
54
+ Authorization: `Bearer ${accessToken}`,
55
+ "Accept-Language": language,
56
+ "Content-Type": "application/json"
79
57
  }
58
+ });
59
+ if (response.status === 401) {
60
+ const error = new Error("Unauthorized");
61
+ error.status = 401;
62
+ throw error;
80
63
  }
81
64
  if (response.status === 409) {
82
65
  const error = new Error("User has already provided consent");
@@ -97,9 +80,11 @@ var fetchConsentContent = async ({
97
80
  };
98
81
  var submitConsentEvent = async ({
99
82
  accessToken,
83
+ baseUrl,
100
84
  noticeUuid,
101
85
  purposes,
102
- declined
86
+ declined,
87
+ meta_data
103
88
  }) => {
104
89
  try {
105
90
  const primaryEmail = localStorage.getItem("userEmail");
@@ -116,7 +101,7 @@ var submitConsentEvent = async ({
116
101
  uuid: purpose.uuid,
117
102
  name: purpose.name,
118
103
  description: purpose.description,
119
- industries: purpose.industries,
104
+ industries: purpose.industries || "",
120
105
  selected: purpose.selected,
121
106
  data_elements: purpose.data_elements.map((element) => ({
122
107
  uuid: element.uuid,
@@ -126,10 +111,12 @@ var submitConsentEvent = async ({
126
111
  selected: element.required ? true : element.selected
127
112
  }))
128
113
  }))
129
- }
114
+ },
115
+ meta_data
130
116
  };
117
+ const apiBaseUrl = baseUrl || BASE_URL;
131
118
  const response = await fetch(
132
- `${BASE_URL}/consent/public/consent-events/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/by-token`,
119
+ `${apiBaseUrl}/public/organisations/${ORGANISATION_UUID}/workspaces/${WORKSPACE_UUID}/by-token`,
133
120
  {
134
121
  method: "POST",
135
122
  headers: {
@@ -162,7 +149,10 @@ var styles = {
162
149
  justifyContent: "center",
163
150
  zIndex: 999,
164
151
  animation: "overlayFadeIn 0.2s cubic-bezier(0.16, 1, 0.3, 1)",
165
- pointerEvents: "all"
152
+ pointerEvents: "all",
153
+ margin: 0,
154
+ padding: 0,
155
+ boxSizing: "border-box"
166
156
  },
167
157
  modal: {
168
158
  position: "fixed",
@@ -177,7 +167,12 @@ var styles = {
177
167
  display: "flex",
178
168
  flexDirection: "column",
179
169
  maxHeight: "90vh",
180
- zIndex: 1e3
170
+ zIndex: 1e3,
171
+ margin: 0,
172
+ padding: 0,
173
+ boxSizing: "border-box",
174
+ textAlign: "left",
175
+ fontFamily: "inherit"
181
176
  },
182
177
  content: {
183
178
  margin: "22px",
@@ -185,7 +180,9 @@ var styles = {
185
180
  flexDirection: "column",
186
181
  flexGrow: 1,
187
182
  overflow: "hidden",
188
- minHeight: 0
183
+ minHeight: 0,
184
+ boxSizing: "border-box",
185
+ textAlign: "left"
189
186
  },
190
187
  topSection: {
191
188
  display: "flex",
@@ -194,17 +191,26 @@ var styles = {
194
191
  paddingBottom: "15px",
195
192
  borderBottom: "1px solid #e5e7eb",
196
193
  boxShadow: "0 1px 2px rgba(0, 0, 0, 0.03)",
197
- backgroundColor: "#ffffff"
194
+ backgroundColor: "#ffffff",
195
+ margin: 0,
196
+ boxSizing: "border-box",
197
+ textAlign: "left"
198
198
  },
199
199
  topLeft: {
200
200
  display: "flex",
201
201
  alignItems: "center",
202
- gap: "10px"
202
+ gap: "10px",
203
+ margin: 0,
204
+ padding: 0,
205
+ boxSizing: "border-box"
203
206
  },
204
207
  logo: {
205
208
  height: "32px",
206
209
  width: "auto",
207
- objectFit: "contain"
210
+ objectFit: "contain",
211
+ margin: 0,
212
+ padding: 0,
213
+ display: "block"
208
214
  },
209
215
  title: {
210
216
  fontSize: "18px",
@@ -212,7 +218,10 @@ var styles = {
212
218
  lineHeight: "150%",
213
219
  letterSpacing: "0.2px",
214
220
  verticalAlign: "middle",
215
- color: "#101828"
221
+ color: "#101828",
222
+ margin: 0,
223
+ padding: 0,
224
+ textAlign: "left"
216
225
  },
217
226
  topRight: {
218
227
  borderRadius: "8px",
@@ -228,6 +237,9 @@ var styles = {
228
237
  verticalAlign: "middle",
229
238
  color: "#344054",
230
239
  gap: "5px",
240
+ margin: 0,
241
+ boxSizing: "border-box",
242
+ textAlign: "left",
231
243
  cursor: "pointer",
232
244
  backgroundColor: "#ffffff"
233
245
  },
@@ -239,52 +251,78 @@ var styles = {
239
251
  flexGrow: 1,
240
252
  overflowY: "auto",
241
253
  minHeight: 0,
242
- paddingRight: "15px"
254
+ paddingRight: "15px",
255
+ boxSizing: "border-box",
256
+ textAlign: "left"
243
257
  },
244
258
  privacyText: {
245
259
  fontSize: "16px",
246
260
  fontWeight: 400,
247
261
  lineHeight: "150%",
248
262
  letterSpacing: "0.2px",
249
- color: "#344054"
263
+ color: "#344054",
264
+ margin: 0,
265
+ padding: 0,
266
+ textAlign: "left"
250
267
  },
251
268
  link: {
252
269
  color: "#4f87ff",
253
- textDecoration: "none"
270
+ textDecoration: "none",
271
+ margin: 0,
272
+ padding: 0,
273
+ boxSizing: "border-box"
254
274
  },
255
275
  subTitle: {
256
276
  fontWeight: 600,
257
277
  fontSize: "16px",
258
278
  lineHeight: "150%",
259
279
  letterSpacing: "0.2px",
260
- color: "#101828"
280
+ color: "#101828",
281
+ margin: 0,
282
+ padding: 0,
283
+ textAlign: "left"
261
284
  },
262
285
  optionsContainer: {
263
286
  display: "flex",
264
287
  flexDirection: "column",
265
- gap: "14px"
288
+ gap: "14px",
289
+ margin: 0,
290
+ padding: 0,
291
+ boxSizing: "border-box"
266
292
  },
267
293
  optionItem: {
268
294
  display: "flex",
269
295
  justifyContent: "space-between",
270
- alignItems: "center"
296
+ alignItems: "center",
297
+ margin: 0,
298
+ padding: 0,
299
+ boxSizing: "border-box"
271
300
  },
272
301
  optionLeft: {
273
302
  display: "flex",
274
303
  gap: "12px",
275
304
  alignItems: "center",
276
- cursor: "pointer"
305
+ cursor: "pointer",
306
+ margin: 0,
307
+ padding: 0,
308
+ boxSizing: "border-box"
277
309
  },
278
310
  optionTextContainer: {
279
311
  display: "flex",
280
- flexDirection: "column"
312
+ flexDirection: "column",
313
+ margin: 0,
314
+ padding: 0,
315
+ boxSizing: "border-box"
281
316
  },
282
317
  optionTitle: {
283
318
  fontWeight: 500,
284
319
  fontSize: "16px",
285
320
  lineHeight: "150%",
286
321
  letterSpacing: "0.2px",
287
- color: "#101828"
322
+ color: "#101828",
323
+ margin: 0,
324
+ padding: 0,
325
+ textAlign: "left"
288
326
  },
289
327
  optionDescription: {
290
328
  fontWeight: 400,
@@ -292,39 +330,57 @@ var styles = {
292
330
  lineHeight: "150%",
293
331
  letterSpacing: "0.2px",
294
332
  color: "#475467",
295
- verticalAlign: "middle"
333
+ verticalAlign: "middle",
334
+ margin: 0,
335
+ padding: 0,
336
+ textAlign: "left"
296
337
  },
297
338
  checkboxLarge: {
298
339
  height: "20px",
299
340
  width: "20px",
300
341
  padding: "4px",
301
342
  borderRadius: "5px",
302
- border: "2px solid #d0d5dd"
343
+ border: "2px solid #d0d5dd",
344
+ margin: 0,
345
+ boxSizing: "border-box"
303
346
  },
304
347
  dataElementsContainer: {
305
348
  marginLeft: "27px",
306
349
  display: "flex",
307
- flexDirection: "column"
350
+ flexDirection: "column",
351
+ margin: 0,
352
+ padding: 0,
353
+ boxSizing: "border-box",
354
+ paddingLeft: "22px"
308
355
  },
309
356
  dataElementItem: {
310
357
  display: "flex",
311
358
  alignItems: "center",
312
359
  gap: "10px",
313
- justifyContent: "space-between"
360
+ justifyContent: "space-between",
361
+ margin: 0,
362
+ padding: 0,
363
+ boxSizing: "border-box",
364
+ minHeight: "24px"
314
365
  },
315
366
  dataElementText: {
316
367
  fontWeight: 400,
317
368
  fontSize: "14px",
318
369
  lineHeight: "150%",
319
370
  letterSpacing: "0.2px",
320
- color: "#344054"
371
+ color: "#344054",
372
+ margin: 0,
373
+ padding: 0,
374
+ textAlign: "left"
321
375
  },
322
376
  checkboxSmall: {
323
377
  height: "16px",
324
378
  width: "16px",
325
379
  padding: "4px",
326
380
  borderRadius: "5px",
327
- border: "2px solid #d0d5dd"
381
+ border: "2px solid #d0d5dd",
382
+ margin: 0,
383
+ boxSizing: "border-box"
328
384
  },
329
385
  bottomSection: {
330
386
  display: "flex",
@@ -333,7 +389,9 @@ var styles = {
333
389
  paddingTop: "15px",
334
390
  borderTop: "1px solid #e5e7eb",
335
391
  boxShadow: "0 -1px 2px rgba(0, 0, 0, 0.03)",
336
- backgroundColor: "#ffffff"
392
+ backgroundColor: "#ffffff",
393
+ margin: 0,
394
+ boxSizing: "border-box"
337
395
  },
338
396
  button: {
339
397
  width: "100%",
@@ -343,7 +401,10 @@ var styles = {
343
401
  fontSize: "16px",
344
402
  lineHeight: "150%",
345
403
  letterSpacing: "0.2px",
346
- cursor: "pointer"
404
+ cursor: "pointer",
405
+ margin: 0,
406
+ boxSizing: "border-box",
407
+ textAlign: "center"
347
408
  },
348
409
  acceptButton: {
349
410
  backgroundColor: "#4f87ff",
@@ -356,7 +417,10 @@ var styles = {
356
417
  color: "#000000"
357
418
  },
358
419
  languageSelectorContainer: {
359
- position: "relative"
420
+ position: "relative",
421
+ margin: 0,
422
+ padding: 0,
423
+ boxSizing: "border-box"
360
424
  },
361
425
  languageDropdown: {
362
426
  position: "absolute",
@@ -368,7 +432,10 @@ var styles = {
368
432
  boxShadow: "0px 2px 4px rgba(0, 0, 0, 0.1)",
369
433
  zIndex: 10,
370
434
  width: "max-content",
371
- marginTop: "4px"
435
+ marginTop: "4px",
436
+ padding: 0,
437
+ boxSizing: "border-box",
438
+ textAlign: "left"
372
439
  },
373
440
  languageItem: {
374
441
  padding: "8px 12px",
@@ -376,7 +443,10 @@ var styles = {
376
443
  fontSize: "12px",
377
444
  color: "#344054",
378
445
  backgroundColor: "#ffffff",
379
- borderBottom: "1px solid #e5e7eb"
446
+ borderBottom: "1px solid #e5e7eb",
447
+ margin: 0,
448
+ boxSizing: "border-box",
449
+ textAlign: "left"
380
450
  },
381
451
  selectedLanguageItem: {
382
452
  backgroundColor: "#f3f4f6",
@@ -388,7 +458,9 @@ var styles = {
388
458
  alignItems: "center",
389
459
  justifyContent: "center",
390
460
  padding: "2rem",
391
- minHeight: "200px"
461
+ minHeight: "200px",
462
+ margin: 0,
463
+ boxSizing: "border-box"
392
464
  },
393
465
  loadingSpinner: {
394
466
  width: "40px",
@@ -397,55 +469,8 @@ var styles = {
397
469
  borderTop: "4px solid #3498db",
398
470
  borderRadius: "50%",
399
471
  animation: "spin 1s linear infinite",
400
- marginBottom: "1rem"
401
- },
402
- // Media query styles
403
- "@media (max-width: 768px)": {
404
- modal: {
405
- width: "90%"
406
- },
407
- content: {
408
- margin: "20px"
409
- },
410
- title: {
411
- fontSize: "16px"
412
- },
413
- subTitle: {
414
- fontSize: "14px"
415
- },
416
- privacyText: {
417
- fontSize: "14px"
418
- },
419
- optionTitle: {
420
- fontSize: "14px"
421
- },
422
- optionDescription: {
423
- fontSize: "11px"
424
- },
425
- dataElementText: {
426
- fontSize: "12px"
427
- },
428
- topRight: {
429
- fontSize: "11px",
430
- padding: "3px 6px",
431
- height: "auto",
432
- width: "auto"
433
- },
434
- languageItem: {
435
- fontSize: "11px",
436
- padding: "6px 10px"
437
- },
438
- bottomSection: {
439
- flexDirection: "column",
440
- gap: "12px"
441
- },
442
- button: {
443
- fontSize: "14px",
444
- padding: "10px 20px"
445
- },
446
- middleSection: {
447
- paddingRight: "10px"
448
- }
472
+ marginBottom: "1rem",
473
+ boxSizing: "border-box"
449
474
  }
450
475
  };
451
476
 
@@ -485,23 +510,33 @@ var RedactoNoticeConsent = ({
485
510
  noticeId,
486
511
  accessToken,
487
512
  refreshToken,
513
+ baseUrl,
488
514
  language = "en",
489
- blockUI = false,
515
+ blockUI = true,
490
516
  onAccept,
491
517
  onDecline,
492
518
  onError,
493
- settings
519
+ settings,
520
+ applicationId
494
521
  }) => {
495
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
522
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
496
523
  const [content, setContent] = (0, import_react2.useState)(null);
497
524
  const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
498
525
  const [isSubmitting, setIsSubmitting] = (0, import_react2.useState)(false);
526
+ const [isRefreshingToken, setIsRefreshingToken] = (0, import_react2.useState)(false);
499
527
  const [isLanguageDropdownOpen, setIsLanguageDropdownOpen] = (0, import_react2.useState)(false);
500
528
  const [selectedLanguage, setSelectedLanguage] = (0, import_react2.useState)(language);
501
529
  const [collapsedPurposes, setCollapsedPurposes] = (0, import_react2.useState)({});
502
530
  const [selectedPurposes, setSelectedPurposes] = (0, import_react2.useState)({});
503
531
  const [selectedDataElements, setSelectedDataElements] = (0, import_react2.useState)({});
504
532
  const [hasAlreadyConsented, setHasAlreadyConsented] = (0, import_react2.useState)(false);
533
+ const [errorMessage, setErrorMessage] = (0, import_react2.useState)(null);
534
+ const [fetchError, setFetchError] = (0, import_react2.useState)(null);
535
+ const modalRef = (0, import_react2.useRef)(null);
536
+ const firstFocusableRef = (0, import_react2.useRef)(null);
537
+ const lastFocusableRef = (0, import_react2.useRef)(null);
538
+ const MAX_REFRESH_ATTEMPTS = 1;
539
+ const [refreshAttempts, setRefreshAttempts] = (0, import_react2.useState)(0);
505
540
  const isMobile = useMediaQuery("(max-width: 768px)");
506
541
  const responsiveStyles = (0, import_react2.useMemo)(
507
542
  () => ({
@@ -549,6 +584,28 @@ var RedactoNoticeConsent = ({
549
584
  },
550
585
  middleSection: {
551
586
  paddingRight: isMobile ? "10px" : "15px"
587
+ },
588
+ errorDialog: {
589
+ padding: isMobile ? "12px" : "16px",
590
+ maxWidth: isMobile ? "100%" : "400px",
591
+ marginBottom: isMobile ? "16px" : "20px"
592
+ },
593
+ errorTitle: {
594
+ fontSize: isMobile ? "16px" : "18px",
595
+ margin: isMobile ? "0 0 8px 0" : "0 0 12px 0"
596
+ },
597
+ errorMessage: {
598
+ fontSize: isMobile ? "12px" : "14px",
599
+ margin: isMobile ? "0 0 12px 0" : "0 0 16px 0"
600
+ },
601
+ errorButton: {
602
+ padding: isMobile ? "6px 12px" : "8px 16px",
603
+ fontSize: isMobile ? "12px" : "14px"
604
+ },
605
+ closeButton: {
606
+ top: isMobile ? "4px" : "8px",
607
+ right: isMobile ? "4px" : "8px",
608
+ padding: isMobile ? "2px" : "4px"
552
609
  }
553
610
  }),
554
611
  [isMobile]
@@ -600,65 +657,82 @@ var RedactoNoticeConsent = ({
600
657
  }
601
658
  return defaultText;
602
659
  };
603
- (0, import_react2.useEffect)(() => {
604
- const fetchNotice = async () => {
605
- setIsLoading(true);
606
- try {
607
- const consentContentData = await fetchConsentContent({
608
- noticeId,
609
- accessToken,
610
- refreshToken,
611
- language
612
- });
613
- setContent(consentContentData.detail.active_config);
614
- if (consentContentData.detail.active_config.default_language) {
615
- setSelectedLanguage(
616
- consentContentData.detail.active_config.default_language
617
- );
618
- }
619
- const initialCollapsedState = consentContentData.detail.active_config.purposes.reduce(
620
- (acc, purpose) => ({
621
- ...acc,
622
- [purpose.uuid]: true
623
- }),
624
- {}
625
- );
626
- setCollapsedPurposes(initialCollapsedState);
627
- const initialPurposeState = consentContentData.detail.active_config.purposes.reduce(
628
- (acc, purpose) => {
629
- return {
630
- ...acc,
631
- [purpose.uuid]: false
632
- // Initialize all purposes as unchecked
633
- };
634
- },
635
- {}
636
- );
637
- setSelectedPurposes(initialPurposeState);
638
- const initialDataElementState = consentContentData.detail.active_config.purposes.reduce(
639
- (acc, purpose) => {
640
- purpose.data_elements.forEach((element) => {
641
- const combinedId = `${purpose.uuid}-${element.uuid}`;
642
- acc[combinedId] = false;
643
- });
644
- return acc;
645
- },
646
- {}
660
+ const fetchNotice = async () => {
661
+ setIsLoading(true);
662
+ setFetchError(null);
663
+ try {
664
+ const consentContentData = await fetchConsentContent({
665
+ noticeId,
666
+ accessToken,
667
+ refreshToken,
668
+ baseUrl,
669
+ language,
670
+ specific_uuid: applicationId
671
+ });
672
+ setContent(consentContentData.detail.active_config);
673
+ if (consentContentData.detail.active_config.default_language) {
674
+ setSelectedLanguage(
675
+ consentContentData.detail.active_config.default_language
647
676
  );
648
- setSelectedDataElements(initialDataElementState);
649
- } catch (err) {
650
- console.error(err);
651
- if (err.status === 409) {
652
- setHasAlreadyConsented(true);
653
- } else {
654
- onError == null ? void 0 : onError(err);
655
- }
656
- } finally {
657
- setIsLoading(false);
658
677
  }
659
- };
678
+ const initialCollapsedState = consentContentData.detail.active_config.purposes.reduce(
679
+ (acc, purpose) => ({
680
+ ...acc,
681
+ [purpose.uuid]: true
682
+ }),
683
+ {}
684
+ );
685
+ setCollapsedPurposes(initialCollapsedState);
686
+ const initialPurposeState = consentContentData.detail.active_config.purposes.reduce(
687
+ (acc, purpose) => {
688
+ return {
689
+ ...acc,
690
+ [purpose.uuid]: false
691
+ };
692
+ },
693
+ {}
694
+ );
695
+ setSelectedPurposes(initialPurposeState);
696
+ const initialDataElementState = consentContentData.detail.active_config.purposes.reduce(
697
+ (acc, purpose) => {
698
+ purpose.data_elements.forEach((element) => {
699
+ const combinedId = `${purpose.uuid}-${element.uuid}`;
700
+ acc[combinedId] = false;
701
+ });
702
+ return acc;
703
+ },
704
+ {}
705
+ );
706
+ setSelectedDataElements(initialDataElementState);
707
+ } catch (err) {
708
+ console.error(err);
709
+ const error = err;
710
+ setFetchError(error);
711
+ if (error.status === 401 && refreshAttempts < MAX_REFRESH_ATTEMPTS) {
712
+ setRefreshAttempts((c) => c + 1);
713
+ setIsRefreshingToken(true);
714
+ onError == null ? void 0 : onError(error);
715
+ } else if (error.status === 409) {
716
+ setHasAlreadyConsented(true);
717
+ } else {
718
+ onError == null ? void 0 : onError(error);
719
+ }
720
+ } finally {
721
+ setIsLoading(false);
722
+ setIsRefreshingToken(false);
723
+ }
724
+ };
725
+ (0, import_react2.useEffect)(() => {
660
726
  fetchNotice();
661
- }, [noticeId, accessToken, refreshToken, language, onError]);
727
+ }, [
728
+ noticeId,
729
+ accessToken,
730
+ refreshToken,
731
+ language,
732
+ onError,
733
+ applicationId,
734
+ isRefreshingToken
735
+ ]);
662
736
  const togglePurposeCollapse = (purposeUuid) => {
663
737
  setCollapsedPurposes((prev) => ({
664
738
  ...prev,
@@ -719,9 +793,11 @@ var RedactoNoticeConsent = ({
719
793
  const handleAccept = async () => {
720
794
  try {
721
795
  setIsSubmitting(true);
796
+ setErrorMessage(null);
722
797
  if (content) {
723
798
  await submitConsentEvent({
724
799
  accessToken,
800
+ baseUrl,
725
801
  noticeUuid: content.notice_uuid,
726
802
  purposes: content.purposes.map((purpose) => ({
727
803
  ...purpose,
@@ -731,12 +807,19 @@ var RedactoNoticeConsent = ({
731
807
  selected: element.required ? true : selectedDataElements[`${purpose.uuid}-${element.uuid}`] || false
732
808
  }))
733
809
  })),
734
- declined: false
810
+ declined: false,
811
+ meta_data: applicationId ? { specific_uuid: applicationId } : void 0
735
812
  });
736
813
  }
737
814
  onAccept == null ? void 0 : onAccept();
738
815
  } catch (error) {
739
816
  console.error("Error submitting consent:", error);
817
+ const err = error;
818
+ if (err.status === 500) {
819
+ setErrorMessage(
820
+ "An error occurred while submitting your consent. Please try again later."
821
+ );
822
+ }
740
823
  onError == null ? void 0 : onError(error);
741
824
  } finally {
742
825
  setIsSubmitting(false);
@@ -761,7 +844,7 @@ var RedactoNoticeConsent = ({
761
844
  };
762
845
  const acceptButtonStyle = {
763
846
  ...buttonStyle,
764
- backgroundColor: ((_b = (_a = settings == null ? void 0 : settings.button) == null ? void 0 : _a.accept) == null ? void 0 : _b.backgroundColor) || "#4f87ff",
847
+ backgroundColor: ((_b = (_a = settings == null ? void 0 : settings.button) == null ? void 0 : _a.accept) == null ? void 0 : _b.backgroundColor) || (content == null ? void 0 : content.primary_color) || "#4f87ff",
765
848
  color: ((_d = (_c = settings == null ? void 0 : settings.button) == null ? void 0 : _c.accept) == null ? void 0 : _d.textColor) || "#ffffff"
766
849
  };
767
850
  const declineButtonStyle = {
@@ -771,18 +854,18 @@ var RedactoNoticeConsent = ({
771
854
  borderColor: (settings == null ? void 0 : settings.borderColor) || "#d0d5dd"
772
855
  };
773
856
  const linkStyle = {
774
- color: ((_i = settings == null ? void 0 : settings.link) == null ? void 0 : _i.color) || "#4f87ff"
857
+ color: (settings == null ? void 0 : settings.link) || (content == null ? void 0 : content.secondary_color) || "#4f87ff"
775
858
  };
776
859
  const languageSelectorStyle = {
777
860
  borderRadius: (settings == null ? void 0 : settings.borderRadius) || "8px",
778
861
  borderColor: (settings == null ? void 0 : settings.borderColor) || "#d0d5dd",
779
- backgroundColor: ((_k = (_j = settings == null ? void 0 : settings.button) == null ? void 0 : _j.language) == null ? void 0 : _k.backgroundColor) || "#ffffff",
780
- color: ((_m = (_l = settings == null ? void 0 : settings.button) == null ? void 0 : _l.language) == null ? void 0 : _m.textColor) || "#344054"
862
+ backgroundColor: ((_j = (_i = settings == null ? void 0 : settings.button) == null ? void 0 : _i.language) == null ? void 0 : _j.backgroundColor) || "#ffffff",
863
+ color: ((_l = (_k = settings == null ? void 0 : settings.button) == null ? void 0 : _k.language) == null ? void 0 : _l.textColor) || "#344054"
781
864
  };
782
865
  const selectedLanguageItemStyle = {
783
866
  ...languageSelectorStyle,
784
- backgroundColor: ((_o = (_n = settings == null ? void 0 : settings.button) == null ? void 0 : _n.language) == null ? void 0 : _o.selectedBackgroundColor) || "#f3f4f6",
785
- color: ((_q = (_p = settings == null ? void 0 : settings.button) == null ? void 0 : _p.language) == null ? void 0 : _q.selectedTextColor) || "#344054",
867
+ backgroundColor: ((_n = (_m = settings == null ? void 0 : settings.button) == null ? void 0 : _m.language) == null ? void 0 : _n.selectedBackgroundColor) || "#f3f4f6",
868
+ color: ((_p = (_o = settings == null ? void 0 : settings.button) == null ? void 0 : _o.language) == null ? void 0 : _p.selectedTextColor) || "#344054",
786
869
  fontWeight: 600
787
870
  };
788
871
  const headingStyle = {
@@ -794,11 +877,61 @@ var RedactoNoticeConsent = ({
794
877
  const sectionStyle = {
795
878
  backgroundColor: (settings == null ? void 0 : settings.backgroundColor) || "#ffffff"
796
879
  };
880
+ const handleCloseError = () => {
881
+ setErrorMessage(null);
882
+ };
883
+ (0, import_react2.useEffect)(() => {
884
+ const handleKeyDown = (event) => {
885
+ if (!modalRef.current) return;
886
+ const focusableElements = modalRef.current.querySelectorAll(
887
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
888
+ );
889
+ if (!focusableElements.length) return;
890
+ if (event.key === "Escape") {
891
+ handleDecline();
892
+ }
893
+ if (event.key === "Tab") {
894
+ const firstElement = focusableElements[0];
895
+ const lastElement = focusableElements[focusableElements.length - 1];
896
+ if (event.shiftKey) {
897
+ if (document.activeElement === firstElement) {
898
+ event.preventDefault();
899
+ lastElement.focus();
900
+ }
901
+ } else {
902
+ if (document.activeElement === lastElement) {
903
+ event.preventDefault();
904
+ firstElement.focus();
905
+ }
906
+ }
907
+ }
908
+ };
909
+ const modal = modalRef.current;
910
+ modal == null ? void 0 : modal.addEventListener("keydown", handleKeyDown);
911
+ if (modal && !isLoading) {
912
+ const focusableElements = modal.querySelectorAll(
913
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
914
+ );
915
+ const firstElement = focusableElements[0];
916
+ firstElement == null ? void 0 : firstElement.focus();
917
+ }
918
+ return () => {
919
+ modal == null ? void 0 : modal.removeEventListener("keydown", handleKeyDown);
920
+ };
921
+ }, [isLoading, handleDecline]);
797
922
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: hasAlreadyConsented ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
798
- blockUI && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.overlay, "aria-hidden": "true" }),
923
+ blockUI && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
924
+ "div",
925
+ {
926
+ style: styles.overlay,
927
+ "aria-hidden": "true",
928
+ role: "presentation"
929
+ }
930
+ ),
799
931
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
800
932
  "div",
801
933
  {
934
+ ref: modalRef,
802
935
  style: {
803
936
  ...styles.modal,
804
937
  ...responsiveStyles.modal,
@@ -807,10 +940,187 @@ var RedactoNoticeConsent = ({
807
940
  role: "dialog",
808
941
  "aria-modal": "true",
809
942
  "aria-labelledby": "privacy-notice-title",
810
- children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.loadingContainer, children: [
943
+ "aria-describedby": "privacy-notice-description",
944
+ tabIndex: -1,
945
+ children: isLoading || isRefreshingToken ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.loadingContainer, children: [
811
946
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.loadingSpinner }),
812
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { ...styles.privacyText, ...textStyle }, children: "Loading..." })
813
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...styles.content, ...responsiveStyles.content }, children: [
947
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { ...styles.privacyText, ...textStyle }, children: isRefreshingToken ? "Refreshing session..." : "Loading..." })
948
+ ] }) : fetchError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
949
+ "div",
950
+ {
951
+ style: {
952
+ ...styles.content,
953
+ ...responsiveStyles.content,
954
+ display: "flex",
955
+ flexDirection: "column",
956
+ alignItems: "center",
957
+ justifyContent: "center",
958
+ textAlign: "center",
959
+ padding: "40px 20px"
960
+ },
961
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
962
+ "div",
963
+ {
964
+ style: {
965
+ color: "#DC2626",
966
+ padding: responsiveStyles.errorDialog.padding,
967
+ borderRadius: "8px",
968
+ marginBottom: responsiveStyles.errorDialog.marginBottom,
969
+ width: "100%",
970
+ maxWidth: responsiveStyles.errorDialog.maxWidth,
971
+ position: "relative"
972
+ },
973
+ children: [
974
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
975
+ "button",
976
+ {
977
+ onClick: handleDecline,
978
+ style: {
979
+ position: "absolute",
980
+ top: responsiveStyles.closeButton.top,
981
+ right: responsiveStyles.closeButton.right,
982
+ background: "none",
983
+ border: "none",
984
+ color: "#DC2626",
985
+ cursor: "pointer",
986
+ padding: responsiveStyles.closeButton.padding,
987
+ display: "flex",
988
+ alignItems: "center",
989
+ justifyContent: "center"
990
+ },
991
+ "aria-label": "Close error message",
992
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
993
+ "svg",
994
+ {
995
+ width: isMobile ? "14" : "16",
996
+ height: isMobile ? "14" : "16",
997
+ viewBox: "0 0 16 16",
998
+ fill: "none",
999
+ xmlns: "http://www.w3.org/2000/svg",
1000
+ "aria-hidden": "true",
1001
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1002
+ "path",
1003
+ {
1004
+ d: "M12 4L4 12M4 4L12 12",
1005
+ stroke: "currentColor",
1006
+ strokeWidth: "2",
1007
+ strokeLinecap: "round",
1008
+ strokeLinejoin: "round"
1009
+ }
1010
+ )
1011
+ }
1012
+ )
1013
+ }
1014
+ ),
1015
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1016
+ "h3",
1017
+ {
1018
+ style: {
1019
+ margin: responsiveStyles.errorTitle.margin,
1020
+ fontSize: responsiveStyles.errorTitle.fontSize,
1021
+ fontWeight: "600"
1022
+ },
1023
+ children: "Error Loading Consent Notice"
1024
+ }
1025
+ ),
1026
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1027
+ "p",
1028
+ {
1029
+ style: {
1030
+ margin: responsiveStyles.errorMessage.margin,
1031
+ fontSize: responsiveStyles.errorMessage.fontSize,
1032
+ lineHeight: "1.5"
1033
+ },
1034
+ children: fetchError.message || "Failed to load consent notice. Please try again."
1035
+ }
1036
+ ),
1037
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1038
+ "button",
1039
+ {
1040
+ onClick: fetchNotice,
1041
+ style: {
1042
+ backgroundColor: "#DC2626",
1043
+ color: "#FFFFFF",
1044
+ border: "none",
1045
+ padding: responsiveStyles.errorButton.padding,
1046
+ borderRadius: "6px",
1047
+ cursor: "pointer",
1048
+ fontSize: responsiveStyles.errorButton.fontSize,
1049
+ fontWeight: "500",
1050
+ transition: "background-color 0.2s"
1051
+ },
1052
+ onMouseOver: (e) => e.currentTarget.style.backgroundColor = "#B91C1C",
1053
+ onMouseOut: (e) => e.currentTarget.style.backgroundColor = "#DC2626",
1054
+ children: "Refresh"
1055
+ }
1056
+ )
1057
+ ]
1058
+ }
1059
+ )
1060
+ }
1061
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...styles.content, ...responsiveStyles.content }, children: [
1062
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1063
+ "div",
1064
+ {
1065
+ role: "alert",
1066
+ style: {
1067
+ backgroundColor: "#FEE2E2",
1068
+ color: "#DC2626",
1069
+ padding: "12px",
1070
+ borderRadius: "6px",
1071
+ marginBottom: "16px",
1072
+ fontSize: "14px",
1073
+ border: "1px solid #FCA5A5",
1074
+ position: "relative",
1075
+ display: "flex",
1076
+ alignItems: "center",
1077
+ justifyContent: "space-between"
1078
+ },
1079
+ children: [
1080
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: errorMessage }),
1081
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1082
+ "button",
1083
+ {
1084
+ type: "button",
1085
+ onClick: handleCloseError,
1086
+ style: {
1087
+ background: "none",
1088
+ border: "none",
1089
+ color: "#DC2626",
1090
+ cursor: "pointer",
1091
+ padding: "4px",
1092
+ marginLeft: "8px",
1093
+ display: "flex",
1094
+ alignItems: "center",
1095
+ justifyContent: "center"
1096
+ },
1097
+ "aria-label": "Close error message",
1098
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1099
+ "svg",
1100
+ {
1101
+ width: "16",
1102
+ height: "16",
1103
+ viewBox: "0 0 16 16",
1104
+ fill: "none",
1105
+ xmlns: "http://www.w3.org/2000/svg",
1106
+ "aria-hidden": "true",
1107
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1108
+ "path",
1109
+ {
1110
+ d: "M12 4L4 12M4 4L12 12",
1111
+ stroke: "currentColor",
1112
+ strokeWidth: "2",
1113
+ strokeLinecap: "round",
1114
+ strokeLinejoin: "round"
1115
+ }
1116
+ )
1117
+ }
1118
+ )
1119
+ }
1120
+ )
1121
+ ]
1122
+ }
1123
+ ),
814
1124
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...styles.topSection, ...sectionStyle }, children: [
815
1125
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.topLeft, children: [
816
1126
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -818,7 +1128,7 @@ var RedactoNoticeConsent = ({
818
1128
  {
819
1129
  style: styles.logo,
820
1130
  src: (content == null ? void 0 : content.logo_url) || redacto_logo_default,
821
- alt: "logo"
1131
+ alt: "Redacto Logo"
822
1132
  }
823
1133
  ),
824
1134
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -838,6 +1148,7 @@ var RedactoNoticeConsent = ({
838
1148
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
839
1149
  "button",
840
1150
  {
1151
+ ref: firstFocusableRef,
841
1152
  style: {
842
1153
  ...styles.topRight,
843
1154
  ...responsiveStyles.topRight,
@@ -846,6 +1157,7 @@ var RedactoNoticeConsent = ({
846
1157
  onClick: toggleLanguageDropdown,
847
1158
  "aria-expanded": isLanguageDropdownOpen,
848
1159
  "aria-haspopup": "listbox",
1160
+ "aria-controls": "language-listbox",
849
1161
  children: [
850
1162
  selectedLanguage,
851
1163
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -856,11 +1168,12 @@ var RedactoNoticeConsent = ({
856
1168
  height: "16",
857
1169
  viewBox: "0 0 16 16",
858
1170
  fill: "none",
859
- stroke: ((_s = (_r = settings == null ? void 0 : settings.button) == null ? void 0 : _r.language) == null ? void 0 : _s.textColor) || "currentColor",
1171
+ stroke: ((_r = (_q = settings == null ? void 0 : settings.button) == null ? void 0 : _q.language) == null ? void 0 : _r.textColor) || "currentColor",
860
1172
  strokeWidth: "2",
861
1173
  strokeLinecap: "round",
862
1174
  strokeLinejoin: "round",
863
1175
  style: { flexShrink: 0, marginLeft: "4px" },
1176
+ "aria-hidden": "true",
864
1177
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 6l4 4 4-4" })
865
1178
  }
866
1179
  )
@@ -870,6 +1183,7 @@ var RedactoNoticeConsent = ({
870
1183
  isLanguageDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
871
1184
  "ul",
872
1185
  {
1186
+ id: "language-listbox",
873
1187
  style: {
874
1188
  ...styles.languageDropdown,
875
1189
  ...languageSelectorStyle
@@ -900,6 +1214,7 @@ var RedactoNoticeConsent = ({
900
1214
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
901
1215
  "div",
902
1216
  {
1217
+ id: "privacy-notice-description",
903
1218
  style: {
904
1219
  ...styles.middleSection,
905
1220
  ...responsiveStyles.middleSection,
@@ -926,6 +1241,7 @@ var RedactoNoticeConsent = ({
926
1241
  href: (content == null ? void 0 : content.privacy_policy_url) || "#",
927
1242
  target: "_blank",
928
1243
  rel: "noopener noreferrer",
1244
+ "aria-label": "Privacy Policy (opens in new tab)",
929
1245
  children: [
930
1246
  "[",
931
1247
  getTranslatedText(
@@ -944,7 +1260,9 @@ var RedactoNoticeConsent = ({
944
1260
  {
945
1261
  style: { ...styles.link, ...linkStyle },
946
1262
  href: (content == null ? void 0 : content.sub_processors_url) || "#",
947
- target: "",
1263
+ target: "_blank",
1264
+ rel: "noopener noreferrer",
1265
+ "aria-label": "Vendors List (opens in new tab)",
948
1266
  children: [
949
1267
  "[",
950
1268
  getTranslatedText(
@@ -973,13 +1291,23 @@ var RedactoNoticeConsent = ({
973
1291
  )
974
1292
  }
975
1293
  ),
976
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.optionsContainer, children: (_t = content == null ? void 0 : content.purposes) == null ? void 0 : _t.map((purpose) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1294
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.optionsContainer, children: (_s = content == null ? void 0 : content.purposes) == null ? void 0 : _s.map((purpose) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
977
1295
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.optionItem, children: [
978
1296
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
979
1297
  "div",
980
1298
  {
981
1299
  style: styles.optionLeft,
982
1300
  onClick: () => togglePurposeCollapse(purpose.uuid),
1301
+ role: "button",
1302
+ tabIndex: 0,
1303
+ "aria-expanded": !collapsedPurposes[purpose.uuid],
1304
+ "aria-controls": `purpose-${purpose.uuid}`,
1305
+ onKeyDown: (e) => {
1306
+ if (e.key === "Enter" || e.key === " ") {
1307
+ e.preventDefault();
1308
+ togglePurposeCollapse(purpose.uuid);
1309
+ }
1310
+ },
983
1311
  children: [
984
1312
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
985
1313
  "div",
@@ -1006,6 +1334,7 @@ var RedactoNoticeConsent = ({
1006
1334
  transform: !collapsedPurposes[purpose.uuid] ? "rotate(90deg)" : "rotate(0deg)",
1007
1335
  transition: "transform 0.3s ease"
1008
1336
  },
1337
+ "aria-hidden": "true",
1009
1338
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M1 1L6 6L1 11" })
1010
1339
  }
1011
1340
  )
@@ -1052,58 +1381,76 @@ var RedactoNoticeConsent = ({
1052
1381
  style: styles.checkboxLarge,
1053
1382
  type: "checkbox",
1054
1383
  checked: selectedPurposes[purpose.uuid] || false,
1055
- onChange: () => handlePurposeCheckboxChange(purpose.uuid)
1384
+ onChange: () => handlePurposeCheckboxChange(purpose.uuid),
1385
+ "aria-label": `Select all data elements for ${getTranslatedText(
1386
+ `purposes.name`,
1387
+ purpose.name,
1388
+ purpose.uuid
1389
+ )}`
1056
1390
  }
1057
1391
  )
1058
1392
  ] }),
1059
- !collapsedPurposes[purpose.uuid] && purpose.data_elements && purpose.data_elements.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.dataElementsContainer, children: purpose.data_elements.map((dataElement) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1393
+ !collapsedPurposes[purpose.uuid] && purpose.data_elements && purpose.data_elements.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1060
1394
  "div",
1061
1395
  {
1062
- style: styles.dataElementItem,
1063
- children: [
1064
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1065
- "span",
1066
- {
1067
- style: {
1068
- ...styles.dataElementText,
1069
- ...responsiveStyles.dataElementText,
1070
- ...textStyle
1071
- },
1072
- children: [
1073
- getTranslatedText(
1074
- `data_elements.name`,
1075
- dataElement.name,
1076
- dataElement.uuid
1077
- ),
1078
- dataElement.required && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1079
- "span",
1080
- {
1081
- style: {
1082
- color: "red",
1083
- marginLeft: "4px"
1084
- },
1085
- children: "*"
1086
- }
1087
- )
1088
- ]
1089
- }
1090
- ),
1091
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1092
- "input",
1093
- {
1094
- style: styles.checkboxSmall,
1095
- type: "checkbox",
1096
- checked: selectedDataElements[`${purpose.uuid}-${dataElement.uuid}`] || false,
1097
- onChange: () => handleDataElementCheckboxChange(
1098
- dataElement.uuid,
1099
- purpose.uuid
1396
+ id: `purpose-${purpose.uuid}`,
1397
+ style: styles.dataElementsContainer,
1398
+ children: purpose.data_elements.map((dataElement) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1399
+ "div",
1400
+ {
1401
+ style: styles.dataElementItem,
1402
+ children: [
1403
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1404
+ "span",
1405
+ {
1406
+ style: {
1407
+ ...styles.dataElementText,
1408
+ ...responsiveStyles.dataElementText,
1409
+ ...textStyle
1410
+ },
1411
+ children: [
1412
+ getTranslatedText(
1413
+ `data_elements.name`,
1414
+ dataElement.name,
1415
+ dataElement.uuid
1416
+ ),
1417
+ dataElement.required && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1418
+ "span",
1419
+ {
1420
+ style: {
1421
+ color: "red",
1422
+ marginLeft: "4px"
1423
+ },
1424
+ "aria-label": "required",
1425
+ children: "*"
1426
+ }
1427
+ )
1428
+ ]
1429
+ }
1430
+ ),
1431
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1432
+ "input",
1433
+ {
1434
+ style: styles.checkboxSmall,
1435
+ type: "checkbox",
1436
+ checked: selectedDataElements[`${purpose.uuid}-${dataElement.uuid}`] || false,
1437
+ onChange: () => handleDataElementCheckboxChange(
1438
+ dataElement.uuid,
1439
+ purpose.uuid
1440
+ ),
1441
+ "aria-label": `Select ${getTranslatedText(
1442
+ `data_elements.name`,
1443
+ dataElement.name,
1444
+ dataElement.uuid
1445
+ )}${dataElement.required ? " (required)" : ""}`
1446
+ }
1100
1447
  )
1101
- }
1102
- )
1103
- ]
1104
- },
1105
- dataElement.uuid
1106
- )) })
1448
+ ]
1449
+ },
1450
+ dataElement.uuid
1451
+ ))
1452
+ }
1453
+ )
1107
1454
  ] }, purpose.uuid)) })
1108
1455
  ]
1109
1456
  }
@@ -1120,6 +1467,7 @@ var RedactoNoticeConsent = ({
1120
1467
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1121
1468
  "button",
1122
1469
  {
1470
+ ref: lastFocusableRef,
1123
1471
  style: {
1124
1472
  ...styles.button,
1125
1473
  ...responsiveStyles.button,
@@ -1129,6 +1477,10 @@ var RedactoNoticeConsent = ({
1129
1477
  },
1130
1478
  onClick: handleAccept,
1131
1479
  disabled: acceptDisabled,
1480
+ "aria-label": getTranslatedText(
1481
+ "confirm_button_text",
1482
+ (content == null ? void 0 : content.confirm_button_text) || "Accept"
1483
+ ),
1132
1484
  children: isSubmitting ? "Processing..." : getTranslatedText(
1133
1485
  "confirm_button_text",
1134
1486
  (content == null ? void 0 : content.confirm_button_text) || "Accept"
@@ -1146,6 +1498,10 @@ var RedactoNoticeConsent = ({
1146
1498
  },
1147
1499
  onClick: handleDecline,
1148
1500
  disabled: isSubmitting,
1501
+ "aria-label": getTranslatedText(
1502
+ "decline_button_text",
1503
+ (content == null ? void 0 : content.decline_button_text) || "Decline"
1504
+ ),
1149
1505
  children: isSubmitting ? "Processing..." : getTranslatedText(
1150
1506
  "decline_button_text",
1151
1507
  (content == null ? void 0 : content.decline_button_text) || "Decline"