@redacto.io/consent-sdk-react 10.0.0-beta.8 → 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 (30) hide show
  1. package/CHANGELOG.md +10 -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 +51 -10
  8. package/dist/privacy-center.d.ts +51 -10
  9. package/dist/privacy-center.js +250 -70
  10. package/dist/privacy-center.mjs +249 -71
  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/client.ts +116 -24
  19. package/src/RedactoPrivacyCenter/api/fetcher.ts +24 -9
  20. package/src/RedactoPrivacyCenter/components/Form.tsx +55 -30
  21. package/src/RedactoPrivacyCenter/components/SelectUserGate.tsx +8 -0
  22. package/src/RedactoPrivacyCenter/components/groupHelpers.ts +42 -6
  23. package/src/RedactoPrivacyCenter/context/AuthContext.tsx +131 -39
  24. package/src/RedactoPrivacyCenter/context/types.ts +38 -0
  25. package/src/RedactoPrivacyCenter/lib/constants.ts +12 -5
  26. package/src/RedactoPrivacyCenter/lib/sandbox.ts +104 -0
  27. package/src/RedactoPrivacyCenter/lib/types.ts +20 -0
  28. package/src/RedactoPrivacyCenter/lib/utils.ts +15 -0
  29. package/src/shared/sandbox.ts +6 -0
  30. package/tests/Form.test.tsx +142 -5
