@redacto.io/consent-sdk-react 10.0.0-beta.7 → 10.0.0-beta.9

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 (34) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/{chunk-6A665OPR.mjs → chunk-OGL6OC3A.mjs} +4 -0
  3. package/dist/index.d.mts +29 -3
  4. package/dist/index.d.ts +29 -3
  5. package/dist/index.js +162 -56
  6. package/dist/index.mjs +161 -57
  7. package/dist/privacy-center.d.mts +54 -12
  8. package/dist/privacy-center.d.ts +54 -12
  9. package/dist/privacy-center.js +265 -77
  10. package/dist/privacy-center.mjs +264 -78
  11. package/package.json +1 -1
  12. package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +55 -5
  13. package/src/RedactoNoticeConsent/api/index.ts +78 -48
  14. package/src/RedactoNoticeConsent/api/sandbox.ts +150 -0
  15. package/src/RedactoNoticeConsent/api/types.ts +57 -11
  16. package/src/RedactoNoticeConsent/types.ts +28 -2
  17. package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +37 -2
  18. package/src/RedactoPrivacyCenter/api/actions.ts +3 -1
  19. package/src/RedactoPrivacyCenter/api/client.ts +122 -25
  20. package/src/RedactoPrivacyCenter/api/fetcher.ts +24 -9
  21. package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +2 -1
  22. package/src/RedactoPrivacyCenter/components/Form.tsx +55 -30
  23. package/src/RedactoPrivacyCenter/components/SelectUserGate.tsx +8 -0
  24. package/src/RedactoPrivacyCenter/components/groupHelpers.ts +42 -6
  25. package/src/RedactoPrivacyCenter/context/AuthContext.tsx +131 -39
  26. package/src/RedactoPrivacyCenter/context/types.ts +38 -0
  27. package/src/RedactoPrivacyCenter/lib/api.ts +3 -0
  28. package/src/RedactoPrivacyCenter/lib/constants.ts +12 -5
  29. package/src/RedactoPrivacyCenter/lib/sandbox.ts +104 -0
  30. package/src/RedactoPrivacyCenter/lib/types.ts +20 -0
  31. package/src/RedactoPrivacyCenter/lib/utils.ts +15 -0
  32. package/src/shared/sandbox.ts +6 -0
  33. package/tests/Form.test.tsx +142 -5
  34. package/tests/consentClient.test.ts +46 -0
@@ -1,6 +1,7 @@
1
1
  import {
2
+ SANDBOX_TOKEN_HEADER,
2
3
  useMediaQuery
3
- } from "./chunk-6A665OPR.mjs";
4
+ } from "./chunk-OGL6OC3A.mjs";
4
5
 
5
6
  // src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx
6
7
  import { I18nextProvider } from "react-i18next";
@@ -8098,6 +8099,33 @@ import {
8098
8099
  useState as useState2
8099
8100
  } from "react";
8100
8101
 
8102
+ // src/RedactoPrivacyCenter/lib/sandbox.ts
8103
+ var sandboxConfig = null;
8104
+ var setSandboxConfig = (config) => {
8105
+ sandboxConfig = config;
8106
+ };
8107
+ var getSandboxConfig = () => sandboxConfig;
8108
+ var isSandboxMode = () => sandboxConfig !== null;
8109
+ var sandboxAuthHeaders = () => {
8110
+ if (!sandboxConfig) {
8111
+ return null;
8112
+ }
8113
+ return {
8114
+ [SANDBOX_TOKEN_HEADER]: sandboxConfig.token
8115
+ };
8116
+ };
8117
+ var sandboxBodyIdentity = () => {
8118
+ if (!sandboxConfig) {
8119
+ return null;
8120
+ }
8121
+ if (sandboxConfig.ucic) {
8122
+ return { org_user_id: sandboxConfig.ucic };
8123
+ }
8124
+ return sandboxConfig.subject.includes("@") ? { primary_email: sandboxConfig.subject } : { primary_mobile: sandboxConfig.subject };
8125
+ };
8126
+ var sandboxQueryIdentity = () => sandboxBodyIdentity();
8127
+ var sandboxContact = () => sandboxConfig ? sandboxConfig.ucic || sandboxConfig.subject : null;
8128
+
8101
8129
  // src/RedactoPrivacyCenter/api/fetcher.ts
