@redacto.io/consent-sdk-react 5.1.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.d.mts +24 -1
  3. package/dist/index.d.ts +24 -1
  4. package/dist/index.js +149 -206
  5. package/dist/index.mjs +148 -206
  6. package/dist/privacy-center.d.mts +81 -2
  7. package/dist/privacy-center.d.ts +81 -2
  8. package/dist/privacy-center.js +2823 -1272
  9. package/dist/privacy-center.mjs +2813 -1263
  10. package/package.json +1 -1
  11. package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +16 -20
  12. package/src/RedactoNoticeConsent/api/index.ts +21 -103
  13. package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +5 -4
  14. package/src/RedactoNoticeConsentInline/api/index.ts +64 -117
  15. package/src/RedactoPrivacyCenter/NotificationsPage.tsx +174 -0
  16. package/src/RedactoPrivacyCenter/PrivacyCenterHomePage.tsx +3 -0
  17. package/src/RedactoPrivacyCenter/api/actions.ts +84 -0
  18. package/src/RedactoPrivacyCenter/api/client.ts +118 -0
  19. package/src/RedactoPrivacyCenter/components/DataRequest/PurposeSelectionSection.tsx +15 -0
  20. package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationBell.tsx +160 -0
  21. package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationCTAButton.tsx +18 -0
  22. package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationDropdown.tsx +54 -0
  23. package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationDropdownItem.tsx +57 -0
  24. package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationIcon.tsx +19 -0
  25. package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationListPanel.tsx +92 -0
  26. package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationRefreshButton.tsx +20 -0
  27. package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationRow.tsx +58 -0
  28. package/src/RedactoPrivacyCenter/components/NotificationHub/StatCard.tsx +10 -0
  29. package/src/RedactoPrivacyCenter/components/NotificationHub/useNotificationActions.ts +112 -0
  30. package/src/RedactoPrivacyCenter/components/NotificationHub/utils.ts +27 -0
  31. package/src/RedactoPrivacyCenter/components/PrivacyCenterLayout.tsx +3 -2
  32. package/src/RedactoPrivacyCenter/context/NavigationContext.tsx +2 -2
  33. package/src/RedactoPrivacyCenter/lib/api.ts +77 -0
  34. package/src/RedactoPrivacyCenter/lib/constants.ts +78 -1
  35. package/src/RedactoPrivacyCenter/lib/types.ts +148 -0
  36. package/src/RedactoPrivacyCenter/lib/utils.ts +3 -0
  37. package/src/RedactoPrivacyCenter/locales/en/translation.json +27 -1
  38. package/src/RedactoPrivacyCenter/styles/injectStyles.ts +505 -0
  39. package/src/RedactoPrivacyCenter/ui/PCPopover.tsx +23 -1
  40. package/src/index.ts +5 -0
  41. package/src/privacy-center.ts +1 -0
  42. package/src/shared/api-errors.ts +171 -0
