@redacto.io/consent-sdk-react 9.4.0 → 10.0.0-beta.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 (36) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/index.d.mts +4 -2
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +122 -15
  5. package/dist/index.mjs +122 -15
  6. package/dist/privacy-center.d.mts +31 -7
  7. package/dist/privacy-center.d.ts +31 -7
  8. package/dist/privacy-center.js +187 -44
  9. package/dist/privacy-center.mjs +187 -44
  10. package/package.json +1 -1
  11. package/src/RedactoNoticeConsent/RedactoNoticeConsent.test.tsx +5 -0
  12. package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +29 -4
  13. package/src/RedactoNoticeConsent/api/index.ts +131 -2
  14. package/src/RedactoNoticeConsent/api/types.ts +33 -1
  15. package/src/RedactoNoticeConsent/types.ts +1 -0
  16. package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +3 -1
  17. package/src/RedactoNoticeConsentInline/api/index.ts +5 -2
  18. package/src/RedactoNoticeConsentInline/api/types.ts +1 -1
  19. package/src/RedactoNoticeConsentInline/types.ts +1 -0
  20. package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +6 -4
  21. package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +3 -1
  22. package/src/RedactoPrivacyCenter/api/actions.ts +10 -3
  23. package/src/RedactoPrivacyCenter/api/client.ts +67 -21
  24. package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +12 -1
  25. package/src/RedactoPrivacyCenter/components/Form.tsx +58 -6
  26. package/src/RedactoPrivacyCenter/components/groupHelpers.ts +64 -1
  27. package/src/RedactoPrivacyCenter/context/AuthContext.tsx +7 -5
  28. package/src/RedactoPrivacyCenter/context/BaseUrlContext.tsx +8 -2
  29. package/src/RedactoPrivacyCenter/context/types.ts +1 -0
  30. package/src/RedactoPrivacyCenter/lib/api.ts +8 -0
  31. package/src/RedactoPrivacyCenter/lib/constants.ts +9 -0
  32. package/src/RedactoPrivacyCenter/lib/types.ts +11 -1
  33. package/src/RedactoPrivacyCenter/lib/utils.ts +28 -0
  34. package/tests/Form.test.tsx +5 -0
  35. package/tests/mocks.ts +1 -0
  36. package/tests/resolveContactFromJwt.test.ts +44 -0