8102
8130
  var ApiError = class _ApiError extends Error {
8103
8131
  constructor(message, options = {}) {
@@ -8144,11 +8172,18 @@ async function apiFetch(url, options = {}) {
8144
8172
  }
8145
8173
  }
8146
8174
  if (getAuthToken) {
8147
- const token = await getAuthToken();
8148
- if (token) {
8149
- const trimmedToken = token.trim();
8150
- requestHeaders.set("X-Auth-Token", trimmedToken);
8151
- requestHeaders.set("x-auth-token", trimmedToken);
8175
+ const sandboxHeaders = sandboxAuthHeaders();
8176
+ if (sandboxHeaders) {
8177
+ Object.entries(sandboxHeaders).forEach(([key, value]) => {
8178
+ requestHeaders.set(key, value);
8179
+ });
8180
+ } else {
8181
+ const token = await getAuthToken();
8182
+ if (token) {
8183
+ const trimmedToken = token.trim();
8184
+ requestHeaders.set("X-Auth-Token", trimmedToken);
8185
+ requestHeaders.set("x-auth-token", trimmedToken);
8186
+ }
8152
8187
  }
8153
8188
  }
8154
8189
  const fetchOptionsFinal = {
@@ -8440,7 +8475,8 @@ async function manageConsentServer(params) {
8440
8475
  params.dataElementUuids,
8441
8476
  params.productUuid,
8442
8477
  params.noticeUuid,
8443
- params.dataElements
8478
+ params.dataElements,
8479
+ params.language
8444
8480
  );
8445
8481
  if (result && typeof result === "object" && "success" in result) {
8446
8482
  return Boolean(result.success);
@@ -8886,6 +8922,7 @@ var MAX_REFRESH_BACKOFF_MS = 3e5;
8886
8922
  var REFRESH_TOKEN_STORAGE_KEY = "redacto_pc_refresh_token";
8887
8923
  var LEGACY_REFRESH_TOKEN_COOKIE = "refresh_token";
8888
8924
  var FORM_PICKER_GROUP_LIMIT = 100;
8925
+ var LEGACY_PRODUCT_GROUP_UUID = "__legacy_flat_purposes__";
8889
8926
  var POLL_INTERVAL = 3e4;
8890
8927
  var NOTIFICATION_PAGE_SIZE = 10;
8891
8928
  var NOTIFICATION_DROPDOWN_LIMIT = 5;
@@ -9113,6 +9150,9 @@ var getInitialState = (slug) => {
9113
9150
  };
9114
9151
  var checkAndRefreshAuth = async (expectedSlug, organizationId, workspaceId, consentClient) => {
9115
9152
  if (typeof window === "undefined") return false;
9153
+ if (getSandboxConfig()) {
9154
+ return true;
9155
+ }
9116
9156
  const accessToken = sessionStorage.getItem("access_token");
9117
9157
  const email = sessionStorage.getItem("email");
9118
9158
  const orgSlug = sessionStorage.getItem("pc_org_slug");
@@ -9223,6 +9263,10 @@ var signOutPrivacyCenter = () => {
9223
9263
  };
9224
9264
  var ensureValidToken = async (organizationId, workspaceId, slug, authContext, consentClient) => {
9225
9265
  if (typeof window === "undefined") return null;
9266
+ const sandbox = getSandboxConfig();
9267
+ if (sandbox) {
9268
+ return sandbox.token;
9269
+ }
9226
9270
  const accessToken = (authContext == null ? void 0 : authContext.accessToken) || sessionStorage.getItem("access_token");
9227
9271
  if (accessToken && typeof accessToken === "string" && accessToken.trim() !== "" && !isJwtExpired(accessToken, TOKEN_EXPIRY_BUFFER_SECONDS)) {
9228
9272
  return accessToken;
@@ -9551,7 +9595,8 @@ var manageConsent = async ({
9551
9595
  dataElementUuids,
9552
9596
  productUuid,
9553
9597
  noticeUuid,
9554
- dataElements
9598
+ dataElements,
9599
+ language
9555
9600
  }) => {
9556
9601
  try {
9557
9602
  const accessToken = await ensureValidToken(organizationId, workspaceId, void 0, authContext, consentClient);
@@ -9570,7 +9615,8 @@ var manageConsent = async ({
9570
9615
  dataElementUuids,
9571
9616
  productUuid,
9572
9617
  noticeUuid,
9573
- dataElements
9618
+ dataElements,
9619
+ language
9574
9620
  });
9575
9621
  return result;
9576
9622
  } catch (error) {
@@ -9796,6 +9842,45 @@ function useCurrentLanguage() {
9796
9842
  import { createContext as createContext2, useContext as useContext2, useState, useEffect, useCallback as useCallback2, useMemo } from "react";
9797
9843
  import { jsx as jsx3 } from "react/jsx-runtime";
9798
9844
  var AuthContext = createContext2(null);
9845
+ var seedSessionStorage = (data) => {
9846
+ if (typeof window === "undefined") {
9847
+ return;
9848
+ }
9849
+ if (data.accessToken) sessionStorage.setItem("access_token", data.accessToken);
9850
+ if (data.orgId) sessionStorage.setItem("pc_org_id", data.orgId);
9851
+ if (data.workspaceId) sessionStorage.setItem("pc_workspace_id", data.workspaceId);
9852
+ if (data.slug) sessionStorage.setItem("pc_org_slug", data.slug);
9853
+ if (data.contact) sessionStorage.setItem("email", data.contact);
9854
+ };
9855
+ var configureSandbox = (props) => {
9856
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
9857
+ const token = (_a = props.token) == null ? void 0 : _a.trim();
9858
+ if (!token) {
9859
+ setSandboxConfig(null);
9860
+ return false;
9861
+ }
9862
+ const organisationUuid = (_c = (_b = props.organisationUuid) == null ? void 0 : _b.trim()) != null ? _c : "";
9863
+ const workspaceUuid = (_e = (_d = props.workspaceUuid) == null ? void 0 : _d.trim()) != null ? _e : "";
9864
+ const ucic = (_g = (_f = props.sandboxUcic) == null ? void 0 : _f.trim()) != null ? _g : "";
9865
+ const subject = (_i = (_h = props.sandboxSubject) == null ? void 0 : _h.trim()) != null ? _i : "";
9866
+ const slug = (_k = (_j = props.slug) == null ? void 0 : _j.trim()) != null ? _k : "";
9867
+ setSandboxConfig({
9868
+ token,
9869
+ ucic: ucic || void 0,
9870
+ subject,
9871
+ organisationUuid,
9872
+ workspaceUuid,
9873
+ slug
9874
+ });
9875
+ seedSessionStorage({
9876
+ accessToken: token,
9877
+ orgId: organisationUuid,
9878
+ workspaceId: workspaceUuid,
9879
+ slug,
9880
+ contact: ucic || subject
9881
+ });
9882
+ return true;
9883
+ };
9799
9884
  var syncJwtDataToSessionStorage = (accessToken) => {
9800
9885
  if (typeof window === "undefined") return;
9801
9886
  const decoded = decodeJwtToken(accessToken);
@@ -9803,44 +9888,49 @@ var syncJwtDataToSessionStorage = (accessToken) => {
9803
9888
  return;
9804
9889
  }
9805
9890
  const contact = resolveContactFromJwt(decoded) || sessionStorage.getItem("email") || (typeof localStorage !== "undefined" ? localStorage.getItem("userEmail") : null);
9806
- if (contact && typeof contact === "string") {
9807
- sessionStorage.setItem("email", contact);
9808
- }
9809
- const orgUuid = decoded.organisation_uuid;
9810
- if (orgUuid && typeof orgUuid === "string") {
9811
- sessionStorage.setItem("pc_org_id", orgUuid);
9812
- }
9813
- const workspaceUuid = decoded.workspace_uuid;
9814
- if (workspaceUuid && typeof workspaceUuid === "string") {
9815
- sessionStorage.setItem("pc_workspace_id", workspaceUuid);
9816
- }
9817
- const orgSlug = decoded.organisation_slug;
9818
- if (orgSlug && typeof orgSlug === "string") {
9819
- sessionStorage.setItem("pc_org_slug", orgSlug);
9820
- }
9891
+ seedSessionStorage({
9892
+ orgId: typeof decoded.organisation_uuid === "string" ? decoded.organisation_uuid : void 0,
9893
+ workspaceId: typeof decoded.workspace_uuid === "string" ? decoded.workspace_uuid : void 0,
9894
+ slug: typeof decoded.organisation_slug === "string" ? decoded.organisation_slug : void 0,
9895
+ contact: typeof contact === "string" ? contact : void 0
9896
+ });
9821
9897
  };
9822
- var AuthProvider = ({
9823
- children,
9824
- accessToken: initialAccessToken,
9825
- refreshToken: initialRefreshToken,
9826
- onError
9827
- }) => {
9898
+ var AuthProvider = (props) => {
9899
+ const {
9900
+ children,
9901
+ accessToken: initialAccessToken,
9902
+ refreshToken: initialRefreshToken,
9903
+ token: sandboxToken,
9904
+ sandboxUcic,
9905
+ sandboxSubject,
9906
+ organisationUuid,
9907
+ workspaceUuid,
9908
+ slug,
9909
+ onError
9910
+ } = props;
9911
+ const [sandboxActive] = useState(() => configureSandbox(props));
9828
9912
  const [accessToken, setAccessToken] = useState(() => {
9913
+ if (sandboxActive) {
9914
+ return sandboxToken != null ? sandboxToken : "";
9915
+ }
9829
9916
  if (initialAccessToken && typeof initialAccessToken === "string" && initialAccessToken.trim() !== "") {
9830
9917
  if (typeof window !== "undefined") {
9831
9918
  sessionStorage.setItem("access_token", initialAccessToken);
9832
9919
  syncJwtDataToSessionStorage(initialAccessToken);
9833
9920
  }
9834
9921
  }
9835
- return initialAccessToken;
9922
+ return initialAccessToken != null ? initialAccessToken : "";
9836
9923
  });
9837
9924
  const [refreshToken, setRefreshToken] = useState(() => {
9925
+ if (sandboxActive) {
9926
+ return "";
9927
+ }
9838
9928
  if (initialRefreshToken && typeof initialRefreshToken === "string" && initialRefreshToken.trim() !== "") {
9839
9929
  if (typeof window !== "undefined") {
9840
9930
  setRefreshTokenCookie(initialRefreshToken);
9841
9931
  }
9842
9932
  }
9843
- return initialRefreshToken;
9933
+ return initialRefreshToken != null ? initialRefreshToken : "";
9844
9934
  });
9845
9935
  const [sessionExpired, setSessionExpired] = useState(false);
9846
9936
  const markSessionExpired = useCallback2(() => setSessionExpired(true), []);
@@ -9849,6 +9939,9 @@ var AuthProvider = ({
9849
9939
  return () => setSessionExpiredListener(null);
9850
9940
  }, [markSessionExpired]);
9851
9941
  useEffect(() => {
9942
+ if (sandboxActive) {
9943
+ return;
9944
+ }
9852
9945
  if (initialAccessToken && typeof initialAccessToken === "string" && initialAccessToken.trim() !== "") {
9853
9946
  setAccessToken(initialAccessToken);
9854
9947
  if (typeof window !== "undefined") {
@@ -9856,8 +9949,11 @@ var AuthProvider = ({
9856
9949
  syncJwtDataToSessionStorage(initialAccessToken);
9857
9950
  }
9858
9951
  }
9859
- }, [initialAccessToken]);
9952
+ }, [initialAccessToken, sandboxActive]);
9860
9953
  useEffect(() => {
9954
+ if (sandboxActive) {
9955
+ return;
9956
+ }
9861
9957
  if (initialRefreshToken && typeof initialRefreshToken === "string" && initialRefreshToken.trim() !== "") {
9862
9958
  setRefreshToken(initialRefreshToken);
9863
9959
  setSessionExpired(false);
@@ -9865,7 +9961,14 @@ var AuthProvider = ({
9865
9961
  setRefreshTokenCookie(initialRefreshToken);
9866
9962
  }
9867
9963
  }
9868
- }, [initialRefreshToken]);
9964
+ }, [initialRefreshToken, sandboxActive]);
9965
+ useEffect(() => {
9966
+ if (!sandboxActive) {
9967
+ return;
9968
+ }
9969
+ configureSandbox(props);
9970
+ return () => setSandboxConfig(null);
9971
+ }, [sandboxActive, sandboxToken, sandboxUcic, sandboxSubject, organisationUuid, workspaceUuid, slug]);
9869
9972
  const updateTokens = useCallback2((newAccessToken, newRefreshToken) => {
9870
9973
  setAccessToken(newAccessToken);
9871
9974
  if (newRefreshToken) {
@@ -9902,7 +10005,8 @@ import { createContext as createContext3, useContext as useContext3, useMemo as
9902
10005
 
9903
10006
  // src/RedactoPrivacyCenter/api/client.ts
9904
10007
  function createConsentClient(baseUrl, ledgerBaseUrl) {
9905
- const useLedger = Boolean(ledgerBaseUrl);
10008
+ const ledgerConfigured = Boolean(ledgerBaseUrl);
10009
+ const useLedger = () => ledgerConfigured && !isSandboxMode();
9906
10010
  const ledgerBase = (ledgerBaseUrl != null ? ledgerBaseUrl : "").replace(/\/$/, "");
9907
10011
  async function privacyCenterApiFetch(url, options) {
9908
10012
  const { authToken, getAuthToken, headers = {}, ...fetchOptions } = options;
@@ -9927,11 +10031,18 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
9927
10031
  );
9928
10032
  }
9929
10033
  }
9930
- const token = authToken || (getAuthToken ? await getAuthToken() : null);
9931
- if (token) {
9932
- const trimmedToken = token.trim();
9933
- const bearerToken = trimmedToken.startsWith("Bearer ") ? trimmedToken : `Bearer ${trimmedToken}`;
9934
- requestHeaders.set("Authorization", bearerToken);
10034
+ const sandboxHeaders = sandboxAuthHeaders();
10035
+ if (sandboxHeaders) {
10036
+ Object.entries(sandboxHeaders).forEach(([key, value]) => {
10037
+ requestHeaders.set(key, value);
10038
+ });
10039
+ } else {
10040
+ const token = authToken || (getAuthToken ? await getAuthToken() : null);
10041
+ if (token) {
10042
+ const trimmedToken = token.trim();
10043
+ const bearerToken = trimmedToken.startsWith("Bearer ") ? trimmedToken : `Bearer ${trimmedToken}`;
10044
+ requestHeaders.set("Authorization", bearerToken);
10045
+ }
9935
10046
  }
9936
10047
  const fetchOptionsFinal = {
9937
10048
  ...fetchOptions,
@@ -9997,7 +10108,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
9997
10108
  return `${baseUrl}/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}/dsar/privacy-center${path}`;
9998
10109
  }
9999
10110
  function ledgerUrl(baseRequest, path) {
10000
- if (!useLedger) {
10111
+ if (!useLedger()) {
10001
10112
  throw new Error("ledgerUrl called without a configured ledgerBaseUrl");
10002
10113
  }
10003
10114
  return `${ledgerBase}/public/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}${path}`;
@@ -10006,11 +10117,30 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10006
10117
  return privacyCenterUrl(baseRequest, `/cases/${caseUuid}${path}`);
10007
10118
  }
10008
10119
  function notificationUrl(baseRequest, path = "") {
10009
- return privacyCenterUrl(baseRequest, `/notifications${path}`);
10120
+ const identitySuffix = sandboxIdentitySuffix();
10121
+ if (!identitySuffix) {
10122
+ return privacyCenterUrl(baseRequest, `/notifications${path}`);
10123
+ }
10124
+ const separator = path.includes("?") ? `&${identitySuffix.slice(1)}` : identitySuffix;
10125
+ return privacyCenterUrl(baseRequest, `/notifications${path}${separator}`);
10010
10126
  }
10011
10127
  function resolveAuthToken(authToken, baseRequest) {
10012
10128
  return authToken || baseRequest.authToken;
10013
10129
  }
10130
+ function appendSandboxIdentity(queryParams) {
10131
+ const identity = sandboxQueryIdentity();
10132
+ if (identity) {
10133
+ Object.entries(identity).forEach(([key, value]) => {
10134
+ queryParams.append(key, value);
10135
+ });
10136
+ }
10137
+ }
10138
+ function sandboxIdentitySuffix() {
10139
+ const queryParams = new URLSearchParams();
10140
+ appendSandboxIdentity(queryParams);
10141
+ const queryString = queryParams.toString();
10142
+ return queryString ? `?${queryString}` : "";
10143
+ }
10014
10144
  return {
10015
10145
  /**
10016
10146
  * Get form data (privacy center)
@@ -10042,18 +10172,20 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10042
10172
  async createCaseRequest(baseRequest, payload, authToken, options) {
10043
10173
  const url = privacyCenterUrl(baseRequest, "/case");
10044
10174
  const { useSessionAuth = false, getAuthToken, ...fetchOptions } = options || {};
10175
+ const contact = sandboxContact();
10176
+ const requestPayload = contact && payload && typeof payload === "object" ? { ...payload, contact } : payload;
10045
10177
  if (useSessionAuth) {
10046
10178
  return apiFetch(url, {
10047
10179
  ...fetchOptions,
10048
10180
  method: "POST",
10049
- body: JSON.stringify(payload),
10181
+ body: JSON.stringify(requestPayload),
10050
10182
  getAuthToken
10051
10183
  });
10052
10184
  }
10053
10185
  return privacyCenterApiFetch(url, {
10054
10186
  ...fetchOptions,
10055
10187
  method: "POST",
10056
- body: JSON.stringify(payload),
10188
+ body: JSON.stringify(requestPayload),
10057
10189
  authToken: resolveAuthToken(authToken, baseRequest)
10058
10190
  });
10059
10191
  },
@@ -10134,9 +10266,10 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10134
10266
  if (params.status) queryParams.append("status", params.status);
10135
10267
  if (params.product_uuid) queryParams.append("product_uuid", params.product_uuid);
10136
10268
  if (params.language) queryParams.append("language", params.language);
10269
+ appendSandboxIdentity(queryParams);
10137
10270
  const queryString = queryParams.toString();
10138
10271
  const suffix = `/user-consents${queryString ? `?${queryString}` : ""}`;
10139
- const url = useLedger ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10272
+ const url = useLedger() ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10140
10273
  return privacyCenterApiFetch(url, {
10141
10274
  ...options,
10142
10275
  method: "GET",
@@ -10156,9 +10289,10 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10156
10289
  if (params.search) queryParams.append("search", params.search);
10157
10290
  if (params.language) queryParams.append("language", params.language);
10158
10291
  if (params.nominator_uuid) queryParams.append("nominator_uuid", params.nominator_uuid);
10292
+ appendSandboxIdentity(queryParams);
10159
10293
  const queryString = queryParams.toString();
10160
10294
  const suffix = `/user-consents/${productUuid}/purposes${queryString ? `?${queryString}` : ""}`;
10161
- const url = useLedger ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10295
+ const url = useLedger() ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10162
10296
  return privacyCenterApiFetch(url, {
10163
10297
  ...options,
10164
10298
  method: "GET",
@@ -10181,8 +10315,8 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10181
10315
  * Without a ledger, the legacy Python `/manage-consent?status=` endpoint is
10182
10316
  * used with its `{ purpose_uuid, contact, ... }` payload.
10183
10317
  */
10184
- async manageConsent(baseRequest, purposeId, contact, status, authToken, options, nominatorContact, dataElementUuids, productUuid, noticeUuid, dataElements) {
10185
- if (!useLedger) {
10318
+ async manageConsent(baseRequest, purposeId, contact, status, authToken, options, nominatorContact, dataElementUuids, productUuid, noticeUuid, dataElements, language) {
10319
+ if (!useLedger()) {
10186
10320
  const url2 = privacyCenterUrl(baseRequest, `/manage-consent?status=${status}`);
10187
10321
  const body2 = { purpose_uuid: purposeId, contact };
10188
10322
  if (nominatorContact) {
@@ -10194,6 +10328,9 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10194
10328
  if (productUuid) {
10195
10329
  body2.product_uuid = productUuid;
10196
10330
  }
10331
+ if (language) {
10332
+ body2.language = language;
10333
+ }
10197
10334
  return privacyCenterApiFetch(url2, {
10198
10335
  ...options,
10199
10336
  method: "POST",
@@ -10228,7 +10365,8 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10228
10365
  selected: purposeSelected,
10229
10366
  data_elements: elements
10230
10367
  }
10231
- ]
10368
+ ],
10369
+ ...language ? { language } : {}
10232
10370
  };
10233
10371
  const url = ledgerUrl(baseRequest, "/submit-consent");
10234
10372
  return privacyCenterApiFetch(url, {
@@ -10246,6 +10384,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10246
10384
  if (offset !== void 0) queryParams.append("offset", offset.toString());
10247
10385
  if (limit !== void 0) queryParams.append("limit", limit.toString());
10248
10386
  if (language) queryParams.append("language", language);
10387
+ appendSandboxIdentity(queryParams);
10249
10388
  const queryString = queryParams.toString();
10250
10389
  const url = privacyCenterUrl(baseRequest, `/activities${queryString ? `?${queryString}` : ""}`);
10251
10390
  return privacyCenterApiFetch(url, {
@@ -10295,7 +10434,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10295
10434
  if (params.language) queryParams.append("language", params.language);
10296
10435
  const queryString = queryParams.toString();
10297
10436
  const receiptsSuffix = `/receipts${queryString ? `?${queryString}` : ""}`;
10298
- const url = useLedger ? ledgerUrl(baseRequest, receiptsSuffix) : privacyCenterUrl(baseRequest, receiptsSuffix);
10437
+ const url = useLedger() ? ledgerUrl(baseRequest, receiptsSuffix) : privacyCenterUrl(baseRequest, receiptsSuffix);
10299
10438
  return privacyCenterApiFetch(url, {
10300
10439
  ...options,
10301
10440
  method: "GET",
@@ -10310,11 +10449,16 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10310
10449
  * and the Authorization header must be sent (anchor navigation wouldn't carry it).
10311
10450
  */
10312
10451
  async getReceiptPdf(baseRequest, receiptUuid, authToken) {
10313
- const url = useLedger ? ledgerUrl(baseRequest, `/receipts/${receiptUuid}/download`) : privacyCenterUrl(baseRequest, `/receipts/${receiptUuid}/pdf`);
10452
+ const url = useLedger() ? ledgerUrl(baseRequest, `/receipts/${receiptUuid}/download`) : privacyCenterUrl(baseRequest, `/receipts/${receiptUuid}/pdf`);
10314
10453
  const token = resolveAuthToken(authToken, baseRequest);
10315
10454
  const requestHeaders = new Headers();
10316
10455
  requestHeaders.set("Accept", "application/pdf");
10317
- if (token) {
10456
+ const sandboxHeaders = sandboxAuthHeaders();
10457
+ if (sandboxHeaders) {
10458
+ Object.entries(sandboxHeaders).forEach(([key, value]) => {
10459
+ requestHeaders.set(key, value);
10460
+ });
10461
+ } else if (token) {
10318
10462
  const trimmedToken = token.trim();
10319
10463
  requestHeaders.set(
10320
10464
  "Authorization",
@@ -10345,6 +10489,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10345
10489
  if (offset !== void 0) queryParams.append("offset", offset.toString());
10346
10490
  if (limit !== void 0) queryParams.append("limit", limit.toString());
10347
10491
  if (language) queryParams.append("language", language);
10492
+ appendSandboxIdentity(queryParams);
10348
10493
  const queryString = queryParams.toString();
10349
10494
  const url = privacyCenterUrl(baseRequest, `/cases?${queryString}`);
10350
10495
  return privacyCenterApiFetch(url, {
@@ -10357,7 +10502,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10357
10502
  * Get messages for a case (privacy center)
10358
10503
  */
10359
10504
  async getCaseMessages(baseRequest, caseUuid, authToken) {
10360
- const url = caseUrl(baseRequest, caseUuid, "/messages");
10505
+ const url = caseUrl(baseRequest, caseUuid, `/messages${sandboxIdentitySuffix()}`);
10361
10506
  return privacyCenterApiFetch(url, {
10362
10507
  authToken: resolveAuthToken(authToken, baseRequest)
10363
10508
  });
@@ -10366,7 +10511,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10366
10511
  * Send a message on a case (privacy center)
10367
10512
  */
10368
10513
  async sendCaseMessage(baseRequest, caseUuid, body, documentUuids, authToken) {
10369
- const url = caseUrl(baseRequest, caseUuid, "/messages");
10514
+ const url = caseUrl(baseRequest, caseUuid, `/messages${sandboxIdentitySuffix()}`);
10370
10515
  return privacyCenterApiFetch(url, {
10371
10516
  method: "POST",
10372
10517
  body: JSON.stringify({ body, document_uuids: documentUuids }),
@@ -10377,7 +10522,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10377
10522
  * Upload a document on a case (multipart/form-data, privacy center)
10378
10523
  */
10379
10524
  async uploadCaseDocument(baseRequest, caseUuid, file, authToken) {
10380
- const url = caseUrl(baseRequest, caseUuid, "/upload-document");
10525
+ const url = caseUrl(baseRequest, caseUuid, `/upload-document${sandboxIdentitySuffix()}`);
10381
10526
  const formData = new FormData();
10382
10527
  formData.append("file", file, file.name);
10383
10528
  formData.append("payload", JSON.stringify({ metadata: null }));
@@ -15177,6 +15322,10 @@ var SelectUserGate = ({ children }) => {
15177
15322
  const tokenOrgUserId = ((_d = (_c = decodeJwtToken(accessToken)) == null ? void 0 : _c.user_data) == null ? void 0 : _d.org_user_id) || "";
15178
15323
  useEffect17(() => {
15179
15324
  let cancelled = false;
15325
+ if (isSandboxMode()) {
15326
+ setPhase("resolved");
15327
+ return;
15328
+ }
15180
15329
  if (!organizationId || !workspaceId || !accessToken) {
15181
15330
  setPhase("resolved");
15182
15331
  return;
@@ -18363,7 +18512,8 @@ function ConsentManager({ variant }) {
18363
18512
  dataElementUuids,
18364
18513
  productUuid,
18365
18514
  noticeUuid,
18366
- dataElements
18515
+ dataElements,
18516
+ language: langParam
18367
18517
  });
18368
18518
  if (response) {
18369
18519
  toast.success(successMessages[action]);
@@ -18392,7 +18542,7 @@ function ConsentManager({ variant }) {
18392
18542
  handleCloseModal();
18393
18543
  }
18394
18544
  },
18395
- [organizationId, workspaceId, contact, fetchData, handleCloseModal, t, authContext, consentClient, selectedRecord]
18545
+ [organizationId, workspaceId, contact, fetchData, handleCloseModal, t, authContext, consentClient, selectedRecord, langParam]
18396
18546
  );
18397
18547
  const getVar26 = (varName) => `var(${varName})`;
18398
18548
  const directBadge = (_c = (_b = consentDetail == null ? void 0 : consentDetail.status_summary) == null ? void 0 : _b.direct_purposes) != null ? _c : "";
@@ -18928,23 +19078,36 @@ var consentGroupToFormProductGroup = (group) => {
18928
19078
  };
18929
19079
  };
18930
19080
  var purposeItemToFormPurpose = (purpose) => {
18931
- var _a, _b;
19081
+ var _a, _b, _c, _d, _e, _f;
18932
19082
  return {
18933
- uuid: purpose.purpose_uuid,
18934
- purpose_uuid: purpose.purpose_uuid,
19083
+ // The ledger keys purposes as `purpose_uuid`; the legacy Python
19084
+ // user-consents payload keys some of them as `uuid`. Accept either so the
19085
+ // picker and the submitted `purpose_uuid` resolve on both backends.
19086
+ uuid: (_b = (_a = purpose.purpose_uuid) != null ? _a : purpose.uuid) != null ? _b : "",
19087
+ purpose_uuid: (_d = (_c = purpose.purpose_uuid) != null ? _c : purpose.uuid) != null ? _d : "",
18935
19088
  name: purpose.name,
18936
- description: (_a = purpose.description) != null ? _a : "",
19089
+ description: (_e = purpose.description) != null ? _e : "",
18937
19090
  industries: "",
18938
19091
  selected: false,
18939
19092
  given_consent: false,
18940
19093
  status: purpose.status,
18941
19094
  validity: null,
18942
19095
  enabled: true,
18943
- data_elements: ((_b = purpose.data_elements) != null ? _b : []).map(
19096
+ data_elements: ((_f = purpose.data_elements) != null ? _f : []).map(
18944
19097
  consentDataElementToFormDataElement
18945
19098
  )
18946
19099
  };
18947
19100
  };
19101
+ var legacyFlatGroup = (form, label) => {
19102
+ var _a;
19103
+ return {
19104
+ product_uuid: LEGACY_PRODUCT_GROUP_UUID,
19105
+ product_name: label,
19106
+ product_description: null,
19107
+ nominator: null,
19108
+ purposes: ((_a = form.purposes) != null ? _a : []).map((wrapper) => wrapper == null ? void 0 : wrapper.purpose).filter((purpose) => Boolean(purpose))
19109
+ };
19110
+ };
18948
19111
  var consentDataElementToFormDataElement = (element) => ({
18949
19112
  uuid: element.uuid,
18950
19113
  name: element.name,
@@ -20101,7 +20264,7 @@ function Form({
20101
20264
  const [isSubmitted, setIsSubmitted] = useState24(false);
20102
20265
  const { t } = useTranslation34();
20103
20266
  const { accessToken, refreshToken, onError, updateTokens } = useAuth();
20104
- const { consentClient, baseUrl, ledgerBaseUrl } = useBaseUrl();
20267
+ const { consentClient, baseUrl } = useBaseUrl();
20105
20268
  const organizationId = organization == null ? void 0 : organization.uuid;
20106
20269
  const workspaceId = (_a = organization == null ? void 0 : organization.workspaces[0]) == null ? void 0 : _a.uuid;
20107
20270
  const authContext = useMemo15(() => ({
@@ -20163,8 +20326,19 @@ function Form({
20163
20326
  if (!data) {
20164
20327
  return [];
20165
20328
  }
20166
- return [...(_a2 = data.direct_groups) != null ? _a2 : [], ...(_b2 = data.nominated_groups) != null ? _b2 : []];
20167
- }, [data]);
20329
+ const groups = [
20330
+ ...(_a2 = data.direct_groups) != null ? _a2 : [],
20331
+ ...(_b2 = data.nominated_groups) != null ? _b2 : []
20332
+ ];
20333
+ if (groups.length > 0) {
20334
+ return groups;
20335
+ }
20336
+ const flatGroup = legacyFlatGroup(data, t("yourData"));
20337
+ if (buildGroupPurposes(flatGroup).length === 0) {
20338
+ return [];
20339
+ }
20340
+ return [flatGroup];
20341
+ }, [data, t]);
20168
20342
  const skipProductStep = allGroups.length === 1;
20169
20343
  const selectedGroup = useMemo15(() => {
20170
20344
  var _a2, _b2;
@@ -20182,10 +20356,10 @@ function Form({
20182
20356
  },
20183
20357
  []
20184
20358
  );
20185
- const withLedgerPickerGroups = useCallback15(
20359
+ const withUserConsentPickerGroups = useCallback15(
20186
20360
  async (form, language) => {
20187
20361
  var _a2, _b2;
20188
- if (!ledgerBaseUrl || isPopup || isCaseManagementContext || !organizationId || !workspaceId) {
20362
+ if (isPopup || isCaseManagementContext || !organizationId || !workspaceId) {
20189
20363
  return form;
20190
20364
  }
20191
20365
  const consents = await fetchUserConsents({
@@ -20200,19 +20374,18 @@ function Form({
20200
20374
  nominatedLimit: FORM_PICKER_GROUP_LIMIT,
20201
20375
  language
20202
20376
  });
20203
- if (!consents) {
20377
+ const direct = (_a2 = consents == null ? void 0 : consents.direct) != null ? _a2 : [];
20378
+ const nominated = (_b2 = consents == null ? void 0 : consents.nominated) != null ? _b2 : [];
20379
+ if (direct.length === 0 && nominated.length === 0) {
20204
20380
  return form;
20205
20381
  }
20206
20382
  return {
20207
20383
  ...form,
20208
- direct_groups: ((_a2 = consents.direct) != null ? _a2 : []).map(consentGroupToFormProductGroup),
20209
- nominated_groups: ((_b2 = consents.nominated) != null ? _b2 : []).map(
20210
- consentGroupToFormProductGroup
20211
- )
20384
+ direct_groups: direct.map(consentGroupToFormProductGroup),
20385
+ nominated_groups: nominated.map(consentGroupToFormProductGroup)
20212
20386
  };
20213
20387
  },
20214
20388
  [
20215
- ledgerBaseUrl,
20216
20389
  isPopup,
20217
20390
  isCaseManagementContext,
20218
20391
  organizationId,
@@ -20249,7 +20422,7 @@ function Form({
20249
20422
  toast.info(t("translationNotAvailable"));
20250
20423
  return;
20251
20424
  }
20252
- setData(await withLedgerPickerGroups(translatedFormData, langValue));
20425
+ setData(await withUserConsentPickerGroups(translatedFormData, langValue));
20253
20426
  if (translatedFormData.grievance_options) {
20254
20427
  const currentGrievanceSelections = { ...selectedGrievances };
20255
20428
  setGrievanceOptions(translatedFormData.grievance_options);
@@ -20265,7 +20438,7 @@ function Form({
20265
20438
  } finally {
20266
20439
  setIsTranslating(false);
20267
20440
  }
20268
- }, [organizationId, workspaceId, data, formData.contact, isPopup, isCaseManagementContext, authContext, consentClient, selectedGrievances, t, withLedgerPickerGroups]);
20441
+ }, [organizationId, workspaceId, data, formData.contact, isPopup, isCaseManagementContext, authContext, consentClient, selectedGrievances, t, withUserConsentPickerGroups]);
20269
20442
  useEffect24(() => {
20270
20443
  if (!skipProductStep) {
20271
20444
  setSelectedProductKey(null);
@@ -20371,7 +20544,7 @@ function Form({
20371
20544
  console.warn("No purposes with data elements found in API response");
20372
20545
  }
20373
20546
  }
20374
- const pickerData = await withLedgerPickerGroups(
20547
+ const pickerData = await withUserConsentPickerGroups(
20375
20548
  displayData,
20376
20549
  langParam || void 0
20377
20550
  );
@@ -20395,7 +20568,7 @@ function Form({
20395
20568
  }
20396
20569
  };
20397
20570
  void initializePrivacyCenterForm();
20398
- }, [organizationId, workspaceId, isPopup, authContext, consentClient, withLedgerPickerGroups]);
20571
+ }, [organizationId, workspaceId, isPopup, authContext, consentClient, withUserConsentPickerGroups]);
20399
20572
  const getEnglishDataElementName = useCallback15((translatedName) => {
20400
20573
  var _a2, _b2, _c2;
20401
20574
  if (!((_a2 = englishDataRef.current) == null ? void 0 : _a2.purposes)) {
@@ -20457,7 +20630,8 @@ function Form({
20457
20630
  return;
20458
20631
  }
20459
20632
  const isProductScoped = isProductScopedRequestType(requestType);
20460
- const anchorGroup = isProductScoped ? selectedGroup : null;
20633
+ const isLegacyFlatSelection = (selectedGroup == null ? void 0 : selectedGroup.product_uuid) === LEGACY_PRODUCT_GROUP_UUID;
20634
+ const anchorGroup = isProductScoped && !isLegacyFlatSelection ? selectedGroup : null;
20461
20635
  const requestDetails = {
20462
20636
  purposes: [],
20463
20637
  correction_data: [],
@@ -27928,6 +28102,12 @@ function RedactoPrivacyCenter({
27928
28102
  slug,
27929
28103
  accessToken,
27930
28104
  refreshToken,
28105
+ token,
28106
+ email,
28107
+ mobile,
28108
+ ucic,
28109
+ organisationUuid,
28110
+ workspaceUuid,
27931
28111
  onError,
27932
28112
  initialPage = "consent-manager",
27933
28113
  onBack
@@ -27937,6 +28117,12 @@ function RedactoPrivacyCenter({
27937
28117
  {
27938
28118
  accessToken,
27939
28119
  refreshToken,
28120
+ token,
28121
+ sandboxUcic: ucic,
28122
+ sandboxSubject: email || mobile,
28123
+ organisationUuid,
28124
+ workspaceUuid,
28125
+ slug,
27940
28126
  onError,
27941
28127
  children: /* @__PURE__ */ jsx92(NavigationProvider, { initialPage, children: /* @__PURE__ */ jsx92(PageChromeProvider, { children: /* @__PURE__ */ jsx92(PrivacyCenterLayout, { slug, onBack, children: /* @__PURE__ */ jsx92(PrivacyCenterHomePage, {}) }) }) })
27942
28128
  }