@@ -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 = {
@@ -8887,6 +8922,7 @@ var MAX_REFRESH_BACKOFF_MS = 3e5;
8887
8922
  var REFRESH_TOKEN_STORAGE_KEY = "redacto_pc_refresh_token";
8888
8923
  var LEGACY_REFRESH_TOKEN_COOKIE = "refresh_token";
8889
8924
  var FORM_PICKER_GROUP_LIMIT = 100;
8925
+ var LEGACY_PRODUCT_GROUP_UUID = "__legacy_flat_purposes__";
8890
8926
  var POLL_INTERVAL = 3e4;
8891
8927
  var NOTIFICATION_PAGE_SIZE = 10;
8892
8928
  var NOTIFICATION_DROPDOWN_LIMIT = 5;
@@ -9114,6 +9150,9 @@ var getInitialState = (slug) => {
9114
9150
  };
9115
9151
  var checkAndRefreshAuth = async (expectedSlug, organizationId, workspaceId, consentClient) => {
9116
9152
  if (typeof window === "undefined") return false;
9153
+ if (getSandboxConfig()) {
9154
+ return true;
9155
+ }
9117
9156
  const accessToken = sessionStorage.getItem("access_token");
9118
9157
  const email = sessionStorage.getItem("email");
9119
9158
  const orgSlug = sessionStorage.getItem("pc_org_slug");
@@ -9224,6 +9263,10 @@ var signOutPrivacyCenter = () => {
9224
9263
  };
9225
9264
  var ensureValidToken = async (organizationId, workspaceId, slug, authContext, consentClient) => {
9226
9265
  if (typeof window === "undefined") return null;
9266
+ const sandbox = getSandboxConfig();
9267
+ if (sandbox) {
9268
+ return sandbox.token;
9269
+ }
9227
9270
  const accessToken = (authContext == null ? void 0 : authContext.accessToken) || sessionStorage.getItem("access_token");
9228
9271
  if (accessToken && typeof accessToken === "string" && accessToken.trim() !== "" && !isJwtExpired(accessToken, TOKEN_EXPIRY_BUFFER_SECONDS)) {
9229
9272
  return accessToken;
@@ -9799,6 +9842,45 @@ function useCurrentLanguage() {
9799
9842
  import { createContext as createContext2, useContext as useContext2, useState, useEffect, useCallback as useCallback2, useMemo } from "react";
9800
9843
  import { jsx as jsx3 } from "react/jsx-runtime";
9801
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
+ };
9802
9884
  var syncJwtDataToSessionStorage = (accessToken) => {
9803
9885
  if (typeof window === "undefined") return;
9804
9886
  const decoded = decodeJwtToken(accessToken);
@@ -9806,44 +9888,49 @@ var syncJwtDataToSessionStorage = (accessToken) => {
9806
9888
  return;
9807
9889
  }
9808
9890
  const contact = resolveContactFromJwt(decoded) || sessionStorage.getItem("email") || (typeof localStorage !== "undefined" ? localStorage.getItem("userEmail") : null);
9809
- if (contact && typeof contact === "string") {
9810
- sessionStorage.setItem("email", contact);
9811
- }
9812
- const orgUuid = decoded.organisation_uuid;
9813
- if (orgUuid && typeof orgUuid === "string") {
9814
- sessionStorage.setItem("pc_org_id", orgUuid);
9815
- }
9816
- const workspaceUuid = decoded.workspace_uuid;
9817
- if (workspaceUuid && typeof workspaceUuid === "string") {
9818
- sessionStorage.setItem("pc_workspace_id", workspaceUuid);
9819
- }
9820
- const orgSlug = decoded.organisation_slug;
9821
- if (orgSlug && typeof orgSlug === "string") {
9822
- sessionStorage.setItem("pc_org_slug", orgSlug);
9823
- }
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
+ });
9824
9897
  };
9825
- var AuthProvider = ({
9826
- children,
9827
- accessToken: initialAccessToken,
9828
- refreshToken: initialRefreshToken,
9829
- onError
9830
- }) => {
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));
9831
9912
  const [accessToken, setAccessToken] = useState(() => {
9913
+ if (sandboxActive) {
9914
+ return sandboxToken != null ? sandboxToken : "";
9915
+ }
9832
9916
  if (initialAccessToken && typeof initialAccessToken === "string" && initialAccessToken.trim() !== "") {
9833
9917
  if (typeof window !== "undefined") {
9834
9918
  sessionStorage.setItem("access_token", initialAccessToken);
9835
9919
  syncJwtDataToSessionStorage(initialAccessToken);
9836
9920
  }
9837
9921
  }
9838
- return initialAccessToken;
9922
+ return initialAccessToken != null ? initialAccessToken : "";
9839
9923
  });
9840
9924
  const [refreshToken, setRefreshToken] = useState(() => {
9925
+ if (sandboxActive) {
9926
+ return "";
9927
+ }
9841
9928
  if (initialRefreshToken && typeof initialRefreshToken === "string" && initialRefreshToken.trim() !== "") {
9842
9929
  if (typeof window !== "undefined") {
9843
9930
  setRefreshTokenCookie(initialRefreshToken);
9844
9931
  }
9845
9932
  }
9846
- return initialRefreshToken;
9933
+ return initialRefreshToken != null ? initialRefreshToken : "";
9847
9934
  });
9848
9935
  const [sessionExpired, setSessionExpired] = useState(false);
9849
9936
  const markSessionExpired = useCallback2(() => setSessionExpired(true), []);
@@ -9852,6 +9939,9 @@ var AuthProvider = ({
9852
9939
  return () => setSessionExpiredListener(null);
9853
9940
  }, [markSessionExpired]);
9854
9941
  useEffect(() => {
9942
+ if (sandboxActive) {
9943
+ return;
9944
+ }
9855
9945
  if (initialAccessToken && typeof initialAccessToken === "string" && initialAccessToken.trim() !== "") {
9856
9946
  setAccessToken(initialAccessToken);
9857
9947
  if (typeof window !== "undefined") {
@@ -9859,8 +9949,11 @@ var AuthProvider = ({
9859
9949
  syncJwtDataToSessionStorage(initialAccessToken);
9860
9950
  }
9861
9951
  }
9862
- }, [initialAccessToken]);
9952
+ }, [initialAccessToken, sandboxActive]);
9863
9953
  useEffect(() => {
9954
+ if (sandboxActive) {
9955
+ return;
9956
+ }
9864
9957
  if (initialRefreshToken && typeof initialRefreshToken === "string" && initialRefreshToken.trim() !== "") {
9865
9958
  setRefreshToken(initialRefreshToken);
9866
9959
  setSessionExpired(false);
@@ -9868,7 +9961,14 @@ var AuthProvider = ({
9868
9961
  setRefreshTokenCookie(initialRefreshToken);
9869
9962
  }
9870
9963
  }
9871
- }, [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]);
9872
9972
  const updateTokens = useCallback2((newAccessToken, newRefreshToken) => {
9873
9973
  setAccessToken(newAccessToken);
9874
9974
  if (newRefreshToken) {
@@ -9905,7 +10005,8 @@ import { createContext as createContext3, useContext as useContext3, useMemo as
9905
10005
 
9906
10006
  // src/RedactoPrivacyCenter/api/client.ts
9907
10007
  function createConsentClient(baseUrl, ledgerBaseUrl) {
9908
- const useLedger = Boolean(ledgerBaseUrl);
10008
+ const ledgerConfigured = Boolean(ledgerBaseUrl);
10009
+ const useLedger = () => ledgerConfigured && !isSandboxMode();
9909
10010
  const ledgerBase = (ledgerBaseUrl != null ? ledgerBaseUrl : "").replace(/\/$/, "");
9910
10011
  async function privacyCenterApiFetch(url, options) {
9911
10012
  const { authToken, getAuthToken, headers = {}, ...fetchOptions } = options;
@@ -9930,11 +10031,18 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
9930
10031
  );
9931
10032
  }
9932
10033
  }
9933
- const token = authToken || (getAuthToken ? await getAuthToken() : null);
9934
- if (token) {
9935
- const trimmedToken = token.trim();
9936
- const bearerToken = trimmedToken.startsWith("Bearer ") ? trimmedToken : `Bearer ${trimmedToken}`;
9937
- 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
+ }
9938
10046
  }
9939
10047
  const fetchOptionsFinal = {
9940
10048
  ...fetchOptions,
@@ -10000,7 +10108,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10000
10108
  return `${baseUrl}/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}/dsar/privacy-center${path}`;
10001
10109
  }
10002
10110
  function ledgerUrl(baseRequest, path) {
10003
- if (!useLedger) {
10111
+ if (!useLedger()) {
10004
10112
  throw new Error("ledgerUrl called without a configured ledgerBaseUrl");
10005
10113
  }
10006
10114
  return `${ledgerBase}/public/organisations/${baseRequest.organisationUuid}/workspaces/${baseRequest.workspaceUuid}${path}`;
@@ -10009,11 +10117,30 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10009
10117
  return privacyCenterUrl(baseRequest, `/cases/${caseUuid}${path}`);
10010
10118
  }
10011
10119
  function notificationUrl(baseRequest, path = "") {
10012
- 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}`);
10013
10126
  }
10014
10127
  function resolveAuthToken(authToken, baseRequest) {
10015
10128
  return authToken || baseRequest.authToken;
10016
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
+ }
10017
10144
  return {
10018
10145
  /**
10019
10146
  * Get form data (privacy center)
@@ -10045,18 +10172,20 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10045
10172
  async createCaseRequest(baseRequest, payload, authToken, options) {
10046
10173
  const url = privacyCenterUrl(baseRequest, "/case");
10047
10174
  const { useSessionAuth = false, getAuthToken, ...fetchOptions } = options || {};
10175
+ const contact = sandboxContact();
10176
+ const requestPayload = contact && payload && typeof payload === "object" ? { ...payload, contact } : payload;
10048
10177
  if (useSessionAuth) {
10049
10178
  return apiFetch(url, {
10050
10179
  ...fetchOptions,
10051
10180
  method: "POST",
10052
- body: JSON.stringify(payload),
10181
+ body: JSON.stringify(requestPayload),
10053
10182
  getAuthToken
10054
10183
  });
10055
10184
  }
10056
10185
  return privacyCenterApiFetch(url, {
10057
10186
  ...fetchOptions,
10058
10187
  method: "POST",
10059
- body: JSON.stringify(payload),
10188
+ body: JSON.stringify(requestPayload),
10060
10189
  authToken: resolveAuthToken(authToken, baseRequest)
10061
10190
  });
10062
10191
  },
@@ -10137,9 +10266,10 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10137
10266
  if (params.status) queryParams.append("status", params.status);
10138
10267
  if (params.product_uuid) queryParams.append("product_uuid", params.product_uuid);
10139
10268
  if (params.language) queryParams.append("language", params.language);
10269
+ appendSandboxIdentity(queryParams);
10140
10270
  const queryString = queryParams.toString();
10141
10271
  const suffix = `/user-consents${queryString ? `?${queryString}` : ""}`;
10142
- const url = useLedger ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10272
+ const url = useLedger() ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10143
10273
  return privacyCenterApiFetch(url, {
10144
10274
  ...options,
10145
10275
  method: "GET",
@@ -10159,9 +10289,10 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10159
10289
  if (params.search) queryParams.append("search", params.search);
10160
10290
  if (params.language) queryParams.append("language", params.language);
10161
10291
  if (params.nominator_uuid) queryParams.append("nominator_uuid", params.nominator_uuid);
10292
+ appendSandboxIdentity(queryParams);
10162
10293
  const queryString = queryParams.toString();
10163
10294
  const suffix = `/user-consents/${productUuid}/purposes${queryString ? `?${queryString}` : ""}`;
10164
- const url = useLedger ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10295
+ const url = useLedger() ? ledgerUrl(baseRequest, suffix) : privacyCenterUrl(baseRequest, suffix);
10165
10296
  return privacyCenterApiFetch(url, {
10166
10297
  ...options,
10167
10298
  method: "GET",
@@ -10185,7 +10316,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10185
10316
  * used with its `{ purpose_uuid, contact, ... }` payload.
10186
10317
  */
10187
10318
  async manageConsent(baseRequest, purposeId, contact, status, authToken, options, nominatorContact, dataElementUuids, productUuid, noticeUuid, dataElements, language) {
10188
- if (!useLedger) {
10319
+ if (!useLedger()) {
10189
10320
  const url2 = privacyCenterUrl(baseRequest, `/manage-consent?status=${status}`);
10190
10321
  const body2 = { purpose_uuid: purposeId, contact };
10191
10322
  if (nominatorContact) {
@@ -10253,6 +10384,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10253
10384
  if (offset !== void 0) queryParams.append("offset", offset.toString());
10254
10385
  if (limit !== void 0) queryParams.append("limit", limit.toString());
10255
10386
  if (language) queryParams.append("language", language);
10387
+ appendSandboxIdentity(queryParams);
10256
10388
  const queryString = queryParams.toString();
10257
10389
  const url = privacyCenterUrl(baseRequest, `/activities${queryString ? `?${queryString}` : ""}`);
10258
10390
  return privacyCenterApiFetch(url, {
@@ -10302,7 +10434,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10302
10434
  if (params.language) queryParams.append("language", params.language);
10303
10435
  const queryString = queryParams.toString();
10304
10436
  const receiptsSuffix = `/receipts${queryString ? `?${queryString}` : ""}`;
10305
- const url = useLedger ? ledgerUrl(baseRequest, receiptsSuffix) : privacyCenterUrl(baseRequest, receiptsSuffix);
10437
+ const url = useLedger() ? ledgerUrl(baseRequest, receiptsSuffix) : privacyCenterUrl(baseRequest, receiptsSuffix);
10306
10438
  return privacyCenterApiFetch(url, {
10307
10439
  ...options,
10308
10440
  method: "GET",
@@ -10317,11 +10449,16 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10317
10449
  * and the Authorization header must be sent (anchor navigation wouldn't carry it).
10318
10450
  */
10319
10451
  async getReceiptPdf(baseRequest, receiptUuid, authToken) {
10320
- 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`);
10321
10453
  const token = resolveAuthToken(authToken, baseRequest);
10322
10454
  const requestHeaders = new Headers();
10323
10455
  requestHeaders.set("Accept", "application/pdf");
10324
- 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) {
10325
10462
  const trimmedToken = token.trim();
10326
10463
  requestHeaders.set(
10327
10464
  "Authorization",
@@ -10352,6 +10489,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10352
10489
  if (offset !== void 0) queryParams.append("offset", offset.toString());
10353
10490
  if (limit !== void 0) queryParams.append("limit", limit.toString());
10354
10491
  if (language) queryParams.append("language", language);
10492
+ appendSandboxIdentity(queryParams);
10355
10493
  const queryString = queryParams.toString();
10356
10494
  const url = privacyCenterUrl(baseRequest, `/cases?${queryString}`);
10357
10495
  return privacyCenterApiFetch(url, {
@@ -10364,7 +10502,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10364
10502
  * Get messages for a case (privacy center)
10365
10503
  */
10366
10504
  async getCaseMessages(baseRequest, caseUuid, authToken) {
10367
- const url = caseUrl(baseRequest, caseUuid, "/messages");
10505
+ const url = caseUrl(baseRequest, caseUuid, `/messages${sandboxIdentitySuffix()}`);
10368
10506
  return privacyCenterApiFetch(url, {
10369
10507
  authToken: resolveAuthToken(authToken, baseRequest)
10370
10508
  });
@@ -10373,7 +10511,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10373
10511
  * Send a message on a case (privacy center)
10374
10512
  */
10375
10513
  async sendCaseMessage(baseRequest, caseUuid, body, documentUuids, authToken) {
10376
- const url = caseUrl(baseRequest, caseUuid, "/messages");
10514
+ const url = caseUrl(baseRequest, caseUuid, `/messages${sandboxIdentitySuffix()}`);
10377
10515
  return privacyCenterApiFetch(url, {
10378
10516
  method: "POST",
10379
10517
  body: JSON.stringify({ body, document_uuids: documentUuids }),
@@ -10384,7 +10522,7 @@ function createConsentClient(baseUrl, ledgerBaseUrl) {
10384
10522
  * Upload a document on a case (multipart/form-data, privacy center)
10385
10523
  */
10386
10524
  async uploadCaseDocument(baseRequest, caseUuid, file, authToken) {
10387
- const url = caseUrl(baseRequest, caseUuid, "/upload-document");
10525
+ const url = caseUrl(baseRequest, caseUuid, `/upload-document${sandboxIdentitySuffix()}`);
10388
10526
  const formData = new FormData();
10389
10527
  formData.append("file", file, file.name);
10390
10528
  formData.append("payload", JSON.stringify({ metadata: null }));
@@ -15184,6 +15322,10 @@ var SelectUserGate = ({ children }) => {
15184
15322
  const tokenOrgUserId = ((_d = (_c = decodeJwtToken(accessToken)) == null ? void 0 : _c.user_data) == null ? void 0 : _d.org_user_id) || "";
15185
15323
  useEffect17(() => {
15186
15324
  let cancelled = false;
15325
+ if (isSandboxMode()) {
15326
+ setPhase("resolved");
15327
+ return;
15328
+ }
15187
15329
  if (!organizationId || !workspaceId || !accessToken) {
15188
15330
  setPhase("resolved");
15189
15331
  return;
@@ -18936,23 +19078,36 @@ var consentGroupToFormProductGroup = (group) => {
18936
19078
  };
18937
19079
  };
18938
19080
  var purposeItemToFormPurpose = (purpose) => {
18939
- var _a, _b;
19081
+ var _a, _b, _c, _d, _e, _f;
18940
19082
  return {
18941
- uuid: purpose.purpose_uuid,
18942
- 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 : "",
18943
19088
  name: purpose.name,
18944
- description: (_a = purpose.description) != null ? _a : "",
19089
+ description: (_e = purpose.description) != null ? _e : "",
18945
19090
  industries: "",
18946
19091
  selected: false,
18947
19092
  given_consent: false,
18948
19093
  status: purpose.status,
18949
19094
  validity: null,
18950
19095
  enabled: true,
18951
- data_elements: ((_b = purpose.data_elements) != null ? _b : []).map(
19096
+ data_elements: ((_f = purpose.data_elements) != null ? _f : []).map(
18952
19097
  consentDataElementToFormDataElement
18953
19098
  )
18954
19099
  };
18955
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
+ };
18956
19111
  var consentDataElementToFormDataElement = (element) => ({
18957
19112
  uuid: element.uuid,
18958
19113
  name: element.name,
@@ -20109,7 +20264,7 @@ function Form({
20109
20264
  const [isSubmitted, setIsSubmitted] = useState24(false);
20110
20265
  const { t } = useTranslation34();
20111
20266
  const { accessToken, refreshToken, onError, updateTokens } = useAuth();
20112
- const { consentClient, baseUrl, ledgerBaseUrl } = useBaseUrl();
20267
+ const { consentClient, baseUrl } = useBaseUrl();
20113
20268
  const organizationId = organization == null ? void 0 : organization.uuid;
20114
20269
  const workspaceId = (_a = organization == null ? void 0 : organization.workspaces[0]) == null ? void 0 : _a.uuid;
20115
20270
  const authContext = useMemo15(() => ({
@@ -20171,8 +20326,19 @@ function Form({
20171
20326
  if (!data) {
20172
20327
  return [];
20173
20328
  }
20174
- return [...(_a2 = data.direct_groups) != null ? _a2 : [], ...(_b2 = data.nominated_groups) != null ? _b2 : []];
20175
- }, [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]);
20176
20342
  const skipProductStep = allGroups.length === 1;
20177
20343
  const selectedGroup = useMemo15(() => {
20178
20344
  var _a2, _b2;
@@ -20190,10 +20356,10 @@ function Form({
20190
20356
  },
20191
20357
  []
20192
20358
  );
20193
- const withLedgerPickerGroups = useCallback15(
20359
+ const withUserConsentPickerGroups = useCallback15(
20194
20360
  async (form, language) => {
20195
20361
  var _a2, _b2;
20196
- if (!ledgerBaseUrl || isPopup || isCaseManagementContext || !organizationId || !workspaceId) {
20362
+ if (isPopup || isCaseManagementContext || !organizationId || !workspaceId) {
20197
20363
  return form;
20198
20364
  }
20199
20365
  const consents = await fetchUserConsents({
@@ -20208,19 +20374,18 @@ function Form({
20208
20374
  nominatedLimit: FORM_PICKER_GROUP_LIMIT,
20209
20375
  language
20210
20376
  });
20211
- 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) {
20212
20380
  return form;
20213
20381
  }
20214
20382
  return {
20215
20383
  ...form,
20216
- direct_groups: ((_a2 = consents.direct) != null ? _a2 : []).map(consentGroupToFormProductGroup),
20217
- nominated_groups: ((_b2 = consents.nominated) != null ? _b2 : []).map(
20218
- consentGroupToFormProductGroup
20219
- )
20384
+ direct_groups: direct.map(consentGroupToFormProductGroup),
20385
+ nominated_groups: nominated.map(consentGroupToFormProductGroup)
20220
20386
  };
20221
20387
  },
20222
20388
  [
20223
- ledgerBaseUrl,
20224
20389
  isPopup,
20225
20390
  isCaseManagementContext,
20226
20391
  organizationId,
@@ -20257,7 +20422,7 @@ function Form({
20257
20422
  toast.info(t("translationNotAvailable"));
20258
20423
  return;
20259
20424
  }
20260
- setData(await withLedgerPickerGroups(translatedFormData, langValue));
20425
+ setData(await withUserConsentPickerGroups(translatedFormData, langValue));
20261
20426
  if (translatedFormData.grievance_options) {
20262
20427
  const currentGrievanceSelections = { ...selectedGrievances };
20263
20428
  setGrievanceOptions(translatedFormData.grievance_options);
@@ -20273,7 +20438,7 @@ function Form({
20273
20438
  } finally {
20274
20439
  setIsTranslating(false);
20275
20440
  }
20276
- }, [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]);
20277
20442
  useEffect24(() => {
20278
20443
  if (!skipProductStep) {
20279
20444
  setSelectedProductKey(null);
@@ -20379,7 +20544,7 @@ function Form({
20379
20544
  console.warn("No purposes with data elements found in API response");
20380
20545
  }
20381
20546
  }
20382
- const pickerData = await withLedgerPickerGroups(
20547
+ const pickerData = await withUserConsentPickerGroups(
20383
20548
  displayData,
20384
20549
  langParam || void 0
20385
20550
  );
@@ -20403,7 +20568,7 @@ function Form({
20403
20568
  }
20404
20569
  };
20405
20570
  void initializePrivacyCenterForm();
20406
- }, [organizationId, workspaceId, isPopup, authContext, consentClient, withLedgerPickerGroups]);
20571
+ }, [organizationId, workspaceId, isPopup, authContext, consentClient, withUserConsentPickerGroups]);
20407
20572
  const getEnglishDataElementName = useCallback15((translatedName) => {
20408
20573
  var _a2, _b2, _c2;
20409
20574
  if (!((_a2 = englishDataRef.current) == null ? void 0 : _a2.purposes)) {
@@ -20465,7 +20630,8 @@ function Form({
20465
20630
  return;
20466
20631
  }
20467
20632
  const isProductScoped = isProductScopedRequestType(requestType);
20468
- 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;
20469
20635
  const requestDetails = {
20470
20636
  purposes: [],
20471
20637
  correction_data: [],
@@ -27936,6 +28102,12 @@ function RedactoPrivacyCenter({
27936
28102
  slug,
27937
28103
  accessToken,
27938
28104
  refreshToken,
28105
+ token,
28106
+ email,
28107
+ mobile,
28108
+ ucic,
28109
+ organisationUuid,
28110
+ workspaceUuid,
27939
28111
  onError,
27940
28112
  initialPage = "consent-manager",
27941
28113
  onBack
@@ -27945,6 +28117,12 @@ function RedactoPrivacyCenter({
27945
28117
  {
27946
28118
  accessToken,
27947
28119
  refreshToken,
28120
+ token,
28121
+ sandboxUcic: ucic,
28122
+ sandboxSubject: email || mobile,
28123
+ organisationUuid,
28124
+ workspaceUuid,
28125
+ slug,
27948
28126
  onError,
27949
28127
  children: /* @__PURE__ */ jsx92(NavigationProvider, { initialPage, children: /* @__PURE__ */ jsx92(PageChromeProvider, { children: /* @__PURE__ */ jsx92(PrivacyCenterLayout, { slug, onBack, children: /* @__PURE__ */ jsx92(PrivacyCenterHomePage, {}) }) }) })
27950
28128
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redacto.io/consent-sdk-react",
3
- "version": "10.0.0-beta.8",
3
+ "version": "10.0.0-beta.9",
4
4
  "main": "dist/index.cjs",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",