@@ -31,9 +31,11 @@ type BaseRequest = {
31
31
  /**
32
32
  * Consent service client factory.
33
33
  * Creates a client instance with a specific base URL.
34
- * @param baseUrl - Consent server base URL
34
+ * @param baseUrl - Consent server base URL (Python service, e.g. http://host/consent)
35
+ * @param ledgerBaseUrl - Go ledger base URL (e.g. http://host:8090/consent-ledger).
36
+ * Used for user-consents reads which are served from the ledger's `/public/...` paths.
35
37
  */
36
- declare function createConsentClient(baseUrl: string): {
38
+ declare function createConsentClient(baseUrl: string, ledgerBaseUrl: string): {
37
39
  /**
38
40
  * Get form data (privacy center)
39
41
  */
@@ -92,9 +94,21 @@ declare function createConsentClient(baseUrl: string): {
92
94
  nominator_uuid?: string;
93
95
  }, authToken?: string, options?: Omit<ApiFetchOptions, "getAuthToken">): Promise<unknown>;
94
96
  /**
95
- * Manage consent (privacy center) - revoke, regrant, or renew
97
+ * Manage consent (privacy center) - revoke, regrant, or renew.
98
+ *
99
+ * The Go ledger has no manage-consent route, so this is expressed as a
100
+ * `partial` submit-consent on the ledger — mirroring the Python dual-write
101
+ * relay (`build_consent_management_payload`): the affected purpose is
102
+ * re-submitted with `selected: false` to revoke or `selected: true` to
103
+ * regrant/renew, and `partial: true` so the rest of the notice's purposes
104
+ * are left untouched. The principal is resolved from the JWT, so no
105
+ * `contact`/identifiers are sent in the body, and `consent_event_uuid` is
106
+ * omitted so the ledger mints a fresh event.
96
107
  */
97
- manageConsent(baseRequest: BaseRequest, purposeId: string, contact: string, status: "revoke" | "regrant" | "renew", authToken?: string, options?: Omit<ApiFetchOptions, "getAuthToken">, nominatorContact?: string, dataElementUuids?: string[], productUuid?: string): Promise<unknown>;
108
+ manageConsent(baseRequest: BaseRequest, purposeId: string, contact: string, status: "revoke" | "regrant" | "renew", authToken?: string, options?: Omit<ApiFetchOptions, "getAuthToken">, nominatorContact?: string, dataElementUuids?: string[], productUuid?: string, noticeUuid?: string, dataElements?: Array<{
109
+ uuid: string;
110
+ selected: boolean;
111
+ }>): Promise<unknown>;
98
112
  /**
99
113
  * Get activities (privacy center)
100
114
  */
@@ -358,6 +372,7 @@ type PurposeItem = {
358
372
  method: string;
359
373
  data_elements: ConsentDataElement[];
360
374
  link_reason: string | null;
375
+ notice_uuid: string | null;
361
376
  };
362
377
  type ConsentGroup = {
363
378
  product_uuid: string;
@@ -609,6 +624,7 @@ declare const useInternalNavigation: () => NavigationContextType;
609
624
 
610
625
  interface RedactoPrivacyCenterProps {
611
626
  baseUrl: string;
627
+ ledgerBaseUrl: string;
612
628
  slug: string;
613
629
  accessToken: string;
614
630
  refreshToken: string;
@@ -616,7 +632,7 @@ interface RedactoPrivacyCenterProps {
616
632
  initialPage?: InternalPage;
617
633
  onBack?: 'back' | 'signout';
618
634
  }
619
- declare function RedactoPrivacyCenter({ baseUrl, slug, accessToken, refreshToken, onError, initialPage, onBack, }: RedactoPrivacyCenterProps): react_jsx_runtime.JSX.Element;
635
+ declare function RedactoPrivacyCenter({ baseUrl, ledgerBaseUrl, slug, accessToken, refreshToken, onError, initialPage, onBack, }: RedactoPrivacyCenterProps): react_jsx_runtime.JSX.Element;
620
636
 
621
637
  interface PrivacyCenterLayoutProps {
622
638
  children: ReactNode;
@@ -646,15 +662,18 @@ type AuthContextValue = Readonly<{
646
662
  }>;
647
663
  type BaseUrlContextValue = Readonly<{
648
664
  baseUrl: string;
665
+ ledgerBaseUrl: string;
649
666
  consentClient: ReturnType<typeof createConsentClient>;
650
667
  }>;
651
668
 
652
- declare const BaseUrlProvider: ({ children, baseUrl, }: {
669
+ declare const BaseUrlProvider: ({ children, baseUrl, ledgerBaseUrl, }: {
653
670
  children: ReactNode;
654
671
  baseUrl: string;
672
+ ledgerBaseUrl: string;
655
673
  }) => react_jsx_runtime.JSX.Element;
656
674
  declare const useBaseUrl: () => Readonly<{
657
675
  baseUrl: string;
676
+ ledgerBaseUrl: string;
658
677
  consentClient: ReturnType<typeof createConsentClient>;
659
678
  }>;
660
679
 
@@ -801,7 +820,7 @@ type FetchGroupPurposesParams = {
801
820
  consentClient?: BaseUrlContextValue['consentClient'];
802
821
  };
803
822
  declare const fetchGroupPurposes: (params: FetchGroupPurposesParams) => Promise<GroupPurposesOut | null>;
804
- declare const manageConsent: ({ organizationId, workspaceId, purposeId, contact, action, authContext, consentClient, nominatorContact, dataElementUuids, productUuid, }: {
823
+ declare const manageConsent: ({ organizationId, workspaceId, purposeId, contact, action, authContext, consentClient, nominatorContact, dataElementUuids, productUuid, noticeUuid, dataElements, }: {
805
824
  organizationId: string;
806
825
  workspaceId: string;
807
826
  purposeId: string;
@@ -812,6 +831,11 @@ declare const manageConsent: ({ organizationId, workspaceId, purposeId, contact,
812
831
  nominatorContact?: string;
813
832
  dataElementUuids?: string[];
814
833
  productUuid?: string;
834
+ noticeUuid?: string;
835
+ dataElements?: Array<{
836
+ uuid: string;
837
+ selected: boolean;
838
+ }>;
815
839
  }) => Promise<boolean | null>;
816
840
  declare const fetchActivities: (organizationId: string, workspaceId: string, offset?: number, limit?: number, authContext?: AuthContext, consentClient?: BaseUrlContextValue["consentClient"], language?: string) => Promise<ActivityDetail | null>;
817
841
  declare const fetchCaseHistory: (organizationId: string, workspaceId: string, contact: string, offset?: number, limit?: number, authContext?: AuthContext, consentClient?: BaseUrlContextValue["consentClient"], language?: string) => Promise<CaseHistoryDetail | null>;
@@ -8642,13 +8642,12 @@ async function fetchGroupPurposesServer(params) {
8642
8642
  }
8643
8643
  }
8644
8644
  async function manageConsentServer(params) {
8645
- var _a;
8646
8645
  try {
8647
8646
  if (!params.consentClient) {
8648
8647
  throw new Error("Consent client is required");
8649
8648
  }
8650
8649
  const baseRequest = buildBaseRequest(params.organizationId, params.workspaceId, params.authToken);
8651
- const result = await params.consentClient.manageConsent(
8650
+ await params.consentClient.manageConsent(
8652
8651
  baseRequest,
8653
8652
  params.purposeId,
8654
8653
  params.contact,
@@ -8657,9 +8656,11 @@ async function manageConsentServer(params) {
8657
8656
  void 0,
8658
8657
  params.nominatorContact,
8659
8658
  params.dataElementUuids,
8660
- params.productUuid
8659
+ params.productUuid,
8660
+ params.noticeUuid,
8661
+ params.dataElements
8661
8662
  );
8662
- return (_a = result == null ? void 0 : result.success) != null ? _a : null;
8663
+ return true;
8663
8664
  } catch (error) {
8664
8665
  const errorMsg = (error == null ? void 0 : error.message) || "";
8665
8666
  if (errorMsg.includes("nominator_not_found")) {
@@ -9096,6 +9097,7 @@ var MIN_REFRESH_BACKOFF_MS = 3e4;
9096
9097
  var MAX_REFRESH_BACKOFF_MS = 3e5;
9097
9098
  var REFRESH_TOKEN_STORAGE_KEY = "redacto_pc_refresh_token";
9098
9099
  var LEGACY_REFRESH_TOKEN_COOKIE = "refresh_token";
9100
+ var FORM_PICKER_GROUP_LIMIT = 100;
9099
9101
  var POLL_INTERVAL = 3e4;
9100
9102
  var NOTIFICATION_PAGE_SIZE = 10;
9101
9103
  var NOTIFICATION_DROPDOWN_LIMIT = 5;
@@ -9271,6 +9273,14 @@ var decodeJwtToken = (token) => {
9271
9273
  return null;
9272
9274
  }
9273
9275
  };
9276
+ var resolveContactFromJwt = (decoded) => {
9277
+ if (!decoded) {
9278
+ return null;
9279
+ }
9280
+ const userData = decoded.user_data || {};
9281
+ const candidate = decoded.contact || decoded.primary_email || userData.primary_email || userData.primary_mobile || userData.org_user_id;
9282
+ return typeof candidate === "string" && candidate.trim() !== "" ? candidate : null;
9283
+ };
9274
9284
  var isJwtExpired = (token, bufferSeconds = 5 * 60) => {
9275
9285
  if (!token || typeof token !== "string") {
9276
9286
  return true;
@@ -9751,7 +9761,9 @@ var manageConsent = async ({
9751
9761
  consentClient,
9752
9762
  nominatorContact,
9753
9763
  dataElementUuids,
9754
- productUuid
9764
+ productUuid,
9765
+ noticeUuid,
9766
+ dataElements
9755
9767
  }) => {
9756
9768
  try {
9757
9769
  const accessToken = await ensureValidToken(organizationId, workspaceId, void 0, authContext, consentClient);
@@ -9768,7 +9780,9 @@ var manageConsent = async ({
9768
9780
  consentClient,
9769
9781
  nominatorContact,
9770
9782
  dataElementUuids,
9771
- productUuid
9783
+ productUuid,
9784
+ noticeUuid,
9785
+ dataElements
9772
9786
  });
9773
9787
  return result;
9774
9788
  } catch (error) {
@@ -9788,7 +9802,9 @@ var manageConsent = async ({
9788
9802
  consentClient,
9789
9803
  nominatorContact,
9790
9804
  dataElementUuids,
9791
- productUuid
9805
+ productUuid,
9806
+ noticeUuid,
9807
+ dataElements
9792
9808
  });
9793
9809
  }
9794
9810
  console.error(`Error ${action} consent:`, error);
@@ -9998,9 +10014,9 @@ var syncJwtDataToSessionStorage = (accessToken) => {
9998
10014
  if (!decoded) {
9999
10015
  return;
10000
10016
  }
10001
- const email = decoded.contact || decoded.primary_email || sessionStorage.getItem("email") || (typeof localStorage !== "undefined" ? localStorage.getItem("userEmail") : null);
10002
- if (email && typeof email === "string") {
10003
- sessionStorage.setItem("email", email);
10017
+ const contact = resolveContactFromJwt(decoded) || sessionStorage.getItem("email") || (typeof localStorage !== "undefined" ? localStorage.getItem("userEmail") : null);
10018
+ if (contact && typeof contact === "string") {
10019
+ sessionStorage.setItem("email", contact);
10004
10020
  }
10005
10021
  const orgUuid = decoded.organisation_uuid;
10006
10022
  if (orgUuid && typeof orgUuid === "string") {
@@ -10097,7 +10113,11 @@ var useAuth = () => {
10097
10113
  var import_react4 = require("react");
10098
10114
 
10099
10115
  // src/RedactoPrivacyCenter/api/client.ts
10100
- function createConsentClient(baseUrl) {
10116
+ function createConsentClient(baseUrl, ledgerBaseUrl) {
10117
+ if (!ledgerBaseUrl) {
10118
+ throw new Error("ledgerBaseUrl is required to create the consent client");
10119
+ }
10120
+ const ledgerBase = ledgerBaseUrl.replace(/\/$/, "");
10101
10121
  async function privacyCenterApiFetch(url, options) {
10102
10122
  const { authToken, getAuthToken, headers = {}, ...fetchOptions } = options;
10103
10123
  const requestHeaders = new Headers();
@@ -10190,6 +10210,9 @@ function createConsentClient(baseUrl) {
10190
10210
  function privacyCenterUrl(baseRequest, path) {
10191
10211
  return `${baseUrl}/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}/dsar/privacy-center${path}`;
10192
10212
  }
10213
+ function ledgerUrl(baseRequest, path) {
10214
+ return `${ledgerBase}/public/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}${path}`;
10215
+ }
10193
10216
  function caseUrl(baseRequest, caseUuid, path = "") {
10194
10217
  return privacyCenterUrl(baseRequest, `/cases/${caseUuid}${path}`);
10195
10218
  }
@@ -10323,7 +10346,8 @@ function createConsentClient(baseUrl) {
10323
10346
  if (params.product_uuid) queryParams.append("product_uuid", params.product_uuid);
10324
10347
  if (params.language) queryParams.append("language", params.language);
10325
10348
  const queryString = queryParams.toString();
10326
- const url = privacyCenterUrl(baseRequest, `/user-consents${queryString ? `?${queryString}` : ""}`);
10349
+ const suffix = `/user-consents${queryString ? `?${queryString}` : ""}`;
10350
+ const url = ledgerUrl(baseRequest, suffix);
10327
10351
  return privacyCenterApiFetch(url, {
10328
10352
  ...options,
10329
10353
  method: "GET",
@@ -10344,10 +10368,8 @@ function createConsentClient(baseUrl) {
10344
10368
  if (params.language) queryParams.append("language", params.language);
10345
10369
  if (params.nominator_uuid) queryParams.append("nominator_uuid", params.nominator_uuid);
10346
10370
  const queryString = queryParams.toString();
10347
- const url = privacyCenterUrl(
10348
- baseRequest,
10349
- `/user-consents/${productUuid}/purposes${queryString ? `?${queryString}` : ""}`
10350
- );
10371
+ const suffix = `/user-consents/${productUuid}/purposes${queryString ? `?${queryString}` : ""}`;
10372
+ const url = ledgerUrl(baseRequest, suffix);
10351
10373
  return privacyCenterApiFetch(url, {
10352
10374
  ...options,
10353
10375
  method: "GET",
@@ -10356,20 +10378,48 @@ function createConsentClient(baseUrl) {
10356
10378
  });
10357
10379
  },
10358
10380
  /**
10359
- * Manage consent (privacy center) - revoke, regrant, or renew
10381
+ * Manage consent (privacy center) - revoke, regrant, or renew.
10382
+ *
10383
+ * The Go ledger has no manage-consent route, so this is expressed as a
10384
+ * `partial` submit-consent on the ledger — mirroring the Python dual-write
10385
+ * relay (`build_consent_management_payload`): the affected purpose is
10386
+ * re-submitted with `selected: false` to revoke or `selected: true` to
10387
+ * regrant/renew, and `partial: true` so the rest of the notice's purposes
10388
+ * are left untouched. The principal is resolved from the JWT, so no
10389
+ * `contact`/identifiers are sent in the body, and `consent_event_uuid` is
10390
+ * omitted so the ledger mints a fresh event.
10360
10391
  */
10361
- async manageConsent(baseRequest, purposeId, contact, status, authToken, options, nominatorContact, dataElementUuids, productUuid) {
10362
- const url = privacyCenterUrl(baseRequest, `/manage-consent?status=${status}`);
10363
- const body = { purpose_uuid: purposeId, contact };
10364
- if (nominatorContact) {
10365
- body.nominator_contact = nominatorContact;
10366
- }
10367
- if (Array.isArray(dataElementUuids) && dataElementUuids.length > 0) {
10368
- body.data_element_uuids = dataElementUuids;
10369
- }
10370
- if (productUuid) {
10371
- body.product_uuid = productUuid;
10372
- }
10392
+ async manageConsent(baseRequest, purposeId, contact, status, authToken, options, nominatorContact, dataElementUuids, productUuid, noticeUuid, dataElements) {
10393
+ if (!noticeUuid) {
10394
+ throw new Error("notice_uuid is required to manage consent via the ledger");
10395
+ }
10396
+ const purposeSelected = status !== "revoke";
10397
+ const elements = (dataElements != null ? dataElements : []).map((de) => {
10398
+ let selected;
10399
+ if (status === "revoke") {
10400
+ selected = false;
10401
+ } else if (status === "regrant") {
10402
+ selected = Array.isArray(dataElementUuids) ? dataElementUuids.includes(de.uuid) : de.selected;
10403
+ } else {
10404
+ selected = de.selected;
10405
+ }
10406
+ return { uuid: de.uuid, selected };
10407
+ });
10408
+ const body = {
10409
+ notice_uuid: noticeUuid,
10410
+ partial: true,
10411
+ declined: false,
10412
+ select_all_mandatory: false,
10413
+ self_declared_adult: false,
10414
+ purposes: [
10415
+ {
10416
+ purpose_uuid: purposeId,
10417
+ selected: purposeSelected,
10418
+ data_elements: elements
10419
+ }
10420
+ ]
10421
+ };
10422
+ const url = ledgerUrl(baseRequest, "/submit-consent");
10373
10423
  return privacyCenterApiFetch(url, {
10374
10424
  ...options,
10375
10425
  method: "POST",
@@ -10406,7 +10456,7 @@ function createConsentClient(baseUrl) {
10406
10456
  if (params.created_before) queryParams.append("created_before", params.created_before);
10407
10457
  if (params.language) queryParams.append("language", params.language);
10408
10458
  const queryString = queryParams.toString();
10409
- const url = privacyCenterUrl(baseRequest, `/receipts${queryString ? `?${queryString}` : ""}`);
10459
+ const url = ledgerUrl(baseRequest, `/receipts${queryString ? `?${queryString}` : ""}`);
10410
10460
  return privacyCenterApiFetch(url, {
10411
10461
  ...options,
10412
10462
  method: "GET",
@@ -10421,7 +10471,7 @@ function createConsentClient(baseUrl) {
10421
10471
  * and the Authorization header must be sent (anchor navigation wouldn't carry it).
10422
10472
  */
10423
10473
  async getReceiptPdf(baseRequest, receiptUuid, authToken) {
10424
- const url = privacyCenterUrl(baseRequest, `/receipts/${receiptUuid}/pdf`);
10474
+ const url = ledgerUrl(baseRequest, `/receipts/${receiptUuid}/download`);
10425
10475
  const token = resolveAuthToken(authToken, baseRequest);
10426
10476
  const requestHeaders = new Headers();
10427
10477
  requestHeaders.set("Accept", "application/pdf");
@@ -10607,15 +10657,20 @@ var import_jsx_runtime4 = require("react/jsx-runtime");
10607
10657
  var BaseUrlContext = (0, import_react4.createContext)(null);
10608
10658
  var BaseUrlProvider = ({
10609
10659
  children,
10610
- baseUrl
10660
+ baseUrl,
10661
+ ledgerBaseUrl
10611
10662
  }) => {
10612
- const consentClient = (0, import_react4.useMemo)(() => createConsentClient(baseUrl), [baseUrl]);
10663
+ const consentClient = (0, import_react4.useMemo)(
10664
+ () => createConsentClient(baseUrl, ledgerBaseUrl),
10665
+ [baseUrl, ledgerBaseUrl]
10666
+ );
10613
10667
  const value = (0, import_react4.useMemo)(
10614
10668
  () => ({
10615
10669
  baseUrl,
10670
+ ledgerBaseUrl,
10616
10671
  consentClient
10617
10672
  }),
10618
- [baseUrl, consentClient]
10673
+ [baseUrl, ledgerBaseUrl, consentClient]
10619
10674
  );
10620
10675
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BaseUrlContext.Provider, { value, children });
10621
10676
  };
@@ -15145,9 +15200,9 @@ function PrivacyCenterLayout({ children, slug, onBack }) {
15145
15200
  if (orgId) sessionStorage.setItem("pc_org_id", orgId);
15146
15201
  if (workspaceId) sessionStorage.setItem("pc_workspace_id", workspaceId);
15147
15202
  if (orgSlug) sessionStorage.setItem("pc_org_slug", orgSlug);
15148
- const email = decoded.contact || decoded.primary_email;
15149
- if (email && typeof email === "string") {
15150
- sessionStorage.setItem("email", email);
15203
+ const contact = resolveContactFromJwt(decoded);
15204
+ if (contact) {
15205
+ sessionStorage.setItem("email", contact);
15151
15206
  }
15152
15207
  }
15153
15208
  }
@@ -18155,6 +18210,7 @@ function ConsentManager({ variant }) {
18155
18210
  );
18156
18211
  const handleManageConsent = (0, import_react37.useCallback)(
18157
18212
  async (purposeId, action, nominatorContact, dataElementUuids, productUuid) => {
18213
+ var _a2, _b2;
18158
18214
  if (!organizationId || !workspaceId || !contact) {
18159
18215
  toast.error(t("missingInfoToManage"));
18160
18216
  return;
@@ -18171,6 +18227,11 @@ function ConsentManager({ variant }) {
18171
18227
  renew: t("unableToRenewConsent")
18172
18228
  };
18173
18229
  try {
18230
+ const noticeUuid = (_a2 = selectedRecord == null ? void 0 : selectedRecord.notice_uuid) != null ? _a2 : void 0;
18231
+ const dataElements = ((_b2 = selectedRecord == null ? void 0 : selectedRecord.data_elements) != null ? _b2 : []).map((el) => ({
18232
+ uuid: el.uuid,
18233
+ selected: el.selected
18234
+ }));
18174
18235
  const response = await manageConsent({
18175
18236
  organizationId,
18176
18237
  workspaceId,
@@ -18181,7 +18242,9 @@ function ConsentManager({ variant }) {
18181
18242
  consentClient,
18182
18243
  nominatorContact,
18183
18244
  dataElementUuids,
18184
- productUuid
18245
+ productUuid,
18246
+ noticeUuid,
18247
+ dataElements
18185
18248
  });
18186
18249
  if (response) {
18187
18250
  toast.success(successMessages[action]);
@@ -18203,7 +18266,7 @@ function ConsentManager({ variant }) {
18203
18266
  handleCloseModal();
18204
18267
  }
18205
18268
  },
18206
- [organizationId, workspaceId, contact, fetchData, handleCloseModal, t, authContext, consentClient]
18269
+ [organizationId, workspaceId, contact, fetchData, handleCloseModal, t, authContext, consentClient, selectedRecord]
18207
18270
  );
18208
18271
  const getVar26 = (varName) => `var(${varName})`;
18209
18272
  const directBadge = (_c = (_b = consentDetail == null ? void 0 : consentDetail.status_summary) == null ? void 0 : _b.direct_purposes) != null ? _c : "";
@@ -18728,6 +18791,43 @@ var import_ai = require("react-icons/ai");
18728
18791
  var import_pi4 = require("react-icons/pi");
18729
18792
 
18730
18793
  // src/RedactoPrivacyCenter/components/groupHelpers.ts
18794
+ var consentGroupToFormProductGroup = (group) => {
18795
+ var _a;
18796
+ return {
18797
+ product_uuid: group.product_uuid,
18798
+ product_name: group.product_name,
18799
+ product_description: group.product_description,
18800
+ nominator: group.nominator,
18801
+ purposes: ((_a = group.purposes) != null ? _a : []).map(purposeItemToFormPurpose)
18802
+ };
18803
+ };
18804
+ var purposeItemToFormPurpose = (purpose) => {
18805
+ var _a, _b;
18806
+ return {
18807
+ uuid: purpose.purpose_uuid,
18808
+ purpose_uuid: purpose.purpose_uuid,
18809
+ name: purpose.name,
18810
+ description: (_a = purpose.description) != null ? _a : "",
18811
+ industries: "",
18812
+ selected: false,
18813
+ given_consent: false,
18814
+ status: purpose.status,
18815
+ validity: null,
18816
+ enabled: true,
18817
+ data_elements: ((_b = purpose.data_elements) != null ? _b : []).map(
18818
+ consentDataElementToFormDataElement
18819
+ )
18820
+ };
18821
+ };
18822
+ var consentDataElementToFormDataElement = (element) => ({
18823
+ uuid: element.uuid,
18824
+ name: element.name,
18825
+ description: "",
18826
+ enabled: element.enabled,
18827
+ required: element.required,
18828
+ given_consent: element.selected,
18829
+ selected: element.selected
18830
+ });
18731
18831
  var buildGroupPurposes = (group) => group.purposes.filter((p) => p !== null && p !== void 0).map((p) => {
18732
18832
  const validDataElements = Array.isArray(p.data_elements) ? p.data_elements.filter((de) => de !== null && de !== void 0 && Boolean(de.uuid)).map((de) => ({ ...de, selected: false })) : [];
18733
18833
  return {
@@ -19956,6 +20056,44 @@ function Form({
19956
20056
  },
19957
20057
  []
19958
20058
  );
20059
+ const withLedgerPickerGroups = (0, import_react41.useCallback)(
20060
+ async (form, language) => {
20061
+ var _a2, _b2;
20062
+ if (isPopup || isCaseManagementContext || !organizationId || !workspaceId) {
20063
+ return form;
20064
+ }
20065
+ const consents = await fetchUserConsents({
20066
+ organizationId,
20067
+ workspaceId,
20068
+ authContext,
20069
+ consentClient,
20070
+ // No status filter: include every status (active / expired / withdrawn
20071
+ // / declined), matching Python form/data, so a DSAR can target products
20072
+ // the user no longer actively consents to.
20073
+ limit: FORM_PICKER_GROUP_LIMIT,
20074
+ nominatedLimit: FORM_PICKER_GROUP_LIMIT,
20075
+ language
20076
+ });
20077
+ if (!consents) {
20078
+ return form;
20079
+ }
20080
+ return {
20081
+ ...form,
20082
+ direct_groups: ((_a2 = consents.direct) != null ? _a2 : []).map(consentGroupToFormProductGroup),
20083
+ nominated_groups: ((_b2 = consents.nominated) != null ? _b2 : []).map(
20084
+ consentGroupToFormProductGroup
20085
+ )
20086
+ };
20087
+ },
20088
+ [
20089
+ isPopup,
20090
+ isCaseManagementContext,
20091
+ organizationId,
20092
+ workspaceId,
20093
+ authContext,
20094
+ consentClient
20095
+ ]
20096
+ );
19959
20097
  const fetchAndApplyTranslations = (0, import_react41.useCallback)(async (langValue) => {
19960
20098
  if (!organizationId || !workspaceId || !data) {
19961
20099
  return;
@@ -19984,7 +20122,7 @@ function Form({
19984
20122
  toast.info(t("translationNotAvailable"));
19985
20123
  return;
19986
20124
  }
19987
- setData(translatedFormData);
20125
+ setData(await withLedgerPickerGroups(translatedFormData, langValue));
19988
20126
  if (translatedFormData.grievance_options) {
19989
20127
  const currentGrievanceSelections = { ...selectedGrievances };
19990
20128
  setGrievanceOptions(translatedFormData.grievance_options);
@@ -20000,7 +20138,7 @@ function Form({
20000
20138
  } finally {
20001
20139
  setIsTranslating(false);
20002
20140
  }
20003
- }, [organizationId, workspaceId, data, formData.contact, isPopup, isCaseManagementContext, authContext, consentClient, selectedGrievances, t]);
20141
+ }, [organizationId, workspaceId, data, formData.contact, isPopup, isCaseManagementContext, authContext, consentClient, selectedGrievances, t, withLedgerPickerGroups]);
20004
20142
  (0, import_react41.useEffect)(() => {
20005
20143
  if (!skipProductStep) {
20006
20144
  setSelectedProductKey(null);
@@ -20106,7 +20244,11 @@ function Form({
20106
20244
  console.warn("No purposes with data elements found in API response");
20107
20245
  }
20108
20246
  }
20109
- setData(displayData);
20247
+ const pickerData = await withLedgerPickerGroups(
20248
+ displayData,
20249
+ langParam || void 0
20250
+ );
20251
+ setData(pickerData);
20110
20252
  setGrievanceOptions(displayData.grievance_options || []);
20111
20253
  const initialGrievances = (displayData.grievance_options || []).reduce(
20112
20254
  (acc, option) => {
@@ -20126,7 +20268,7 @@ function Form({
20126
20268
  }
20127
20269
  };
20128
20270
  void initializePrivacyCenterForm();
20129
- }, [organizationId, workspaceId, isPopup, authContext, consentClient]);
20271
+ }, [organizationId, workspaceId, isPopup, authContext, consentClient, withLedgerPickerGroups]);
20130
20272
  const getEnglishDataElementName = (0, import_react41.useCallback)((translatedName) => {
20131
20273
  var _a2, _b2, _c2;
20132
20274
  if (!((_a2 = englishDataRef.current) == null ? void 0 : _a2.purposes)) {
@@ -27530,6 +27672,7 @@ var import_jsx_runtime90 = require("react/jsx-runtime");
27530
27672
  injectPCStyles();
27531
27673
  function RedactoPrivacyCenter({
27532
27674
  baseUrl,
27675
+ ledgerBaseUrl,
27533
27676
  slug,
27534
27677
  accessToken,
27535
27678
  refreshToken,
@@ -27537,7 +27680,7 @@ function RedactoPrivacyCenter({
27537
27680
  initialPage = "consent-manager",
27538
27681
  onBack
27539
27682
  }) {
27540
- return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(import_react_i18next52.I18nextProvider, { i18n: i18n_default, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(BrandingProvider, { slug, baseUrl, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(BaseUrlProvider, { baseUrl, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
27683
+ return /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(import_react_i18next52.I18nextProvider, { i18n: i18n_default, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(BrandingProvider, { slug, baseUrl, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(BaseUrlProvider, { baseUrl, ledgerBaseUrl, children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
27541
27684
  AuthProvider,
27542
27685
  {
27543
27686
  accessToken,