@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
@@ -8164,6 +8164,36 @@ var useOrganization = () => {
8164
8164
  // src/RedactoPrivacyCenter/context/DataAvailabilityContext.tsx
8165
8165
  var import_react5 = require("react");
8166
8166
 
8167
+ // src/shared/sandbox.ts
8168
+ var SANDBOX_TOKEN_HEADER = "X-Consent-Token";
8169
+
8170
+ // src/RedactoPrivacyCenter/lib/sandbox.ts
8171
+ var sandboxConfig = null;
8172
+ var setSandboxConfig = (config) => {
8173
+ sandboxConfig = config;
8174
+ };
8175
+ var getSandboxConfig = () => sandboxConfig;
8176
+ var isSandboxMode = () => sandboxConfig !== null;
8177
+ var sandboxAuthHeaders = () => {
8178
+ if (!sandboxConfig) {
8179
+ return null;
8180
+ }
8181
+ return {
8182
+ [SANDBOX_TOKEN_HEADER]: sandboxConfig.token
8183
+ };
8184
+ };
8185
+ var sandboxBodyIdentity = () => {
8186
+ if (!sandboxConfig) {
8187
+ return null;
8188
+ }
8189
+ if (sandboxConfig.ucic) {
8190
+ return { org_user_id: sandboxConfig.ucic };
8191
+ }
8192
+ return sandboxConfig.subject.includes("@") ? { primary_email: sandboxConfig.subject } : { primary_mobile: sandboxConfig.subject };
8193
+ };
8194
+ var sandboxQueryIdentity = () => sandboxBodyIdentity();
8195
+ var sandboxContact = () => sandboxConfig ? sandboxConfig.ucic || sandboxConfig.subject : null;
8196
+
8167
8197
  // src/RedactoPrivacyCenter/api/fetcher.ts
8168
8198
  var ApiError = class _ApiError extends Error {
8169
8199
  constructor(message, options = {}) {
@@ -8210,11 +8240,18 @@ async function apiFetch(url, options = {}) {
8210
8240
  }
8211
8241
  }
8212
8242
  if (getAuthToken) {
8213
- const token = await getAuthToken();
8214
- if (token) {
8215
- const trimmedToken = token.trim();
8216
- requestHeaders.set("X-Auth-Token", trimmedToken);
8217
- requestHeaders.set("x-auth-token", trimmedToken);
8243
+ const sandboxHeaders = sandboxAuthHeaders();
8244
+ if (sandboxHeaders) {
8245
+ Object.entries(sandboxHeaders).forEach(([key, value]) => {
8246
+ requestHeaders.set(key, value);
8247
+ });
8248
+ } else {
8249
+ const token = await getAuthToken();
8250
+ if (token) {
8251
+ const trimmedToken = token.trim();
8252
+ requestHeaders.set("X-Auth-Token", trimmedToken);
8253
+ requestHeaders.set("x-auth-token", trimmedToken);
8254
+ }
8218
8255
  }
8219
8256
  }
8220
8257
  const fetchOptionsFinal = {
@@ -8506,7 +8543,8 @@ async function manageConsentServer(params) {
8506
8543
  params.dataElementUuids,
8507
8544
  params.productUuid,
8508
8545
  params.noticeUuid,
8509
- params.dataElements
8546
+ params.dataElements,
8547
+ params.language
8510
8548
  );
8511
8549
  if (result && typeof result === "object" && "success" in result) {
8512
8550
  return Boolean(result.success);
@@ -8952,6 +8990,7 @@ var MAX_REFRESH_BACKOFF_MS = 3e5;
8952
8990
  var REFRESH_TOKEN_STORAGE_KEY = "redacto_pc_refresh_token";
8953
8991
  var LEGACY_REFRESH_TOKEN_COOKIE = "refresh_token";
8954
8992
  var FORM_PICKER_GROUP_LIMIT = 100;
8993
+ var LEGACY_PRODUCT_GROUP_UUID = "__legacy_flat_purposes__";
8955
8994
  var POLL_INTERVAL = 3e4;
8956
8995
  var NOTIFICATION_PAGE_SIZE = 10;
8957
8996
  var NOTIFICATION_DROPDOWN_LIMIT = 5;
@@ -9179,6 +9218,9 @@ var getInitialState = (slug) => {
9179
9218
  };
9180
9219
  var checkAndRefreshAuth = async (expectedSlug, organizationId, workspaceId, consentClient) => {
9181
9220
  if (typeof window === "undefined") return false;
9221
+ if (getSandboxConfig()) {
9222
+ return true;
9223
+ }
9182
9224
  const accessToken = sessionStorage.getItem("access_token");
9183
9225
  const email = sessionStorage.getItem("email");
9184
9226
  const orgSlug = sessionStorage.getItem("pc_org_slug");
@@ -9289,6 +9331,10 @@ var signOutPrivacyCenter = () => {
9289
9331
  };
9290
9332
  var ensureValidToken = async (organizationId, workspaceId, slug, authContext, consentClient) => {
9291
9333
  if (typeof window === "undefined") return null;
9334
+ const sandbox = getSandboxConfig();
9335
+ if (sandbox) {
9336
+ return sandbox.token;
9337
+ }
9292
9338
  const accessToken = (authContext == null ? void 0 : authContext.accessToken) || sessionStorage.getItem("access_token");
9293
9339
  if (accessToken && typeof accessToken === "string" && accessToken.trim() !== "" && !isJwtExpired(accessToken, TOKEN_EXPIRY_BUFFER_SECONDS)) {
9294
9340
  return accessToken;
@@ -9617,7 +9663,8 @@ var manageConsent = async ({
9617
9663
  dataElementUuids,
9618
9664
  productUuid,
9619
9665
  noticeUuid,
9620
- dataElements
9666
+ dataElements,
9667
+ language
9621
9668
  }) => {
9622
9669
  try {
9623
9670
  const accessToken = await ensureValidToken(organizationId, workspaceId, void 0, authContext, consentClient);
@@ -9636,7 +9683,8 @@ var manageConsent = async ({
9636
9683
  dataElementUuids,
9637
9684
  productUuid,
9638
9685
  noticeUuid,
9639
- dataElements
9686
+ dataElements,
9687
+ language
9640
9688
  });
9641
9689
  return result;
9642
9690
  } catch (error) {
@@ -9862,6 +9910,45 @@ function useCurrentLanguage() {
9862
9910
  var import_react3 = require("react");
9863
9911
  var import_jsx_runtime3 = require("react/jsx-runtime");
9864
9912
  var AuthContext = (0, import_react3.createContext)(null);
9913
+ var seedSessionStorage = (data) => {
9914
+ if (typeof window === "undefined") {
9915
+ return;
9916
+ }
9917
+ if (data.accessToken) sessionStorage.setItem("access_token", data.accessToken);
9918
+ if (data.orgId) sessionStorage.setItem("pc_org_id", data.orgId);
9919
+ if (data.workspaceId) sessionStorage.setItem("pc_workspace_id", data.workspaceId);
9920
+ if (data.slug) sessionStorage.setItem("pc_org_slug", data.slug);
9921
+ if (data.contact) sessionStorage.setItem("email", data.contact);
9922
+ };
9923
+ var configureSandbox = (props) => {
9924
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
9925
+ const token = (_a = props.token) == null ? void 0 : _a.trim();
9926
+ if (!token) {
9927
+ setSandboxConfig(null);
9928
+ return false;
9929
+ }
9930
+ const organisationUuid = (_c = (_b = props.organisationUuid) == null ? void 0 : _b.trim()) != null ? _c : "";
9931
+ const workspaceUuid = (_e = (_d = props.workspaceUuid) == null ? void 0 : _d.trim()) != null ? _e : "";
9932
+ const ucic = (_g = (_f = props.sandboxUcic) == null ? void 0 : _f.trim()) != null ? _g : "";
9933
+ const subject = (_i = (_h = props.sandboxSubject) == null ? void 0 : _h.trim()) != null ? _i : "";
9934
+ const slug = (_k = (_j = props.slug) == null ? void 0 : _j.trim()) != null ? _k : "";
9935
+ setSandboxConfig({
9936
+ token,
9937
+ ucic: ucic || void 0,
9938
+ subject,
9939
+ organisationUuid,
9940
+ workspaceUuid,
9941
+ slug
9942
+ });
9943
+ seedSessionStorage({
9944
+ accessToken: token,
9945
+ orgId: organisationUuid,
9946
+ workspaceId: workspaceUuid,
9947
+ slug,
9948
+ contact: ucic || subject
9949
+ });
9950
+ return true;
9951
+ };
9865
9952
  var syncJwtDataToSessionStorage = (accessToken) => {
9866
9953
  if (typeof window === "undefined") return;
9867
9954
  const decoded = decodeJwtToken(accessToken);
@@ -9869,44 +9956,49 @@ var syncJwtDataToSessionStorage = (accessToken) => {
9869
9956
  return;
9870
9957
  }
9871
9958
  const contact = resolveContactFromJwt(decoded) || sessionStorage.getItem("email") || (typeof localStorage !== "undefined" ? localStorage.getItem("userEmail") : null);
9872
- if (contact && typeof contact === "string") {
9873
- sessionStorage.setItem("email", contact);
9874
- }
9875
- const orgUuid = decoded.organisation_uuid;
9876
- if (orgUuid && typeof orgUuid === "string") {
9877
- sessionStorage.setItem("pc_org_id", orgUuid);
9878
- }
9879
- const workspaceUuid = decoded.workspace_uuid;
9880
- if (workspaceUuid && typeof workspaceUuid === "string") {
9881
- sessionStorage.setItem("pc_workspace_id", workspaceUuid);
9882
- }
9883
- const orgSlug = decoded.organisation_slug;
9884
- if (orgSlug && typeof orgSlug === "string") {
9885
- sessionStorage.setItem("pc_org_slug", orgSlug);
9886
- }
9959
+ seedSessionStorage({
9960
+ orgId: typeof decoded.organisation_uuid === "string" ? decoded.organisation_uuid : void 0,
9961
+ workspaceId: typeof decoded.workspace_uuid === "string" ? decoded.workspace_uuid : void 0,
9962
+ slug: typeof decoded.organisation_slug === "string" ? decoded.organisation_slug : void 0,
9963
+ contact: typeof contact === "string" ? contact : void 0
9964
+ });
9887
9965
  };
9888
- var AuthProvider = ({
9889
- children,
9890
- accessToken: initialAccessToken,
9891
- refreshToken: initialRefreshToken,
9892
- onError
9893
- }) => {
9966
+ var AuthProvider = (props) => {
9967
+ const {
9968
+ children,
9969
+ accessToken: initialAccessToken,
9970
+ refreshToken: initialRefreshToken,
9971
+ token: sandboxToken,
9972
+ sandboxUcic,
9973
+ sandboxSubject,
9974
+ organisationUuid,
9975
+ workspaceUuid,
9976
+ slug,
9977
+ onError
9978
+ } = props;
9979
+ const [sandboxActive] = (0, import_react3.useState)(() => configureSandbox(props));
9894
9980
  const [accessToken, setAccessToken] = (0, import_react3.useState)(() => {
9981
+ if (sandboxActive) {
9982
+ return sandboxToken != null ? sandboxToken : "";
9983
+ }
9895
9984
  if (initialAccessToken && typeof initialAccessToken === "string" && initialAccessToken.trim() !== "") {
9896
9985
  if (typeof window !== "undefined") {
9897
9986
  sessionStorage.setItem("access_token", initialAccessToken);
9898
9987
  syncJwtDataToSessionStorage(initialAccessToken);
9899
9988
  }
9900
9989
  }
9901
- return initialAccessToken;
9990
+ return initialAccessToken != null ? initialAccessToken : "";
9902
9991
  });
9903
9992
  const [refreshToken, setRefreshToken] = (0, import_react3.useState)(() => {
9993
+ if (sandboxActive) {
9994
+ return "";
9995
+ }
9904
9996
  if (initialRefreshToken && typeof initialRefreshToken === "string" && initialRefreshToken.trim() !== "") {
9905
9997
  if (typeof window !== "undefined") {
9906
9998
  setRefreshTokenCookie(initialRefreshToken);
9907
9999
  }
9908
10000
  }
9909
- return initialRefreshToken;
10001
+ return initialRefreshToken != null ? initialRefreshToken : "";
9910
10002
  });
9911
10003
  const [sessionExpired, setSessionExpired] = (0, import_react3.useState)(false);
9912
10004
  const markSessionExpired = (0, import_react3.useCallback)(() => setSessionExpired(true), []);
@@ -9915,6 +10007,9 @@ var AuthProvider = ({
9915
10007
  return () => setSessionExpiredListener(null);
9916
10008
  }, [markSessionExpired]);
9917
10009
  (0, import_react3.useEffect)(() => {
10010
+ if (sandboxActive) {
10011
+ return;
10012
+ }
9918
10013
  if (initialAccessToken && typeof initialAccessToken === "string" && initialAccessToken.trim() !== "") {
9919
10014
  setAccessToken(initialAccessToken);
9920
10015
  if (typeof window !== "undefined") {
@@ -9922,8 +10017,11 @@ var AuthProvider = ({
9922
10017
  syncJwtDataToSessionStorage(initialAccessToken);
9923
10018
  }
9924
10019
  }
9925
- }, [initialAccessToken]);
10020
+ }, [initialAccessToken, sandboxActive]);
9926
10021
  (0, import_react3.useEffect)(() => {
10022
+ if (sandboxActive) {
10023
+ return;
10024
+ }
9927
10025
  if (initialRefreshToken && typeof initialRefreshToken === "string" && initialRefreshToken.trim() !== "") {
9928
10026
  setRefreshToken(initialRefreshToken);
9929
10027
  setSessionExpired(false);
@@ -9931,7 +10029,14 @@ var AuthProvider = ({
9931
10029
  setRefreshTokenCookie(initialRefreshToken);
9932
10030
  }
9933
10031
  }
9934
- }, [initialRefreshToken]);
10032
+ }, [initialRefreshToken, sandboxActive]);
10033
+ (0, import_react3.useEffect)(() => {
10034
+ if (!sandboxActive) {
10035
+ return;
10036
+ }
10037
+ configureSandbox(props);
10038
+ return () => setSandboxConfig(null);
10039
+ }, [sandboxActive, sandboxToken, sandboxUcic, sandboxSubject, organisationUuid, workspaceUuid, slug]);
9935
10040
  const updateTokens = (0, import_react3.useCallback)((newAccessToken, newRefreshToken) => {
9936
10041
  setAccessToken(newAccessToken);
9937
10042
  if (newRefreshToken) {
@@ -9968,7 +10073,8 @@ var import_react4 = require("react");
9968
10073
 
9969
10074
  // src/RedactoPrivacyCenter/api/client.ts
9970
10075
  function createConsentClient(baseUrl, ledgerBaseUrl) {
9971
- const useLedger = Boolean(ledgerBaseUrl);
10076
+ const ledgerConfigured = Boolean(ledgerBaseUrl);
10077
+ const useLedger = () => ledgerConfigured && !isSandboxMode();
9972
10078
  const ledgerBase = (ledgerBaseUrl != null ? ledgerBaseUrl : "").replace(/\/$/, "");
9973
10079
  async function privacyCenterApiFetch(url, options) {
9974
10080
  const { authToken, getAuthToken, headers = {}, ...fetchOptions } = options;
@@ -9993,11 +10099,18 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
9993
10099
  );
9994
10100
  }
9995
10101
  }
9996
- const token = authToken || (getAuthToken ? await getAuthToken() : null);
9997
- if (token) {
9998
- const trimmedToken = token.trim();
9999
- const bearerToken = trimmedToken.startsWith("Bearer ") ? trimmedToken : `Bearer ${trimmedToken}`;
10000
- requestHeaders.set("Authorization", bearerToken);
10102
+ const sandboxHeaders = sandboxAuthHeaders();
10103
+ if (sandboxHeaders) {
10104
+ Object.entries(sandboxHeaders).forEach(([key, value]) => {
10105
+ requestHeaders.set(key, value);
10106
+ });
10107
+ } else {
10108
+ const token = authToken || (getAuthToken ? await getAuthToken() : null);
10109
+ if (token) {
10110
+ const trimmedToken = token.trim();
10111
+ const bearerToken = trimmedToken.startsWith("Bearer ") ? trimmedToken : `Bearer ${trimmedToken}`;
10112
+ requestHeaders.set("Authorization", bearerToken);
10113
+ }
10001
10114
  }
10002
10115
  const fetchOptionsFinal = {
10003
10116
  ...fetchOptions,
@@ -10063,7 +10176,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10063
10176
  return `${baseUrl}/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}/dsar/privacy-center${path}`;
10064
10177
  }
10065
10178
  function ledgerUrl(baseRequest, path) {
10066
- if (!useLedger) {
10179
+ if (!useLedger()) {
10067
10180
  throw new Error("ledgerUrl called without a configured ledgerBaseUrl");
10068
10181
  }
10069
10182
  return `${ledgerBase}/public/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}${path}`;
@@ -10072,11 +10185,30 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10072
10185
  return privacyCenterUrl(baseRequest, `/cases/${caseUuid}${path}`);
10073
10186
  }
10074
10187
  function notificationUrl(baseRequest, path = "") {
10075
- return privacyCenterUrl(baseRequest, `/notifications${path}`);
10188
+ const identitySuffix = sandboxIdentitySuffix();
10189
+ if (!identitySuffix) {
10190
+ return privacyCenterUrl(baseRequest, `/notifications${path}`);
10191
+ }
10192
+ const separator = path.includes("?") ? `&${identitySuffix.slice(1)}` : identitySuffix;
10193
+ return privacyCenterUrl(baseRequest, `/notifications${path}${separator}`);
10076
10194
  }
10077
10195
  function resolveAuthToken(authToken, baseRequest) {
10078
10196
  return authToken || baseRequest.authToken;
10079
10197
  }
10198
+ function appendSandboxIdentity(queryParams) {
10199
+ const identity = sandboxQueryIdentity();
10200
+ if (identity) {
10201
+ Object.entries(identity).forEach(([key, value]) => {
10202
+ queryParams.append(key, value);
10203
+ });
10204
+ }
10205
+ }
10206
+ function sandboxIdentitySuffix() {
10207
+ const queryParams = new URLSearchParams();
10208
+ appendSandboxIdentity(queryParams);
10209
+ const queryString = queryParams.toString();
10210
+ return queryString ? `?${queryString}` : "";
10211
+ }
10080
10212
  return {
10081
10213
  /**
10082
10214
  * Get form data (privacy center)
@@ -10108,18 +10240,20 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10108
10240
  async createCaseRequest(baseRequest, payload, authToken, options) {
10109
10241
  const url = privacyCenterUrl(baseRequest, "/case");
10110
10242
  const { useSessionAuth = false, getAuthToken, ...fetchOptions } = options || {};
10243
+ const contact = sandboxContact();
10244
+ const requestPayload = contact && payload && typeof payload === "object" ? { ...payload, contact } : payload;
10111
10245
  if (useSessionAuth) {
10112
10246
  return apiFetch(url, {
10113
10247
  ...fetchOptions,
10114
10248
  method: "POST",
10115
- body: JSON.stringify(payload),
10249
+ body: JSON.stringify(requestPayload),
10116
10250
  getAuthToken
10117
10251
  });
10118
10252
  }
10119
10253
  return privacyCenterApiFetch(url, {
10120
10254
  ...fetchOptions,
10121
10255
  method: "POST",
10122
- body: JSON.stringify(payload),
10256
+ body: JSON.stringify(requestPayload),
10123
10257
  authToken: resolveAuthToken(authToken, baseRequest)
10124
10258
  });
10125
10259
  },
@@ -10200,9 +10334,10 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10200
10334
  if (params.status) queryParams.append("status", params.status);
10201
10335
  if (params.product_uuid) queryParams.append("product_uuid", params.product_uuid);
10202
10336
  if (params.language) queryParams.append("language", params.language);
10337
+ appendSandboxIdentity(queryParams);
10203
10338
  const queryString = queryParams.toString();
10204
10339
  const suffix = `/user-consents${queryString ? `?${queryString}` : ""}`;
10205
- const url = useLedger ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10340
+ const url = useLedger() ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10206
10341
  return privacyCenterApiFetch(url, {
10207
10342
  ...options,
10208
10343
  method: "GET",
@@ -10222,9 +10357,10 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10222
10357
  if (params.search) queryParams.append("search", params.search);
10223
10358
  if (params.language) queryParams.append("language", params.language);
10224
10359
  if (params.nominator_uuid) queryParams.append("nominator_uuid", params.nominator_uuid);
10360
+ appendSandboxIdentity(queryParams);
10225
10361
  const queryString = queryParams.toString();
10226
10362
  const suffix = `/user-consents/${productUuid}/purposes${queryString ? `?${queryString}` : ""}`;
10227
- const url = useLedger ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10363
+ const url = useLedger() ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10228
10364
  return privacyCenterApiFetch(url, {
10229
10365
  ...options,
10230
10366
  method: "GET",
@@ -10247,8 +10383,8 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10247
10383
  * Without a ledger, the legacy Python `/manage-consent?status=` endpoint is
10248
10384
  * used with its `{ purpose_uuid, contact, ... }` payload.
10249
10385
  */
10250
- async manageConsent(baseRequest, purposeId, contact, status, authToken, options, nominatorContact, dataElementUuids, productUuid, noticeUuid, dataElements) {
10251
- if (!useLedger) {
10386
+ async manageConsent(baseRequest, purposeId, contact, status, authToken, options, nominatorContact, dataElementUuids, productUuid, noticeUuid, dataElements, language) {
10387
+ if (!useLedger()) {
10252
10388
  const url2 = privacyCenterUrl(baseRequest, `/manage-consent?status=${status}`);
10253
10389
  const body2 = { purpose_uuid: purposeId, contact };
10254
10390
  if (nominatorContact) {
@@ -10260,6 +10396,9 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10260
10396
  if (productUuid) {
10261
10397
  body2.product_uuid = productUuid;
10262
10398
  }
10399
+ if (language) {
10400
+ body2.language = language;
10401
+ }
10263
10402
  return privacyCenterApiFetch(url2, {
10264
10403
  ...options,
10265
10404
  method: "POST",
@@ -10294,7 +10433,8 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10294
10433
  selected: purposeSelected,
10295
10434
  data_elements: elements
10296
10435
  }
10297
- ]
10436
+ ],
10437
+ ...language ? { language } : {}
10298
10438
  };
10299
10439
  const url = ledgerUrl(baseRequest, "/submit-consent");
10300
10440
  return privacyCenterApiFetch(url, {
@@ -10312,6 +10452,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10312
10452
  if (offset !== void 0) queryParams.append("offset", offset.toString());
10313
10453
  if (limit !== void 0) queryParams.append("limit", limit.toString());
10314
10454
  if (language) queryParams.append("language", language);
10455
+ appendSandboxIdentity(queryParams);
10315
10456
  const queryString = queryParams.toString();
10316
10457
  const url = privacyCenterUrl(baseRequest, `/activities${queryString ? `?${queryString}` : ""}`);
10317
10458
  return privacyCenterApiFetch(url, {
@@ -10361,7 +10502,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10361
10502
  if (params.language) queryParams.append("language", params.language);
10362
10503
  const queryString = queryParams.toString();
10363
10504
  const receiptsSuffix = `/receipts${queryString ? `?${queryString}` : ""}`;
10364
- const url = useLedger ? ledgerUrl(baseRequest, receiptsSuffix) : privacyCenterUrl(baseRequest, receiptsSuffix);
10505
+ const url = useLedger() ? ledgerUrl(baseRequest, receiptsSuffix) : privacyCenterUrl(baseRequest, receiptsSuffix);
10365
10506
  return privacyCenterApiFetch(url, {
10366
10507
  ...options,
10367
10508
  method: "GET",
@@ -10376,11 +10517,16 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10376
10517
  * and the Authorization header must be sent (anchor navigation wouldn't carry it).
10377
10518
  */
10378
10519
  async getReceiptPdf(baseRequest, receiptUuid, authToken) {
10379
- const url = useLedger ? ledgerUrl(baseRequest, `/receipts/${receiptUuid}/download`) : privacyCenterUrl(baseRequest, `/receipts/${receiptUuid}/pdf`);
10520
+ const url = useLedger() ? ledgerUrl(baseRequest, `/receipts/${receiptUuid}/download`) : privacyCenterUrl(baseRequest, `/receipts/${receiptUuid}/pdf`);
10380
10521
  const token = resolveAuthToken(authToken, baseRequest);
10381
10522
  const requestHeaders = new Headers();
10382
10523
  requestHeaders.set("Accept", "application/pdf");
10383
- if (token) {
10524
+ const sandboxHeaders = sandboxAuthHeaders();
10525
+ if (sandboxHeaders) {
10526
+ Object.entries(sandboxHeaders).forEach(([key, value]) => {
10527
+ requestHeaders.set(key, value);
10528
+ });
10529
+ } else if (token) {
10384
10530
  const trimmedToken = token.trim();
10385
10531
  requestHeaders.set(
10386
10532
  "Authorization",
@@ -10411,6 +10557,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10411
10557
  if (offset !== void 0) queryParams.append("offset", offset.toString());
10412
10558
  if (limit !== void 0) queryParams.append("limit", limit.toString());
10413
10559
  if (language) queryParams.append("language", language);
10560
+ appendSandboxIdentity(queryParams);
10414
10561
  const queryString = queryParams.toString();
10415
10562
  const url = privacyCenterUrl(baseRequest, `/cases?${queryString}`);
10416
10563
  return privacyCenterApiFetch(url, {
@@ -10423,7 +10570,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10423
10570
  * Get messages for a case (privacy center)
10424
10571
  */
10425
10572
  async getCaseMessages(baseRequest, caseUuid, authToken) {
10426
- const url = caseUrl(baseRequest, caseUuid, "/messages");
10573
+ const url = caseUrl(baseRequest, caseUuid, `/messages${sandboxIdentitySuffix()}`);
10427
10574
  return privacyCenterApiFetch(url, {
10428
10575
  authToken: resolveAuthToken(authToken, baseRequest)
10429
10576
  });
@@ -10432,7 +10579,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10432
10579
  * Send a message on a case (privacy center)
10433
10580
  */
10434
10581
  async sendCaseMessage(baseRequest, caseUuid, body, documentUuids, authToken) {
10435
- const url = caseUrl(baseRequest, caseUuid, "/messages");
10582
+ const url = caseUrl(baseRequest, caseUuid, `/messages${sandboxIdentitySuffix()}`);
10436
10583
  return privacyCenterApiFetch(url, {
10437
10584
  method: "POST",
10438
10585
  body: JSON.stringify({ body, document_uuids: documentUuids }),
@@ -10443,7 +10590,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10443
10590
  * Upload a document on a case (multipart/form-data, privacy center)
10444
10591
  */
10445
10592
  async uploadCaseDocument(baseRequest, caseUuid, file, authToken) {
10446
- const url = caseUrl(baseRequest, caseUuid, "/upload-document");
10593
+ const url = caseUrl(baseRequest, caseUuid, `/upload-document${sandboxIdentitySuffix()}`);
10447
10594
  const formData = new FormData();
10448
10595
  formData.append("file", file, file.name);
10449
10596
  formData.append("payload", JSON.stringify({ metadata: null }));
@@ -15232,6 +15379,10 @@ var SelectUserGate = ({ children }) => {
15232
15379
  const tokenOrgUserId = ((_d = (_c = decodeJwtToken(accessToken)) == null ? void 0 : _c.user_data) == null ? void 0 : _d.org_user_id) || "";
15233
15380
  (0, import_react32.useEffect)(() => {
15234
15381
  let cancelled = false;
15382
+ if (isSandboxMode()) {
15383
+ setPhase("resolved");
15384
+ return;
15385
+ }
15235
15386
  if (!organizationId || !workspaceId || !accessToken) {
15236
15387
  setPhase("resolved");
15237
15388
  return;
@@ -18409,7 +18560,8 @@ function ConsentManager({ variant }) {
18409
18560
  dataElementUuids,
18410
18561
  productUuid,
18411
18562
  noticeUuid,
18412
- dataElements
18563
+ dataElements,
18564
+ language: langParam
18413
18565
  });
18414
18566
  if (response) {
18415
18567
  toast.success(successMessages[action]);
@@ -18438,7 +18590,7 @@ function ConsentManager({ variant }) {
18438
18590
  handleCloseModal();
18439
18591
  }
18440
18592
  },
18441
- [organizationId, workspaceId, contact, fetchData, handleCloseModal, t, authContext, consentClient, selectedRecord]
18593
+ [organizationId, workspaceId, contact, fetchData, handleCloseModal, t, authContext, consentClient, selectedRecord, langParam]
18442
18594
  );
18443
18595
  const getVar26 = (varName) => `var(${varName})`;
18444
18596
  const directBadge = (_c = (_b = consentDetail == null ? void 0 : consentDetail.status_summary) == null ? void 0 : _b.direct_purposes) != null ? _c : "";
@@ -18974,23 +19126,36 @@ var consentGroupToFormProductGroup = (group) => {
18974
19126
  };
18975
19127
  };
18976
19128
  var purposeItemToFormPurpose = (purpose) => {
18977
- var _a, _b;
19129
+ var _a, _b, _c, _d, _e, _f;
18978
19130
  return {
18979
- uuid: purpose.purpose_uuid,
18980
- purpose_uuid: purpose.purpose_uuid,
19131
+ // The ledger keys purposes as `purpose_uuid`; the legacy Python
19132
+ // user-consents payload keys some of them as `uuid`. Accept either so the
19133
+ // picker and the submitted `purpose_uuid` resolve on both backends.
19134
+ uuid: (_b = (_a = purpose.purpose_uuid) != null ? _a : purpose.uuid) != null ? _b : "",
19135
+ purpose_uuid: (_d = (_c = purpose.purpose_uuid) != null ? _c : purpose.uuid) != null ? _d : "",
18981
19136
  name: purpose.name,
18982
- description: (_a = purpose.description) != null ? _a : "",
19137
+ description: (_e = purpose.description) != null ? _e : "",
18983
19138
  industries: "",
18984
19139
  selected: false,
18985
19140
  given_consent: false,
18986
19141
  status: purpose.status,
18987
19142
  validity: null,
18988
19143
  enabled: true,
18989
- data_elements: ((_b = purpose.data_elements) != null ? _b : []).map(
19144
+ data_elements: ((_f = purpose.data_elements) != null ? _f : []).map(
18990
19145
  consentDataElementToFormDataElement
18991
19146
  )
18992
19147
  };
18993
19148
  };
19149
+ var legacyFlatGroup = (form, label) => {
19150
+ var _a;
19151
+ return {
19152
+ product_uuid: LEGACY_PRODUCT_GROUP_UUID,
19153
+ product_name: label,
19154
+ product_description: null,
19155
+ nominator: null,
19156
+ purposes: ((_a = form.purposes) != null ? _a : []).map((wrapper) => wrapper == null ? void 0 : wrapper.purpose).filter((purpose) => Boolean(purpose))
19157
+ };
19158
+ };
18994
19159
  var consentDataElementToFormDataElement = (element) => ({
18995
19160
  uuid: element.uuid,
18996
19161
  name: element.name,
@@ -20147,7 +20312,7 @@ function Form({
20147
20312
  const [isSubmitted, setIsSubmitted] = (0, import_react44.useState)(false);
20148
20313
  const { t } = (0, import_react_i18next35.useTranslation)();
20149
20314
  const { accessToken, refreshToken, onError, updateTokens } = useAuth();
20150
- const { consentClient, baseUrl, ledgerBaseUrl } = useBaseUrl();
20315
+ const { consentClient, baseUrl } = useBaseUrl();
20151
20316
  const organizationId = organization == null ? void 0 : organization.uuid;
20152
20317
  const workspaceId = (_a = organization == null ? void 0 : organization.workspaces[0]) == null ? void 0 : _a.uuid;
20153
20318
  const authContext = (0, import_react44.useMemo)(() => ({
@@ -20209,8 +20374,19 @@ function Form({
20209
20374
  if (!data) {
20210
20375
  return [];
20211
20376
  }
20212
- return [...(_a2 = data.direct_groups) != null ? _a2 : [], ...(_b2 = data.nominated_groups) != null ? _b2 : []];
20213
- }, [data]);
20377
+ const groups = [
20378
+ ...(_a2 = data.direct_groups) != null ? _a2 : [],
20379
+ ...(_b2 = data.nominated_groups) != null ? _b2 : []
20380
+ ];
20381
+ if (groups.length > 0) {
20382
+ return groups;
20383
+ }
20384
+ const flatGroup = legacyFlatGroup(data, t("yourData"));
20385
+ if (buildGroupPurposes(flatGroup).length === 0) {
20386
+ return [];
20387
+ }
20388
+ return [flatGroup];
20389
+ }, [data, t]);
20214
20390
  const skipProductStep = allGroups.length === 1;
20215
20391
  const selectedGroup = (0, import_react44.useMemo)(() => {
20216
20392
  var _a2, _b2;
@@ -20228,10 +20404,10 @@ function Form({
20228
20404
  },
20229
20405
  []
20230
20406
  );
20231
- const withLedgerPickerGroups = (0, import_react44.useCallback)(
20407
+ const withUserConsentPickerGroups = (0, import_react44.useCallback)(
20232
20408
  async (form, language) => {
20233
20409
  var _a2, _b2;
20234
- if (!ledgerBaseUrl || isPopup || isCaseManagementContext || !organizationId || !workspaceId) {
20410
+ if (isPopup || isCaseManagementContext || !organizationId || !workspaceId) {
20235
20411
  return form;
20236
20412
  }
20237
20413
  const consents = await fetchUserConsents({
@@ -20246,19 +20422,18 @@ function Form({
20246
20422
  nominatedLimit: FORM_PICKER_GROUP_LIMIT,
20247
20423
  language
20248
20424
  });
20249
- if (!consents) {
20425
+ const direct = (_a2 = consents == null ? void 0 : consents.direct) != null ? _a2 : [];
20426
+ const nominated = (_b2 = consents == null ? void 0 : consents.nominated) != null ? _b2 : [];
20427
+ if (direct.length === 0 && nominated.length === 0) {
20250
20428
  return form;
20251
20429
  }
20252
20430
  return {
20253
20431
  ...form,
20254
- direct_groups: ((_a2 = consents.direct) != null ? _a2 : []).map(consentGroupToFormProductGroup),
20255
- nominated_groups: ((_b2 = consents.nominated) != null ? _b2 : []).map(
20256
- consentGroupToFormProductGroup
20257
- )
20432
+ direct_groups: direct.map(consentGroupToFormProductGroup),
20433
+ nominated_groups: nominated.map(consentGroupToFormProductGroup)
20258
20434
  };
20259
20435
  },
20260
20436
  [
20261
- ledgerBaseUrl,
20262
20437
  isPopup,
20263
20438
  isCaseManagementContext,
20264
20439
  organizationId,
@@ -20295,7 +20470,7 @@ function Form({
20295
20470
  toast.info(t("translationNotAvailable"));
20296
20471
  return;
20297
20472
  }
20298
- setData(await withLedgerPickerGroups(translatedFormData, langValue));
20473
+ setData(await withUserConsentPickerGroups(translatedFormData, langValue));
20299
20474
  if (translatedFormData.grievance_options) {
20300
20475
  const currentGrievanceSelections = { ...selectedGrievances };
20301
20476
  setGrievanceOptions(translatedFormData.grievance_options);
@@ -20311,7 +20486,7 @@ function Form({
20311
20486
  } finally {
20312
20487
  setIsTranslating(false);
20313
20488
  }
20314
- }, [organizationId, workspaceId, data, formData.contact, isPopup, isCaseManagementContext, authContext, consentClient, selectedGrievances, t, withLedgerPickerGroups]);
20489
+ }, [organizationId, workspaceId, data, formData.contact, isPopup, isCaseManagementContext, authContext, consentClient, selectedGrievances, t, withUserConsentPickerGroups]);
20315
20490
  (0, import_react44.useEffect)(() => {
20316
20491
  if (!skipProductStep) {
20317
20492
  setSelectedProductKey(null);
@@ -20417,7 +20592,7 @@ function Form({
20417
20592
  console.warn("No purposes with data elements found in API response");
20418
20593
  }
20419
20594
  }
20420
- const pickerData = await withLedgerPickerGroups(
20595
+ const pickerData = await withUserConsentPickerGroups(
20421
20596
  displayData,
20422
20597
  langParam || void 0
20423
20598
  );
@@ -20441,7 +20616,7 @@ function Form({
20441
20616
  }
20442
20617
  };
20443
20618
  void initializePrivacyCenterForm();
20444
- }, [organizationId, workspaceId, isPopup, authContext, consentClient, withLedgerPickerGroups]);
20619
+ }, [organizationId, workspaceId, isPopup, authContext, consentClient, withUserConsentPickerGroups]);
20445
20620
  const getEnglishDataElementName = (0, import_react44.useCallback)((translatedName) => {
20446
20621
  var _a2, _b2, _c2;
20447
20622
  if (!((_a2 = englishDataRef.current) == null ? void 0 : _a2.purposes)) {
@@ -20503,7 +20678,8 @@ function Form({
20503
20678
  return;
20504
20679
  }
20505
20680
  const isProductScoped = isProductScopedRequestType(requestType);
20506
- const anchorGroup = isProductScoped ? selectedGroup : null;
20681
+ const isLegacyFlatSelection = (selectedGroup == null ? void 0 : selectedGroup.product_uuid) === LEGACY_PRODUCT_GROUP_UUID;
20682
+ const anchorGroup = isProductScoped && !isLegacyFlatSelection ? selectedGroup : null;
20507
20683
  const requestDetails = {
20508
20684
  purposes: [],
20509
20685
  correction_data: [],
@@ -27959,6 +28135,12 @@ function RedactoPrivacyCenter({
27959
28135
  slug,
27960
28136
  accessToken,
27961
28137
  refreshToken,
28138
+ token,
28139
+ email,
28140
+ mobile,
28141
+ ucic,
28142
+ organisationUuid,
28143
+ workspaceUuid,
27962
28144
  onError,
27963
28145
  initialPage = "consent-manager",
27964
28146
  onBack
@@ -27968,6 +28150,12 @@ function RedactoPrivacyCenter({
27968
28150
  {
27969
28151
  accessToken,
27970
28152
  refreshToken,
28153
+ token,
28154
+ sandboxUcic: ucic,
28155
+ sandboxSubject: email || mobile,
28156
+ organisationUuid,
28157
+ workspaceUuid,
28158
+ slug,
27971
28159
  onError,
27972
28160
  children: /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(NavigationProvider, { initialPage, children: /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(PageChromeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(PrivacyCenterLayout, { slug, onBack, children: /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(PrivacyCenterHomePage, {}) }) }) })
27973
28161
  }