package/dist/index.mjs CHANGED
@@ -3,6 +3,64 @@ import { useCallback, useEffect as useEffect2, useMemo, useRef, useState as useS
3
3
 
4
4
  // src/RedactoNoticeConsent/api/index.ts
5
5
  import { jwtDecode } from "jwt-decode";
6
+
7
+ // src/shared/api-errors.ts
8
+ var ApiError = class extends Error {
9
+ constructor(opts) {
10
+ super(opts.message);
11
+ this.name = "ApiError";
12
+ this.status = opts.status;
13
+ this.code = opts.code;
14
+ }
15
+ };
16
+ function statusFallback(status) {
17
+ if (status === 401) {
18
+ return "Your session has expired. Please request a new access link.";
19
+ }
20
+ if (status === 403) {
21
+ return "You do not have access to this resource.";
22
+ }
23
+ if (status >= 500) {
24
+ return "Something went wrong on our end. Please try again later.";
25
+ }
26
+ return void 0;
27
+ }
28
+ function extractFromDetail(detail) {
29
+ var _a;
30
+ if (typeof detail === "string") {
31
+ return { message: detail };
32
+ }
33
+ if (Array.isArray(detail)) {
34
+ return {};
35
+ }
36
+ if (detail && typeof detail === "object") {
37
+ const obj = detail;
38
+ return { message: (_a = obj.message) != null ? _a : obj.detail, code: obj.error_code };
39
+ }
40
+ return {};
41
+ }
42
+ async function parseApiError(response, fallbackMessage) {
43
+ var _a, _b, _c, _d;
44
+ let body;
45
+ let parsedBody = false;
46
+ try {
47
+ body = await response.json();
48
+ parsedBody = true;
49
+ } catch {
50
+ body = void 0;
51
+ }
52
+ const fromDetail = extractFromDetail(body == null ? void 0 : body.detail);
53
+ const serverMessage = (_a = body == null ? void 0 : body.message) != null ? _a : fromDetail.message;
54
+ const message = (_b = serverMessage != null ? serverMessage : parsedBody ? statusFallback(response.status) : void 0) != null ? _b : fallbackMessage;
55
+ const code = (_d = (_c = body == null ? void 0 : body.error_code) != null ? _c : fromDetail.code) != null ? _d : void 0;
56
+ return new ApiError({
57
+ status: response.status,
58
+ code,
59
+ message
60
+ });
61
+ }
62
+
63
+ // src/RedactoNoticeConsent/api/index.ts
6
64
  var BASE_URL = "https://api.redacto.io/consent";
7
65
  var apiCache = /* @__PURE__ */ new Map();
8
66
  var CACHE_TTL = 5 * 60 * 1e3;
@@ -78,21 +136,10 @@ var fetchConsentContent = async ({
78
136
  signal
79
137
  });
80
138
  if (!response.ok) {
81
- let errorMessage = `Failed to fetch consent content: ${response.status} ${response.statusText}`;
82
- if (response.status === 401) {
83
- errorMessage = "Unauthorized: Invalid or expired token";
84
- } else if (response.status === 403) {
85
- errorMessage = "Forbidden: Access denied";
86
- } else if (response.status === 404) {
87
- errorMessage = "Notice not found";
88
- } else if (response.status === 409) {
89
- errorMessage = "User has already provided consent";
90
- } else if (response.status >= 500) {
91
- errorMessage = "Server error: Please try again later";
92
- }
93
- const error = new Error(errorMessage);
94
- error.status = response.status;
95
- throw error;
139
+ throw await parseApiError(
140
+ response,
141
+ "Could not load the consent notice. Please try again."
142
+ );
96
143
  }
97
144
  const data = await response.json();
98
145
  if (validate_against === "all" && !specific_uuid) {
@@ -162,26 +209,10 @@ var submitConsentEvent = async ({
162
209
  }
163
210
  );
164
211
  if (!response.ok) {
165
- let errorMessage = `Failed to submit consent: ${response.status} ${response.statusText}`;
166
- if (response.status === 400) {
167
- try {
168
- const errorData = await response.json();
169
- errorMessage = errorData.message || "Invalid request data";
170
- } catch {
171
- errorMessage = "Invalid request data";
172
- }
173
- } else if (response.status === 401) {
174
- errorMessage = "Unauthorized: Invalid or expired token";
175
- } else if (response.status === 403) {
176
- errorMessage = "Forbidden: Access denied";
177
- } else if (response.status === 404) {
178
- errorMessage = "Notice not found";
179
- } else if (response.status >= 500) {
180
- errorMessage = "Server error: Please try again later";
181
- }
182
- const error = new Error(errorMessage);
183
- error.status = response.status;
184
- throw error;
212
+ throw await parseApiError(
213
+ response,
214
+ "Could not submit your consent. Please try again."
215
+ );
185
216
  }
186
217
  apiCache.clear();
187
218
  };
@@ -214,19 +245,10 @@ var fetchTTSAudioUrls = async ({
214
245
  signal
215
246
  });
216
247
  if (!response.ok) {
217
- let errorMessage = `Failed to fetch TTS audio URLs: ${response.status} ${response.statusText}`;
218
- if (response.status === 401) {
219
- errorMessage = "Unauthorized: Invalid or expired token";
220
- } else if (response.status === 403) {
221
- errorMessage = "Forbidden: Access denied";
222
- } else if (response.status === 404) {
223
- errorMessage = "Notice or audio not found";
224
- } else if (response.status >= 500) {
225
- errorMessage = "Server error: Please try again later";
226
- }
227
- const error = new Error(errorMessage);
228
- error.status = response.status;
229
- throw error;
248
+ throw await parseApiError(
249
+ response,
250
+ "Could not load audio narration. Please try again."
251
+ );
230
252
  }
231
253
  const data = await response.json();
232
254
  return data;
@@ -288,31 +310,10 @@ var initiateGuardianVerification = async ({
288
310
  }
289
311
  );
290
312
  if (!response.ok) {
291
- let errorMessage = `Failed to initiate verification: ${response.status} ${response.statusText}`;
292
- if (response.status === 400) {
293
- try {
294
- const errorData = await response.json();
295
- errorMessage = errorData.message || "Invalid request data";
296
- } catch {
297
- errorMessage = "Invalid request data";
298
- }
299
- } else if (response.status === 401) {
300
- errorMessage = "Unauthorized: Invalid or expired token";
301
- } else if (response.status === 404) {
302
- errorMessage = "Organization or workspace not found";
303
- } else if (response.status === 422) {
304
- try {
305
- const errorData = await response.json();
306
- errorMessage = errorData.message || "Validation error: Please check your input";
307
- } catch {
308
- errorMessage = "Validation error: Please check your input";
309
- }
310
- } else if (response.status >= 500) {
311
- errorMessage = "Server error: Please try again later";
312
- }
313
- const error = new Error(errorMessage);
314
- error.status = response.status;
315
- throw error;
313
+ throw await parseApiError(
314
+ response,
315
+ "Could not start guardian verification. Please try again."
316
+ );
316
317
  }
317
318
  const responseData = await response.json();
318
319
  const detail = responseData.detail || responseData;
@@ -346,7 +347,7 @@ var verifyGuardianStatus = async ({
346
347
  sessionToken,
347
348
  signal
348
349
  }) => {
349
- var _a, _b, _c, _d, _e, _f, _g, _h;
350
+ var _a, _b, _c, _d, _e, _f, _g;
350
351
  if (!accessToken || !sessionToken) {
351
352
  throw new Error("accessToken and sessionToken are required");
352
353
  }
@@ -374,37 +375,21 @@ var verifyGuardianStatus = async ({
374
375
  }
375
376
  );
376
377
  if (!response.ok) {
377
- let errorMessage = `Failed to check verification status: ${response.status} ${response.statusText}`;
378
- if (response.status === 400) {
379
- try {
380
- const errorData = await response.json();
381
- errorMessage = errorData.message || ((_a = errorData.detail) == null ? void 0 : _a.message) || "Invalid session token";
382
- } catch {
383
- errorMessage = "Invalid session token";
384
- }
385
- } else if (response.status === 401) {
386
- errorMessage = "Unauthorized: Invalid or expired token";
387
- } else if (response.status === 404) {
388
- errorMessage = "Verification session not found or expired. Please restart the verification process.";
389
- } else if (response.status === 410) {
390
- errorMessage = "Verification session has expired. Please restart the verification process.";
391
- } else if (response.status >= 500) {
392
- errorMessage = "Server error: Please try again later";
393
- }
394
- const error = new Error(errorMessage);
395
- error.status = response.status;
396
- throw error;
378
+ throw await parseApiError(
379
+ response,
380
+ "Could not check verification status. Please try again."
381
+ );
397
382
  }
398
383
  const responseData = await response.json();
399
384
  const detail = responseData.detail || responseData;
400
385
  return {
401
- status: (_b = detail.status) != null ? _b : "in_progress",
402
- guardian_info_uuid: (_c = detail.guardian_info_uuid) != null ? _c : null,
403
- verification_reference: (_d = detail.verification_reference) != null ? _d : null,
404
- guardian_details: (_e = detail.guardian_details) != null ? _e : null,
405
- error: (_f = detail.error) != null ? _f : null,
406
- error_code: (_g = detail.error_code) != null ? _g : null,
407
- can_retry: (_h = detail.can_retry) != null ? _h : true
386
+ status: (_a = detail.status) != null ? _a : "in_progress",
387
+ guardian_info_uuid: (_b = detail.guardian_info_uuid) != null ? _b : null,
388
+ verification_reference: (_c = detail.verification_reference) != null ? _c : null,
389
+ guardian_details: (_d = detail.guardian_details) != null ? _d : null,
390
+ error: (_e = detail.error) != null ? _e : null,
391
+ error_code: (_f = detail.error_code) != null ? _f : null,
392
+ can_retry: (_g = detail.can_retry) != null ? _g : true
408
393
  };
409
394
  };
410
395
 
@@ -2901,7 +2886,7 @@ var RedactoNoticeConsent = ({
2901
2886
  return;
2902
2887
  }
2903
2888
  const err = error;
2904
- 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.";
2889
+ const message = err.message || "Failed to submit consent. Please try again.";
2905
2890
  setErrorMessage(message);
2906
2891
  onError == null ? void 0 : onError(error);
2907
2892
  } finally {
@@ -3323,20 +3308,12 @@ var RedactoNoticeConsent = ({
3323
3308
  }, []);
3324
3309
  const availableLanguages = useMemo(() => {
3325
3310
  if (!content) return [language];
3326
- const languages = ["English"];
3311
+ const pinned = ["English"];
3327
3312
  if (content.default_language && content.default_language !== "English" && content.default_language !== "en") {
3328
- languages.push(content.default_language);
3313
+ pinned.push(content.default_language);
3329
3314
  }
3330
- if (content.supported_languages_and_translations) {
3331
- Object.keys(content.supported_languages_and_translations).forEach(
3332
- (lang) => {
3333
- if (!languages.includes(lang)) {
3334
- languages.push(lang);
3335
- }
3336
- }
3337
- );
3338
- }
3339
- return languages;
3315
+ const rest = content.supported_languages_and_translations ? Object.keys(content.supported_languages_and_translations).filter((lang) => !pinned.includes(lang)).sort((a, b) => a.localeCompare(b, "en")) : [];
3316
+ return [...pinned, ...rest];
3340
3317
  }, [content, language]);
3341
3318
  const getLanguageCode = useCallback(
3342
3319
  (displayLanguage) => {
@@ -4581,40 +4558,27 @@ var fetchConsentContent2 = async ({
4581
4558
  baseUrl,
4582
4559
  specific_uuid
4583
4560
  }) => {
4584
- try {
4585
- const apiBaseUrl = baseUrl || BASE_URL2;
4586
- const url = new URL(
4587
- `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/notices/get-notice/${notice_uuid}`
4588
- );
4589
- if (specific_uuid) {
4590
- url.searchParams.append("specific_uuid", specific_uuid);
4591
- }
4592
- const response = await fetch(url.toString(), {
4593
- method: "GET",
4594
- headers: {
4595
- "Content-Type": "application/json"
4596
- }
4597
- });
4598
- if (response.status === 401) {
4599
- const error = new Error("Unauthorized");
4600
- error.status = 401;
4601
- throw error;
4602
- }
4603
- if (response.status === 409) {
4604
- const error = new Error("User has already provided consent");
4605
- error.status = 409;
4606
- throw error;
4607
- }
4608
- if (!response.ok) {
4609
- throw new Error(
4610
- `Failed to fetch consent content: ${response.statusText}`
4611
- );
4561
+ const apiBaseUrl = baseUrl || BASE_URL2;
4562
+ const url = new URL(
4563
+ `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/notices/get-notice/${notice_uuid}`
4564
+ );
4565
+ if (specific_uuid) {
4566
+ url.searchParams.append("specific_uuid", specific_uuid);
4567
+ }
4568
+ const response = await fetch(url.toString(), {
4569
+ method: "GET",
4570
+ headers: {
4571
+ "Content-Type": "application/json"
4612
4572
  }
4613
- const data = await response.json();
4614
- return data;
4615
- } catch (error) {
4616
- throw error;
4573
+ });
4574
+ if (!response.ok) {
4575
+ throw await parseApiError(
4576
+ response,
4577
+ "Could not load the consent notice. Please try again."
4578
+ );
4617
4579
  }
4580
+ const data = await response.json();
4581
+ return data;
4618
4582
  };
4619
4583
  var submitConsentEvent2 = async ({
4620
4584
  org_uuid,
@@ -4626,67 +4590,44 @@ var submitConsentEvent2 = async ({
4626
4590
  declined,
4627
4591
  meta_data
4628
4592
  }) => {
4629
- var _a, _b;
4630
- try {
4631
- const apiBaseUrl = baseUrl || BASE_URL2;
4632
- const payload = {
4633
- notice_uuid: noticeUuid,
4634
- purposes: purposes.map((purpose) => {
4635
- if (!purpose.uuid) {
4636
- throw new Error(`Invalid purpose data: missing uuid`);
4637
- }
4638
- const dataElements = purpose.data_elements.filter((element) => element.enabled).map((element) => ({
4639
- uuid: element.uuid,
4640
- selected: element.required ? true : Boolean(element.selected)
4641
- }));
4642
- return {
4643
- purpose_uuid: purpose.uuid,
4644
- selected: Boolean(purpose.selected),
4645
- data_elements: dataElements.length > 0 ? dataElements : void 0
4646
- };
4647
- }),
4648
- select_all_mandatory: false,
4649
- source: "WEB",
4650
- declined,
4651
- meta_data
4652
- };
4653
- const response = await fetch(
4654
- `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/submit-consent`,
4655
- {
4656
- method: "POST",
4657
- headers: {
4658
- Authorization: `Bearer ${accessToken}`,
4659
- "Content-Type": "application/json"
4660
- },
4661
- body: JSON.stringify(payload)
4662
- }
4663
- );
4664
- if (!response.ok) {
4665
- let errorData;
4666
- try {
4667
- errorData = await response.json();
4668
- } catch {
4669
- errorData = { message: response.statusText };
4670
- }
4671
- if (response.status === 409) {
4672
- const error2 = new Error(
4673
- ((_a = errorData.detail) == null ? void 0 : _a.message) || errorData.message || "User has already provided consent"
4674
- );
4675
- error2.status = 409;
4676
- error2.code = errorData.code || 409;
4677
- error2.detail = errorData.detail;
4678
- throw error2;
4593
+ const apiBaseUrl = baseUrl || BASE_URL2;
4594
+ const payload = {
4595
+ notice_uuid: noticeUuid,
4596
+ purposes: purposes.map((purpose) => {
4597
+ if (!purpose.uuid) {
4598
+ throw new Error(`Invalid purpose data: missing uuid`);
4679
4599
  }
4680
- const error = new Error(
4681
- ((_b = errorData.detail) == null ? void 0 : _b.message) || errorData.message || `Failed to submit consent event: ${response.statusText}`
4682
- );
4683
- error.status = response.status;
4684
- error.code = errorData.code;
4685
- error.detail = errorData.detail;
4686
- throw error;
4600
+ const dataElements = purpose.data_elements.filter((element) => element.enabled).map((element) => ({
4601
+ uuid: element.uuid,
4602
+ selected: element.required ? true : Boolean(element.selected)
4603
+ }));
4604
+ return {
4605
+ purpose_uuid: purpose.uuid,
4606
+ selected: Boolean(purpose.selected),
4607
+ data_elements: dataElements.length > 0 ? dataElements : void 0
4608
+ };
4609
+ }),
4610
+ select_all_mandatory: false,
4611
+ source: "WEB",
4612
+ declined,
4613
+ meta_data
4614
+ };
4615
+ const response = await fetch(
4616
+ `${apiBaseUrl}/public/organisations/${org_uuid}/workspaces/${workspace_uuid}/submit-consent`,
4617
+ {
4618
+ method: "POST",
4619
+ headers: {
4620
+ Authorization: `Bearer ${accessToken}`,
4621
+ "Content-Type": "application/json"
4622
+ },
4623
+ body: JSON.stringify(payload)
4687
4624
  }
4688
- } catch (error) {
4689
- throw error;
4625
+ );
4626
+ if (!response.ok) {
4627
+ throw await parseApiError(
4628
+ response,
4629
+ "Could not submit your consent. Please try again."
4630
+ );
4690
4631
  }
4691
4632
  };
4692
4633
 
@@ -5359,7 +5300,7 @@ var RedactoConsentInlineComponent = ({
5359
5300
  hasSubmittedRef.current = false;
5360
5301
  } catch (error) {
5361
5302
  const err = error;
5362
- 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.";
5303
+ const message = err.message || "Failed to submit consent. Please try again.";
5363
5304
  setErrorMessage(message);
5364
5305
  hasSubmittedRef.current = false;
5365
5306
  throw error;
@@ -6072,6 +6013,7 @@ var DigiLockerCallback = ({
6072
6013
  ] });
6073
6014
  };
6074
6015
  export {
6016
+ ApiError,
6075
6017
  DigiLockerCallback,
6076
6018
  RedactoNoticeConsent,
6077
6019
  RedactoConsentInline as RedactoNoticeConsentInline
@@ -102,6 +102,30 @@ declare function createConsentClient(baseUrl: string): {
102
102
  * Get document info/download URL for a case document (privacy center)
103
103
  */
104
104
  getCaseDocument(baseRequest: BaseRequest, caseUuid: string, documentUuid: string, authToken?: string): Promise<MessageDocument>;
105
+ /**
106
+ * List notifications (paginated, with filters)
107
+ */
108
+ getNotifications(baseRequest: BaseRequest, params?: NotificationQueryParams, authToken?: string): Promise<NotificationListResponse>;
109
+ /**
110
+ * Get notification summary (aggregated counts only)
111
+ */
112
+ getNotificationSummary(baseRequest: BaseRequest, authToken?: string): Promise<NotificationSummary>;
113
+ /**
114
+ * Get unread notification count (lightweight, for badge)
115
+ */
116
+ getUnreadCount(baseRequest: BaseRequest, authToken?: string): Promise<UnreadCountResponse>;
117
+ /**
118
+ * Mark a single notification as read
119
+ */
120
+ markNotificationRead(baseRequest: BaseRequest, notificationUuid: string, authToken?: string): Promise<NotificationActionResponse>;
121
+ /**
122
+ * Mark all notifications as read
123
+ */
124
+ markAllNotificationsRead(baseRequest: BaseRequest, authToken?: string): Promise<NotificationActionResponse>;
125
+ /**
126
+ * Acknowledge a notification (sets is_read and is_acknowledged to true)
127
+ */
128
+ acknowledgeNotification(baseRequest: BaseRequest, notificationUuid: string, authToken?: string): Promise<NotificationActionResponse>;
105
129
  };
106
130
 
107
131
  type Workspace = {
@@ -440,8 +464,61 @@ type UploadDocumentResponse = {
440
464
  allow_ai_processing: boolean;
441
465
  metadata: Record<string, string> | null;
442
466
  };
467
+ type NotificationType = 'guardian_verification_request' | 'consent_expiry_warning' | 'new_consent_notice' | 'consent_withdrawal_confirmation' | 'data_request_status_update' | 'case_message' | 'grievance_status_update' | 'consent_regrant_prompt';
468
+ type NotificationCategory = 'consent' | 'request' | 'system';
469
+ type NotificationCTA = {
470
+ label: string;
471
+ style: 'primary' | 'secondary' | 'danger';
472
+ action_type: 'link' | 'acknowledge';
473
+ url?: string;
474
+ };
475
+ type Notification = {
476
+ uuid: string;
477
+ notification_type: NotificationType;
478
+ category: NotificationCategory;
479
+ title: string;
480
+ description: string;
481
+ is_read: boolean;
482
+ is_acknowledged: boolean;
483
+ source_type: string;
484
+ source_uuid: string | null;
485
+ request_type: string;
486
+ request_type_display?: string | null;
487
+ status_label: string;
488
+ status_label_display?: string | null;
489
+ ctas: NotificationCTA[];
490
+ created_at: string;
491
+ };
492
+ type NotificationSummary = {
493
+ total: number;
494
+ unread: number;
495
+ action_needed: number;
496
+ acknowledged: number;
497
+ };
498
+ type NotificationListResponse = {
499
+ data: Notification[];
500
+ total: number;
501
+ skip: number;
502
+ limit: number;
503
+ summary: NotificationSummary | null;
504
+ };
505
+ type UnreadCountResponse = {
506
+ count: number;
507
+ };
508
+ type NotificationActionResponse = {
509
+ message: string;
510
+ };
511
+ type NotificationQueryParams = {
512
+ category?: NotificationCategory;
513
+ notification_type?: NotificationType;
514
+ is_read?: boolean;
515
+ skip?: number;
516
+ limit?: number;
517
+ include_summary?: boolean;
518
+ language?: string;
519
+ };
443
520
 
444
- type InternalPage = 'consent-manager' | 'form' | 'activity' | 'case-details';
521
+ type InternalPage = 'consent-manager' | 'form' | 'activity' | 'case-details' | 'notifications';
445
522
  interface NavigationContextType {
446
523
  currentPage: InternalPage;
447
524
  navigateTo: (page: InternalPage) => void;
@@ -485,6 +562,8 @@ declare function PrivacyCenterActivityPage(): react_jsx_runtime.JSX.Element;
485
562
 
486
563
  declare const PrivacyCenterCaseDetailsPage: () => react_jsx_runtime.JSX.Element | null;
487
564
 
565
+ declare const NotificationsPage: () => react_jsx_runtime.JSX.Element;
566
+
488
567
  type AuthContextValue = Readonly<{
489
568
  accessToken: string;
490
569
  refreshToken: string;
@@ -646,4 +725,4 @@ declare const useAuth: () => AuthContextValue;
646
725
  */
647
726
  declare const injectPCStyles: () => void;
648
727
 
649
- export { type Activity, type ActivityBadgeStatus$1 as ActivityBadgeStatus, type ActivityDetail, type ActivityResponse, type ApiFetchOptions, type ApiResponse, type AuthContext, AuthProvider, type BaseRequest, BaseUrlProvider, type CaseHistoryDetail, type CaseHistoryResponse, type CaseRequest, type ConsentAction, type ConsentDataElement, type ConsentHistoryStatusSummary, ConsentStatusEnum, type CreateCaseResponse, type DataElement, type FetchOrgParams, type FormData, type FormDataResponse, type GrievanceOptions, type GrievanceTypeElement, GrievanceTypeEnum, type GrievanceValue, type InternalPage, type ManageConsentParams, type ManageConsentResponse, NavigationProvider, type NominatedPurposesGroup, type NominationData, type NominatorInfo, type OrganizationDetail, type OrganizationResponse, type OtpResponse, type OtpVerificationResponse, type Pagination, PrivacyCenterActivityPage, PrivacyCenterCaseDetailsPage, PrivacyCenterConsentManagerPage, PrivacyCenterFormPage, PrivacyCenterHomePage, PrivacyCenterLayout, type ProductConsentHistoryGroup, type Purpose, type RawPurposeWrapper, RedactoPrivacyCenter, RequestTypeEnum, type TokenExchangeResponse, type UpdateCorrectionDataItem, type UpdatePurpose, type UpdateRequestDetails, type UserConsent, type UserConsentDetail, type UserConsentResponse, type UserDataRequest, type Workspace, checkAndRefreshAuth, compareEmails, createCaseRequest, createConsentClient, createOtpServer as createOtp, decodeJwtToken, ensureValidToken, exchangeTokenServer as exchangeToken, fetchActivities, fetchCaseHistory, fetchProducts, fetchUserConsents, formatActivityType, getActivityTypeStatus, getCookieValue, getFormData, getInitialState, injectPCStyles, isJwtExpired, isUserAuthenticated, manageConsent, setRefreshTokenCookie, signOutPrivacyCenter, useAuth, useBaseUrl, useCaseHistory, useInternalNavigation, verifyOtpServer as verifyOtp };
728
+ export { type Activity, type ActivityBadgeStatus$1 as ActivityBadgeStatus, type ActivityDetail, type ActivityResponse, type ApiFetchOptions, type ApiResponse, type AuthContext, AuthProvider, type BaseRequest, BaseUrlProvider, type CaseHistoryDetail, type CaseHistoryResponse, type CaseRequest, type ConsentAction, type ConsentDataElement, type ConsentHistoryStatusSummary, ConsentStatusEnum, type CreateCaseResponse, type DataElement, type FetchOrgParams, type FormData, type FormDataResponse, type GrievanceOptions, type GrievanceTypeElement, GrievanceTypeEnum, type GrievanceValue, type InternalPage, type ManageConsentParams, type ManageConsentResponse, NavigationProvider, type NominatedPurposesGroup, type NominationData, type NominatorInfo, NotificationsPage, type OrganizationDetail, type OrganizationResponse, type OtpResponse, type OtpVerificationResponse, type Pagination, PrivacyCenterActivityPage, PrivacyCenterCaseDetailsPage, PrivacyCenterConsentManagerPage, PrivacyCenterFormPage, PrivacyCenterHomePage, PrivacyCenterLayout, type ProductConsentHistoryGroup, type Purpose, type RawPurposeWrapper, RedactoPrivacyCenter, RequestTypeEnum, type TokenExchangeResponse, type UpdateCorrectionDataItem, type UpdatePurpose, type UpdateRequestDetails, type UserConsent, type UserConsentDetail, type UserConsentResponse, type UserDataRequest, type Workspace, checkAndRefreshAuth, compareEmails, createCaseRequest, createConsentClient, createOtpServer as createOtp, decodeJwtToken, ensureValidToken, exchangeTokenServer as exchangeToken, fetchActivities, fetchCaseHistory, fetchProducts, fetchUserConsents, formatActivityType, getActivityTypeStatus, getCookieValue, getFormData, getInitialState, injectPCStyles, isJwtExpired, isUserAuthenticated, manageConsent, setRefreshTokenCookie, signOutPrivacyCenter, useAuth, useBaseUrl, useCaseHistory, useInternalNavigation, verifyOtpServer as verifyOtp };
@@ -102,6 +102,30 @@ declare function createConsentClient(baseUrl: string): {
102
102
  * Get document info/download URL for a case document (privacy center)
103
103
  */
104
104
  getCaseDocument(baseRequest: BaseRequest, caseUuid: string, documentUuid: string, authToken?: string): Promise<MessageDocument>;
105
+ /**
106
+ * List notifications (paginated, with filters)
107
+ */
108
+ getNotifications(baseRequest: BaseRequest, params?: NotificationQueryParams, authToken?: string): Promise<NotificationListResponse>;
109
+ /**
110
+ * Get notification summary (aggregated counts only)
111
+ */
112
+ getNotificationSummary(baseRequest: BaseRequest, authToken?: string): Promise<NotificationSummary>;
113
+ /**
114
+ * Get unread notification count (lightweight, for badge)
115
+ */
116
+ getUnreadCount(baseRequest: BaseRequest, authToken?: string): Promise<UnreadCountResponse>;
117
+ /**
118
+ * Mark a single notification as read
119
+ */
120
+ markNotificationRead(baseRequest: BaseRequest, notificationUuid: string, authToken?: string): Promise<NotificationActionResponse>;
121
+ /**
122
+ * Mark all notifications as read
123
+ */
124
+ markAllNotificationsRead(baseRequest: BaseRequest, authToken?: string): Promise<NotificationActionResponse>;
125
+ /**
126
+ * Acknowledge a notification (sets is_read and is_acknowledged to true)
127
+ */
128
+ acknowledgeNotification(baseRequest: BaseRequest, notificationUuid: string, authToken?: string): Promise<NotificationActionResponse>;
105
129
  };
106
130
 
107
131
  type Workspace = {
@@ -440,8 +464,61 @@ type UploadDocumentResponse = {
440
464
  allow_ai_processing: boolean;
441
465
  metadata: Record<string, string> | null;
442
466
  };
467
+ type NotificationType = 'guardian_verification_request' | 'consent_expiry_warning' | 'new_consent_notice' | 'consent_withdrawal_confirmation' | 'data_request_status_update' | 'case_message' | 'grievance_status_update' | 'consent_regrant_prompt';
468
+ type NotificationCategory = 'consent' | 'request' | 'system';
469
+ type NotificationCTA = {
470
+ label: string;
471
+ style: 'primary' | 'secondary' | 'danger';
472
+ action_type: 'link' | 'acknowledge';
473
+ url?: string;
474
+ };
475
+ type Notification = {
476
+ uuid: string;
477
+ notification_type: NotificationType;
478
+ category: NotificationCategory;
479
+ title: string;
480
+ description: string;
481
+ is_read: boolean;
482
+ is_acknowledged: boolean;
483
+ source_type: string;
484
+ source_uuid: string | null;
485
+ request_type: string;
486
+ request_type_display?: string | null;
487
+ status_label: string;
488
+ status_label_display?: string | null;
489
+ ctas: NotificationCTA[];
490
+ created_at: string;
491
+ };
492
+ type NotificationSummary = {
493
+ total: number;
494
+ unread: number;
495
+ action_needed: number;
496
+ acknowledged: number;
497
+ };
498
+ type NotificationListResponse = {
499
+ data: Notification[];
500
+ total: number;
501
+ skip: number;
502
+ limit: number;
503
+ summary: NotificationSummary | null;
504
+ };
505
+ type UnreadCountResponse = {
506
+ count: number;
507
+ };
508
+ type NotificationActionResponse = {
509
+ message: string;
510
+ };
511
+ type NotificationQueryParams = {
512
+ category?: NotificationCategory;
513
+ notification_type?: NotificationType;
514
+ is_read?: boolean;
515
+ skip?: number;
516
+ limit?: number;
517
+ include_summary?: boolean;
518
+ language?: string;
519
+ };
443
520
 
444
- type InternalPage = 'consent-manager' | 'form' | 'activity' | 'case-details';
521
+ type InternalPage = 'consent-manager' | 'form' | 'activity' | 'case-details' | 'notifications';
445
522
  interface NavigationContextType {
446
523
  currentPage: InternalPage;
447
524
  navigateTo: (page: InternalPage) => void;
@@ -485,6 +562,8 @@ declare function PrivacyCenterActivityPage(): react_jsx_runtime.JSX.Element;
485
562
 
486
563
  declare const PrivacyCenterCaseDetailsPage: () => react_jsx_runtime.JSX.Element | null;
487
564
 
565
+ declare const NotificationsPage: () => react_jsx_runtime.JSX.Element;
566
+
488
567
  type AuthContextValue = Readonly<{
489
568
  accessToken: string;
490
569
  refreshToken: string;
@@ -646,4 +725,4 @@ declare const useAuth: () => AuthContextValue;
646
725
  */
647
726
  declare const injectPCStyles: () => void;
648
727
 
649
- export { type Activity, type ActivityBadgeStatus$1 as ActivityBadgeStatus, type ActivityDetail, type ActivityResponse, type ApiFetchOptions, type ApiResponse, type AuthContext, AuthProvider, type BaseRequest, BaseUrlProvider, type CaseHistoryDetail, type CaseHistoryResponse, type CaseRequest, type ConsentAction, type ConsentDataElement, type ConsentHistoryStatusSummary, ConsentStatusEnum, type CreateCaseResponse, type DataElement, type FetchOrgParams, type FormData, type FormDataResponse, type GrievanceOptions, type GrievanceTypeElement, GrievanceTypeEnum, type GrievanceValue, type InternalPage, type ManageConsentParams, type ManageConsentResponse, NavigationProvider, type NominatedPurposesGroup, type NominationData, type NominatorInfo, type OrganizationDetail, type OrganizationResponse, type OtpResponse, type OtpVerificationResponse, type Pagination, PrivacyCenterActivityPage, PrivacyCenterCaseDetailsPage, PrivacyCenterConsentManagerPage, PrivacyCenterFormPage, PrivacyCenterHomePage, PrivacyCenterLayout, type ProductConsentHistoryGroup, type Purpose, type RawPurposeWrapper, RedactoPrivacyCenter, RequestTypeEnum, type TokenExchangeResponse, type UpdateCorrectionDataItem, type UpdatePurpose, type UpdateRequestDetails, type UserConsent, type UserConsentDetail, type UserConsentResponse, type UserDataRequest, type Workspace, checkAndRefreshAuth, compareEmails, createCaseRequest, createConsentClient, createOtpServer as createOtp, decodeJwtToken, ensureValidToken, exchangeTokenServer as exchangeToken, fetchActivities, fetchCaseHistory, fetchProducts, fetchUserConsents, formatActivityType, getActivityTypeStatus, getCookieValue, getFormData, getInitialState, injectPCStyles, isJwtExpired, isUserAuthenticated, manageConsent, setRefreshTokenCookie, signOutPrivacyCenter, useAuth, useBaseUrl, useCaseHistory, useInternalNavigation, verifyOtpServer as verifyOtp };
728
+ export { type Activity, type ActivityBadgeStatus$1 as ActivityBadgeStatus, type ActivityDetail, type ActivityResponse, type ApiFetchOptions, type ApiResponse, type AuthContext, AuthProvider, type BaseRequest, BaseUrlProvider, type CaseHistoryDetail, type CaseHistoryResponse, type CaseRequest, type ConsentAction, type ConsentDataElement, type ConsentHistoryStatusSummary, ConsentStatusEnum, type CreateCaseResponse, type DataElement, type FetchOrgParams, type FormData, type FormDataResponse, type GrievanceOptions, type GrievanceTypeElement, GrievanceTypeEnum, type GrievanceValue, type InternalPage, type ManageConsentParams, type ManageConsentResponse, NavigationProvider, type NominatedPurposesGroup, type NominationData, type NominatorInfo, NotificationsPage, type OrganizationDetail, type OrganizationResponse, type OtpResponse, type OtpVerificationResponse, type Pagination, PrivacyCenterActivityPage, PrivacyCenterCaseDetailsPage, PrivacyCenterConsentManagerPage, PrivacyCenterFormPage, PrivacyCenterHomePage, PrivacyCenterLayout, type ProductConsentHistoryGroup, type Purpose, type RawPurposeWrapper, RedactoPrivacyCenter, RequestTypeEnum, type TokenExchangeResponse, type UpdateCorrectionDataItem, type UpdatePurpose, type UpdateRequestDetails, type UserConsent, type UserConsentDetail, type UserConsentResponse, type UserDataRequest, type Workspace, checkAndRefreshAuth, compareEmails, createCaseRequest, createConsentClient, createOtpServer as createOtp, decodeJwtToken, ensureValidToken, exchangeTokenServer as exchangeToken, fetchActivities, fetchCaseHistory, fetchProducts, fetchUserConsents, formatActivityType, getActivityTypeStatus, getCookieValue, getFormData, getInitialState, injectPCStyles, isJwtExpired, isUserAuthenticated, manageConsent, setRefreshTokenCookie, signOutPrivacyCenter, useAuth, useBaseUrl, useCaseHistory, useInternalNavigation, verifyOtpServer as verifyOtp };