@redacto.io/consent-sdk-react-native 5.0.0-beta.8 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11853,6 +11853,18 @@ var decodeJwtToken = (token) => {
11853
11853
  return null;
11854
11854
  }
11855
11855
  };
11856
+ var resolveContactFromJwt = (decoded) => {
11857
+ if (!decoded) {
11858
+ return null;
11859
+ }
11860
+ const userData = decoded.user_data || {};
11861
+ const candidate = decoded.contact || decoded.primary_email || userData.primary_email || userData.primary_mobile || userData.org_user_id;
11862
+ if (typeof candidate !== "string") {
11863
+ return null;
11864
+ }
11865
+ const contact = candidate.trim();
11866
+ return contact === "" ? null : contact;
11867
+ };
11856
11868
  var isJwtExpired = (token, bufferSeconds = 30) => {
11857
11869
  if (!token || typeof token !== "string") return true;
11858
11870
  try {
@@ -11993,6 +12005,23 @@ var formatDateTime = (timestamp) => {
11993
12005
  hours = hours % 12 || 12;
11994
12006
  return `${month} ${day}, ${year} at ${hours}:${minutes} ${ampm}`;
11995
12007
  };
12008
+ var extractCaseRef = (response) => {
12009
+ if (!response || typeof response !== "object") {
12010
+ return null;
12011
+ }
12012
+ const wrapper = response;
12013
+ const candidates = [wrapper.detail, response];
12014
+ for (const candidate of candidates) {
12015
+ if (!candidate || typeof candidate !== "object") {
12016
+ continue;
12017
+ }
12018
+ const { case_id: caseId, uuid } = candidate;
12019
+ if (caseId || uuid) {
12020
+ return { case_id: caseId != null ? caseId : "", uuid: uuid != null ? uuid : "" };
12021
+ }
12022
+ }
12023
+ return null;
12024
+ };
11996
12025
  var generateUuid = () => {
11997
12026
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
11998
12027
  const r = Math.random() * 16 | 0;
@@ -12012,10 +12041,10 @@ function extractJwtAuthData(token) {
12012
12041
  if (!decoded) {
12013
12042
  return { email: null, organizationId: null, workspaceId: null, organizationName: null };
12014
12043
  }
12015
- const userData = decoded.user_data;
12016
- const userEmail = decoded.contact || decoded.primary_email || decoded.email || decoded.user_uuid || decoded.sub || (userData && typeof userData === "object" ? userData.primary_email || userData.email || userData.contact : null) || null;
12044
+ const contact = resolveContactFromJwt(decoded);
12017
12045
  return {
12018
- email: typeof userEmail === "string" ? userEmail : null,
12046
+ // `resolveContactFromJwt` already returns a trimmed, non-empty string or null.
12047
+ email: contact,
12019
12048
  organizationId: decoded.organisation_uuid || null,
12020
12049
  workspaceId: decoded.workspace_uuid || null,
12021
12050
  organizationName: decoded.organisation_name || null
@@ -12024,7 +12053,11 @@ function extractJwtAuthData(token) {
12024
12053
  function syncJwtDataToStore(token) {
12025
12054
  const authData = extractJwtAuthData(token);
12026
12055
  setStoredValue("access_token", token);
12027
- if (authData.email) setStoredValue("email", authData.email);
12056
+ if (authData.email) {
12057
+ setStoredValue("email", authData.email);
12058
+ } else {
12059
+ removeStoredValue("email");
12060
+ }
12028
12061
  if (authData.organizationId) setStoredValue("pc_org_id", authData.organizationId);
12029
12062
  if (authData.workspaceId) setStoredValue("pc_workspace_id", authData.workspaceId);
12030
12063
  return authData;
@@ -14721,6 +14754,11 @@ var useTimePeriodOptions = () => {
14721
14754
  );
14722
14755
  };
14723
14756
  var MAX_DISPLAYED_PURPOSE_NAMES_IN_ERASURE_MODAL = 3;
14757
+ var PRODUCT_SCOPED_REQUEST_TYPES = [
14758
+ "ACCESS" /* ACCESS */,
14759
+ "erasure" /* ERASURE */,
14760
+ "CORRECTION" /* CORRECTION */
14761
+ ];
14724
14762
  var SEARCH_DEBOUNCE_DELAY = 500;
14725
14763
  var FORM_PICKER_GROUP_LIMIT = 100;
14726
14764
  var LEGACY_PRODUCT_GROUP_UUID = "__legacy_flat_purposes__";
@@ -16564,6 +16602,25 @@ var uploadFileWithS2S = async ({
16564
16602
  }
16565
16603
  };
16566
16604
 
16605
+ // src/RedactoPrivacyCenter/lib/requestType.ts
16606
+ var isRequestType = (requestType, expected) => typeof requestType === "string" && requestType.toLowerCase() === expected.toLowerCase();
16607
+ var isProductScopedRequestType = (requestType) => PRODUCT_SCOPED_REQUEST_TYPES.some((type) => isRequestType(requestType, type));
16608
+
16609
+ // src/RedactoPrivacyCenter/lib/erasureConsent.ts
16610
+ var isErasureRequestType = (requestType) => isRequestType(requestType, "erasure" /* ERASURE */);
16611
+ var resolveErasurePurposeNames = (purposeNames, fallback) => {
16612
+ if (purposeNames.length === 0 || purposeNames.length > MAX_DISPLAYED_PURPOSE_NAMES_IN_ERASURE_MODAL) {
16613
+ return fallback;
16614
+ }
16615
+ return purposeNames.join(", ");
16616
+ };
16617
+ var erasureConsentPayload = (requestType, revokeConsentOnFulfilment) => {
16618
+ if (!isErasureRequestType(requestType)) {
16619
+ return {};
16620
+ }
16621
+ return { revoke_consent_on_fulfilment: revokeConsentOnFulfilment };
16622
+ };
16623
+
16567
16624
  // src/RedactoPrivacyCenter/lib/filePicker.ts
16568
16625
  import { Alert as Alert4 } from "react-native";
16569
16626
  async function pickFile() {
@@ -16800,12 +16857,6 @@ var buildGroupDataElements = (group) => {
16800
16857
  // src/RedactoPrivacyCenter/components/Form.tsx
16801
16858
  import { Fragment as Fragment9, jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
16802
16859
  var TOTAL_STEPS = 3;
16803
- var PRODUCT_SCOPED_REQUEST_TYPES = /* @__PURE__ */ new Set([
16804
- "ACCESS" /* ACCESS */,
16805
- "erasure" /* ERASURE */,
16806
- "CORRECTION" /* CORRECTION */
16807
- ]);
16808
- var isProductScopedRequestType = (rt) => PRODUCT_SCOPED_REQUEST_TYPES.has(rt);
16809
16860
  function Form({ onCreateRequest }) {
16810
16861
  const { t } = useTranslation15();
16811
16862
  const { accessToken, refreshToken, email, organizationId, workspaceId, updateTokens, onError } = useAuth();
@@ -16949,7 +17000,7 @@ function Form({ onCreateRequest }) {
16949
17000
  setSelectedProductKey(null);
16950
17001
  }
16951
17002
  setNominationData({ nominee_email: "", nominee_mobile: "" });
16952
- if (requestType === "grievance" /* GRIEVANCE */ && grievanceOptions.length > 0) {
17003
+ if (isRequestType(requestType, "grievance" /* GRIEVANCE */) && grievanceOptions.length > 0) {
16953
17004
  const resetGrievances = grievanceOptions.reduce(
16954
17005
  (acc, option) => {
16955
17006
  acc[option.value] = false;
@@ -16978,12 +17029,10 @@ function Form({ onCreateRequest }) {
16978
17029
  () => groupPurposes.filter((p) => selectedPurposes.has(p.uuid)).map((p) => p.name).filter(Boolean),
16979
17030
  [groupPurposes, selectedPurposes]
16980
17031
  );
16981
- const selectedErasurePurposeNames = useMemo14(() => {
16982
- if (selectedErasurePurposeList.length === 0 || selectedErasurePurposeList.length > MAX_DISPLAYED_PURPOSE_NAMES_IN_ERASURE_MODAL) {
16983
- return t("revokeConsentModalYourPurposes");
16984
- }
16985
- return selectedErasurePurposeList.join(", ");
16986
- }, [selectedErasurePurposeList, t]);
17032
+ const selectedErasurePurposeNames = useMemo14(
17033
+ () => resolveErasurePurposeNames(selectedErasurePurposeList, t("revokeConsentModalYourPurposes")),
17034
+ [selectedErasurePurposeList, t]
17035
+ );
16987
17036
  const togglePurpose = useCallback10(
16988
17037
  (purpose) => {
16989
17038
  const uuid = purpose.uuid;
@@ -17090,7 +17139,7 @@ function Form({ onCreateRequest }) {
17090
17139
  if (isProductScopedRequestType(requestType)) {
17091
17140
  if (allGroups.length === 0) return false;
17092
17141
  if (!selectedGroup) return false;
17093
- if (requestType === "CORRECTION" /* CORRECTION */) {
17142
+ if (isRequestType(requestType, "CORRECTION" /* CORRECTION */)) {
17094
17143
  if (selectedCorrectionFields.size === 0) return false;
17095
17144
  return Array.from(selectedCorrectionFields).every((fieldUuid) => {
17096
17145
  var _a3, _b;
@@ -17098,15 +17147,15 @@ function Form({ onCreateRequest }) {
17098
17147
  return Boolean(((_a3 = v == null ? void 0 : v.current) == null ? void 0 : _a3.trim()) && ((_b = v == null ? void 0 : v.updated) == null ? void 0 : _b.trim()));
17099
17148
  });
17100
17149
  }
17101
- if (requestType === "ACCESS" /* ACCESS */ || requestType === "erasure" /* ERASURE */) {
17150
+ if (isRequestType(requestType, "ACCESS" /* ACCESS */) || isErasureRequestType(requestType)) {
17102
17151
  return selectedPurposes.size > 0;
17103
17152
  }
17104
17153
  return false;
17105
17154
  }
17106
- if (requestType === "grievance" /* GRIEVANCE */) {
17155
+ if (isRequestType(requestType, "grievance" /* GRIEVANCE */)) {
17107
17156
  return Object.values(selectedGrievances).some(Boolean);
17108
17157
  }
17109
- if (requestType === "nomination" /* NOMINATION */) {
17158
+ if (isRequestType(requestType, "nomination" /* NOMINATION */)) {
17110
17159
  return Boolean(nominationData.nominee_email);
17111
17160
  }
17112
17161
  return false;
@@ -17120,7 +17169,10 @@ function Form({ onCreateRequest }) {
17120
17169
  selectedGrievances,
17121
17170
  nominationData
17122
17171
  ]);
17123
- const isFormValid = useMemo14(() => detailsValid && confirmChecked, [detailsValid, confirmChecked]);
17172
+ const isFormValid = useMemo14(
17173
+ () => Boolean(contact.trim()) && detailsValid && confirmChecked,
17174
+ [contact, detailsValid, confirmChecked]
17175
+ );
17124
17176
  const handleUpload = useCallback10(async () => {
17125
17177
  if (!organizationId || !workspaceId) return;
17126
17178
  const caseUuid = formDataResponse == null ? void 0 : formDataResponse.uuid;
@@ -17172,9 +17224,18 @@ function Form({ onCreateRequest }) {
17172
17224
  const removeUploadedDoc = useCallback10((uuid) => {
17173
17225
  setUploadedDocs((prev) => prev.filter((d) => d.uuid !== uuid));
17174
17226
  }, []);
17227
+ const alertSubmitFailed = useCallback10(
17228
+ (message) => {
17229
+ Alert5.alert(t("submit"), message || t("unableToSubmit") || "Unable to submit request. Please try again.");
17230
+ },
17231
+ [t]
17232
+ );
17175
17233
  const handleSubmit = useCallback10(async (revoke = false) => {
17176
- var _a3, _b, _c, _d;
17177
- if (!organizationId || !workspaceId || !contact || !requestType || !formDataResponse) return;
17234
+ var _a3;
17235
+ if (!organizationId || !workspaceId || !contact || !requestType || !formDataResponse) {
17236
+ alertSubmitFailed();
17237
+ return;
17238
+ }
17178
17239
  setRevokeConsentOnFulfilment(revoke);
17179
17240
  setIsSubmitting(true);
17180
17241
  try {
@@ -17201,27 +17262,27 @@ function Form({ onCreateRequest }) {
17201
17262
  purposes: updatePurposes,
17202
17263
  correction_data: correctionData,
17203
17264
  grievance_types: grievanceTypes,
17204
- ...requestType === "nomination" /* NOMINATION */ ? { nomination_data: nominationData } : {}
17265
+ ...isRequestType(requestType, "nomination" /* NOMINATION */) ? { nomination_data: nominationData } : {}
17205
17266
  },
17206
- time_period: requestType === "ACCESS" /* ACCESS */ ? parseInt(timePeriod || "30", 10) : 0,
17267
+ time_period: isRequestType(requestType, "ACCESS" /* ACCESS */) ? parseInt(timePeriod || "30", 10) : 0,
17207
17268
  requestor_note: additionalNote || "",
17208
- ...requestType === "erasure" /* ERASURE */ ? { revoke_consent_on_fulfilment: revoke } : {},
17269
+ ...erasureConsentPayload(requestType, revoke),
17209
17270
  ...anchorGroup ? { product_uuid: anchorGroup.product_uuid } : {},
17210
17271
  ...(anchorGroup == null ? void 0 : anchorGroup.nominator) ? { data_principal_uuid: anchorGroup.nominator.uuid } : {}
17211
17272
  };
17212
17273
  const response = await createCaseRequest(organizationId, workspaceId, request, false, false, authContext, consentClient);
17213
- const responseAny = response;
17214
- const newCaseId = (_c = (_b = responseAny == null ? void 0 : responseAny.case_id) != null ? _b : (_a3 = responseAny == null ? void 0 : responseAny.detail) == null ? void 0 : _a3.case_id) != null ? _c : null;
17274
+ const caseRef = extractCaseRef(response);
17275
+ const newCaseId = (caseRef == null ? void 0 : caseRef.case_id) || (caseRef == null ? void 0 : caseRef.uuid) || null;
17215
17276
  if (newCaseId) {
17216
17277
  setCaseId(newCaseId);
17217
- setSubmittedProductName((_d = anchorGroup == null ? void 0 : anchorGroup.product_name) != null ? _d : "");
17278
+ setSubmittedProductName((_a3 = anchorGroup == null ? void 0 : anchorGroup.product_name) != null ? _a3 : "");
17218
17279
  setIsSubmitted(true);
17219
17280
  } else {
17220
- Alert5.alert(t("submit"), t("unableToSubmit") || "Unable to submit request. Please try again.");
17281
+ alertSubmitFailed();
17221
17282
  }
17222
17283
  } catch (error) {
17223
17284
  console.warn("Error submitting request:", error);
17224
- Alert5.alert(t("submit"), (error == null ? void 0 : error.message) || t("unableToSubmit") || "Unable to submit request.");
17285
+ alertSubmitFailed(error == null ? void 0 : error.message);
17225
17286
  } finally {
17226
17287
  setIsSubmitting(false);
17227
17288
  }
@@ -17244,11 +17305,13 @@ function Form({ onCreateRequest }) {
17244
17305
  consentClient,
17245
17306
  groupDataElements,
17246
17307
  uploadedDocs,
17247
- t
17308
+ alertSubmitFailed
17248
17309
  ]);
17249
17310
  const handleSubmitClick = useCallback10(() => {
17250
- if (!isFormValid) return;
17251
- if (requestType === "erasure" /* ERASURE */) {
17311
+ if (!isFormValid) {
17312
+ return;
17313
+ }
17314
+ if (isErasureRequestType(requestType)) {
17252
17315
  setIsErasureConsentModalOpen(true);
17253
17316
  return;
17254
17317
  }
@@ -17337,7 +17400,7 @@ function Form({ onCreateRequest }) {
17337
17400
  if (groupPurposes.length === 0) {
17338
17401
  return /* @__PURE__ */ jsx43(Text25, { style: [styles33.placeholder, { color: colors.textSecondary }], children: t("noPurposesAvailable") || "No purposes available" });
17339
17402
  }
17340
- const isErasure = requestType === "erasure" /* ERASURE */;
17403
+ const isErasure = isErasureRequestType(requestType);
17341
17404
  const allPurposesSelected = groupPurposes.every(
17342
17405
  (p) => (p.data_elements || []).every((de) => {
17343
17406
  var _a3;
@@ -17457,18 +17520,18 @@ function Form({ onCreateRequest }) {
17457
17520
  ] }),
17458
17521
  selectedGroup ? /* @__PURE__ */ jsxs27(View32, { style: styles33.section, children: [
17459
17522
  /* @__PURE__ */ jsx43(Text25, { style: [styles33.sectionLabel, { color: colors.textSecondary }], children: t("requestDetails") }),
17460
- /* @__PURE__ */ jsx43(View32, { style: [styles33.sectionCard, elevation.card, { backgroundColor: colors.surface }], children: requestType === "CORRECTION" /* CORRECTION */ ? renderCorrectionFields() : renderPurposeFields() })
17523
+ /* @__PURE__ */ jsx43(View32, { style: [styles33.sectionCard, elevation.card, { backgroundColor: colors.surface }], children: isRequestType(requestType, "CORRECTION" /* CORRECTION */) ? renderCorrectionFields() : renderPurposeFields() })
17461
17524
  ] }) : /* @__PURE__ */ jsxs27(View32, { style: [styles33.hintCard, { backgroundColor: colors.surfaceAlt }], children: [
17462
17525
  /* @__PURE__ */ jsx43(Icon, { name: "circle-alert", size: 18, color: colors.textSecondary }),
17463
17526
  /* @__PURE__ */ jsx43(Text25, { style: [styles33.hintText, { color: colors.textSecondary }], children: t("selectProductFirst", { defaultValue: "Select a product to continue" }) })
17464
17527
  ] }),
17465
- requestType === "ACCESS" /* ACCESS */ && selectedGroup ? /* @__PURE__ */ jsxs27(View32, { style: styles33.section, children: [
17528
+ isRequestType(requestType, "ACCESS" /* ACCESS */) && selectedGroup ? /* @__PURE__ */ jsxs27(View32, { style: styles33.section, children: [
17466
17529
  /* @__PURE__ */ jsx43(Text25, { style: [styles33.sectionLabel, { color: colors.textSecondary }], children: t("timePeriod") }),
17467
17530
  /* @__PURE__ */ jsx43(PCSelect, { value: timePeriod, options: timePeriodOptions, onChange: setTimePeriod, placeholder: t("timePeriod") })
17468
17531
  ] }) : null
17469
17532
  ] });
17470
17533
  }
17471
- if (requestType === "grievance" /* GRIEVANCE */) {
17534
+ if (isRequestType(requestType, "grievance" /* GRIEVANCE */)) {
17472
17535
  if (grievanceOptions.length === 0) {
17473
17536
  return /* @__PURE__ */ jsx43(View32, { style: styles33.stepBody, children: /* @__PURE__ */ jsx43(Text25, { style: [styles33.placeholder, { color: colors.textSecondary }], children: t("noPurposesAvailable") || "No grievance types available" }) });
17474
17537
  }
@@ -17484,7 +17547,7 @@ function Form({ onCreateRequest }) {
17484
17547
  ] })
17485
17548
  ] }) });
17486
17549
  }
17487
- if (requestType === "nomination" /* NOMINATION */) {
17550
+ if (isRequestType(requestType, "nomination" /* NOMINATION */)) {
17488
17551
  return /* @__PURE__ */ jsx43(View32, { style: styles33.stepBody, children: /* @__PURE__ */ jsxs27(View32, { style: styles33.section, children: [
17489
17552
  /* @__PURE__ */ jsx43(Text25, { style: [styles33.sectionLabel, { color: colors.textSecondary }], children: t("enterNomineeDetails") }),
17490
17553
  /* @__PURE__ */ jsxs27(View32, { style: [styles33.sectionCard, elevation.card, { backgroundColor: colors.surface }], children: [
@@ -18466,6 +18529,22 @@ import { useMemo as useMemo18, useState as useState21 } from "react";
18466
18529
  import { StyleSheet as StyleSheet39, Text as Text29, TouchableOpacity as TouchableOpacity14, View as View37 } from "react-native";
18467
18530
  import { useTranslation as useTranslation18 } from "react-i18next";
18468
18531
 
18532
+ // src/RedactoPrivacyCenter/context/ProfileSwitchContext.tsx
18533
+ import { createContext as createContext7, useContext as useContext7 } from "react";
18534
+ import { jsx as jsx46 } from "react/jsx-runtime";
18535
+ var ProfileSwitchContext = createContext7({
18536
+ switchProfile: null
18537
+ });
18538
+ function ProfileSwitchProvider({
18539
+ switchProfile,
18540
+ children
18541
+ }) {
18542
+ return /* @__PURE__ */ jsx46(ProfileSwitchContext.Provider, { value: { switchProfile }, children });
18543
+ }
18544
+ function useProfileSwitch() {
18545
+ return useContext7(ProfileSwitchContext);
18546
+ }
18547
+
18469
18548
  // src/RedactoPrivacyCenter/lib/navigation.ts
18470
18549
  function navigateBack(onBack) {
18471
18550
  var _a3, _b;
@@ -18489,7 +18568,7 @@ function navigateBack(onBack) {
18489
18568
 
18490
18569
  // src/RedactoPrivacyCenter/components/NotificationHub/NotificationBell.tsx
18491
18570
  import { StyleSheet as StyleSheet37, Text as Text27, TouchableOpacity as TouchableOpacity12, View as View35 } from "react-native";
18492
- import { jsx as jsx46, jsxs as jsxs29 } from "react/jsx-runtime";
18571
+ import { jsx as jsx47, jsxs as jsxs29 } from "react/jsx-runtime";
18493
18572
  var NotificationBell = ({ count, onPress }) => {
18494
18573
  const { colors } = useTheme();
18495
18574
  const showBadge = count > 0;
@@ -18504,8 +18583,8 @@ var NotificationBell = ({ count, onPress }) => {
18504
18583
  accessibilityRole: "button",
18505
18584
  accessibilityLabel: showBadge ? `Notifications, ${count} unread` : "Notifications",
18506
18585
  children: [
18507
- /* @__PURE__ */ jsx46(Icon, { name: "bell", size: 22, color: colors.text }),
18508
- showBadge ? /* @__PURE__ */ jsx46(View35, { style: [styles36.badge, { backgroundColor: colors.error, borderColor: colors.canvasSubtle }], children: /* @__PURE__ */ jsx46(Text27, { style: styles36.badgeText, numberOfLines: 1, children: badgeLabel }) }) : null
18586
+ /* @__PURE__ */ jsx47(Icon, { name: "bell", size: 22, color: colors.text }),
18587
+ showBadge ? /* @__PURE__ */ jsx47(View35, { style: [styles36.badge, { backgroundColor: colors.error, borderColor: colors.canvasSubtle }], children: /* @__PURE__ */ jsx47(Text27, { style: styles36.badgeText, numberOfLines: 1, children: badgeLabel }) }) : null
18509
18588
  ]
18510
18589
  }
18511
18590
  );
@@ -18571,7 +18650,7 @@ function useUnreadCount() {
18571
18650
  import { useMemo as useMemo17, useState as useState20 } from "react";
18572
18651
  import { StyleSheet as StyleSheet38, Text as Text28, TouchableOpacity as TouchableOpacity13, View as View36 } from "react-native";
18573
18652
  import { useTranslation as useTranslation17 } from "react-i18next";
18574
- import { jsx as jsx47, jsxs as jsxs30 } from "react/jsx-runtime";
18653
+ import { jsx as jsx48, jsxs as jsxs30 } from "react/jsx-runtime";
18575
18654
  var NavDrawer = ({ visible, onClose, onBack }) => {
18576
18655
  const { t } = useTranslation17();
18577
18656
  const { colors, branding } = useTheme();
@@ -18593,15 +18672,15 @@ var NavDrawer = ({ visible, onClose, onBack }) => {
18593
18672
  i18n_default.changeLanguage(value);
18594
18673
  };
18595
18674
  const brandName = (branding == null ? void 0 : branding.brand_name) || organizationName || t("privacyCenter") || "Privacy Center";
18596
- return /* @__PURE__ */ jsx47(BottomSheet, { visible, onClose, title: t("menu") || "Menu", children: /* @__PURE__ */ jsxs30(View36, { style: styles37.body, children: [
18675
+ return /* @__PURE__ */ jsx48(BottomSheet, { visible, onClose, title: t("menu") || "Menu", children: /* @__PURE__ */ jsxs30(View36, { style: styles37.body, children: [
18597
18676
  /* @__PURE__ */ jsxs30(View36, { style: [styles37.identity, { backgroundColor: colors.surfaceAlt }], children: [
18598
- /* @__PURE__ */ jsx47(PCAvatar, { name: brandName, imageUrl: branding == null ? void 0 : branding.icon_url, size: 40 }),
18677
+ /* @__PURE__ */ jsx48(PCAvatar, { name: brandName, imageUrl: branding == null ? void 0 : branding.icon_url, size: 40 }),
18599
18678
  /* @__PURE__ */ jsxs30(View36, { style: styles37.identityText, children: [
18600
- /* @__PURE__ */ jsx47(Text28, { style: [styles37.brandName, { color: colors.text }], numberOfLines: 1, children: brandName }),
18601
- email ? /* @__PURE__ */ jsx47(Text28, { style: [styles37.email, { color: colors.textSecondary }], numberOfLines: 1, children: email }) : null
18679
+ /* @__PURE__ */ jsx48(Text28, { style: [styles37.brandName, { color: colors.text }], numberOfLines: 1, children: brandName }),
18680
+ email ? /* @__PURE__ */ jsx48(Text28, { style: [styles37.email, { color: colors.textSecondary }], numberOfLines: 1, children: email }) : null
18602
18681
  ] })
18603
18682
  ] }),
18604
- /* @__PURE__ */ jsx47(View36, { style: [styles37.menuGroup, { borderColor: colors.border, backgroundColor: colors.surface }], children: items.map((item, index) => {
18683
+ /* @__PURE__ */ jsx48(View36, { style: [styles37.menuGroup, { borderColor: colors.border, backgroundColor: colors.surface }], children: items.map((item, index) => {
18605
18684
  const isActive = currentPage === item.page;
18606
18685
  return /* @__PURE__ */ jsxs30(View36, { children: [
18607
18686
  /* @__PURE__ */ jsxs30(
@@ -18617,8 +18696,8 @@ var NavDrawer = ({ visible, onClose, onBack }) => {
18617
18696
  accessibilityState: { selected: isActive },
18618
18697
  accessibilityLabel: item.label,
18619
18698
  children: [
18620
- /* @__PURE__ */ jsx47(IconTile, { name: item.icon, tone: item.tone, size: "sm" }),
18621
- /* @__PURE__ */ jsx47(
18699
+ /* @__PURE__ */ jsx48(IconTile, { name: item.icon, tone: item.tone, size: "sm" }),
18700
+ /* @__PURE__ */ jsx48(
18622
18701
  Text28,
18623
18702
  {
18624
18703
  style: [styles37.menuLabel, { color: isActive ? colors.primary : colors.text }],
@@ -18626,14 +18705,14 @@ var NavDrawer = ({ visible, onClose, onBack }) => {
18626
18705
  children: item.label
18627
18706
  }
18628
18707
  ),
18629
- /* @__PURE__ */ jsx47(Icon, { name: "chevron-right", size: 18, color: colors.textSecondary })
18708
+ /* @__PURE__ */ jsx48(Icon, { name: "chevron-right", size: 18, color: colors.textSecondary })
18630
18709
  ]
18631
18710
  }
18632
18711
  ),
18633
- index < items.length - 1 ? /* @__PURE__ */ jsx47(View36, { style: [styles37.separator, { backgroundColor: colors.hairline }] }) : null
18712
+ index < items.length - 1 ? /* @__PURE__ */ jsx48(View36, { style: [styles37.separator, { backgroundColor: colors.hairline }] }) : null
18634
18713
  ] }, item.page);
18635
18714
  }) }),
18636
- /* @__PURE__ */ jsx47(
18715
+ /* @__PURE__ */ jsx48(
18637
18716
  PCSelect,
18638
18717
  {
18639
18718
  label: t("language"),
@@ -18654,7 +18733,7 @@ var NavDrawer = ({ visible, onClose, onBack }) => {
18654
18733
  activeOpacity: 0.7,
18655
18734
  accessibilityRole: "button",
18656
18735
  children: [
18657
- /* @__PURE__ */ jsx47(
18736
+ /* @__PURE__ */ jsx48(
18658
18737
  Icon,
18659
18738
  {
18660
18739
  name: onBack === "signout" ? "log-out" : "arrow-left",
@@ -18662,11 +18741,11 @@ var NavDrawer = ({ visible, onClose, onBack }) => {
18662
18741
  color: onBack === "signout" ? colors.error : colors.text
18663
18742
  }
18664
18743
  ),
18665
- /* @__PURE__ */ jsx47(Text28, { style: [styles37.actionLabel, { color: onBack === "signout" ? colors.error : colors.text }], children: onBack === "signout" ? t("signOut") || "Sign Out" : t("back") || "Back" })
18744
+ /* @__PURE__ */ jsx48(Text28, { style: [styles37.actionLabel, { color: onBack === "signout" ? colors.error : colors.text }], children: onBack === "signout" ? t("signOut") || "Sign Out" : t("back") || "Back" })
18666
18745
  ]
18667
18746
  }
18668
18747
  ) : null,
18669
- /* @__PURE__ */ jsx47(Footer, { inline: true })
18748
+ /* @__PURE__ */ jsx48(Footer, { inline: true })
18670
18749
  ] }) });
18671
18750
  };
18672
18751
  var styles37 = StyleSheet38.create({
@@ -18728,7 +18807,7 @@ var styles37 = StyleSheet38.create({
18728
18807
  });
18729
18808
 
18730
18809
  // src/RedactoPrivacyCenter/components/SlimTopBar.tsx
18731
- import { Fragment as Fragment11, jsx as jsx48, jsxs as jsxs31 } from "react/jsx-runtime";
18810
+ import { Fragment as Fragment11, jsx as jsx49, jsxs as jsxs31 } from "react/jsx-runtime";
18732
18811
  var SlimTopBar = ({ mode = "primary", onBack }) => {
18733
18812
  const { t } = useTranslation18();
18734
18813
  const { currentPage, navigateTo } = useInternalNavigation();
@@ -18737,6 +18816,7 @@ var SlimTopBar = ({ mode = "primary", onBack }) => {
18737
18816
  const unreadCount = useUnreadCount();
18738
18817
  const insets = useSafeInsets();
18739
18818
  const [menuOpen, setMenuOpen] = useState21(false);
18819
+ const { switchProfile } = useProfileSwitch();
18740
18820
  const pageChrome = PAGE_CHROME_BY_PAGE[currentPage];
18741
18821
  const isDetail = mode === "detail";
18742
18822
  const brandLabel = useMemo18(
@@ -18755,7 +18835,7 @@ var SlimTopBar = ({ mode = "primary", onBack }) => {
18755
18835
  navigateBack(onBack);
18756
18836
  };
18757
18837
  return /* @__PURE__ */ jsxs31(Fragment11, { children: [
18758
- /* @__PURE__ */ jsx48(
18838
+ /* @__PURE__ */ jsx49(
18759
18839
  View37,
18760
18840
  {
18761
18841
  style: [
@@ -18763,7 +18843,7 @@ var SlimTopBar = ({ mode = "primary", onBack }) => {
18763
18843
  { backgroundColor: colors.canvasSubtle, borderBottomColor: colors.hairline, paddingTop: insets.top + spacing.xs }
18764
18844
  ],
18765
18845
  children: isDetail ? /* @__PURE__ */ jsxs31(View37, { style: styles38.detailRow, children: [
18766
- /* @__PURE__ */ jsx48(
18846
+ /* @__PURE__ */ jsx49(
18767
18847
  TouchableOpacity14,
18768
18848
  {
18769
18849
  style: styles38.iconButton,
@@ -18772,27 +18852,39 @@ var SlimTopBar = ({ mode = "primary", onBack }) => {
18772
18852
  hitSlop: DEFAULT_HIT_SLOP,
18773
18853
  accessibilityRole: "button",
18774
18854
  accessibilityLabel: t("back") || "Back",
18775
- children: /* @__PURE__ */ jsx48(Icon, { name: "arrow-left", size: 22, color: colors.text })
18855
+ children: /* @__PURE__ */ jsx49(Icon, { name: "arrow-left", size: 22, color: colors.text })
18776
18856
  }
18777
18857
  ),
18778
- /* @__PURE__ */ jsx48(Text29, { style: [styles38.detailTitle, { color: colors.text }], numberOfLines: 1, children: t((pageChrome == null ? void 0 : pageChrome.titleKey) || "privacyCenter") }),
18779
- /* @__PURE__ */ jsx48(View37, { style: styles38.placeholder })
18858
+ /* @__PURE__ */ jsx49(Text29, { style: [styles38.detailTitle, { color: colors.text }], numberOfLines: 1, children: t((pageChrome == null ? void 0 : pageChrome.titleKey) || "privacyCenter") }),
18859
+ /* @__PURE__ */ jsx49(View37, { style: styles38.placeholder })
18780
18860
  ] }) : /* @__PURE__ */ jsxs31(View37, { style: styles38.row, children: [
18781
- /* @__PURE__ */ jsx48(View37, { style: styles38.brandWrap, children: (branding == null ? void 0 : branding.logo_url) ? /* @__PURE__ */ jsx48(
18861
+ /* @__PURE__ */ jsx49(View37, { style: styles38.brandWrap, children: (branding == null ? void 0 : branding.logo_url) ? /* @__PURE__ */ jsx49(
18782
18862
  BrandImage,
18783
18863
  {
18784
18864
  uri: branding.logo_url,
18785
18865
  height: 24,
18786
18866
  maxWidth: 124,
18787
- fallback: /* @__PURE__ */ jsx48(PCAvatar, { name: brandLabel, imageUrl: branding == null ? void 0 : branding.icon_url, size: 24 })
18867
+ fallback: /* @__PURE__ */ jsx49(PCAvatar, { name: brandLabel, imageUrl: branding == null ? void 0 : branding.icon_url, size: 24 })
18788
18868
  }
18789
18869
  ) : /* @__PURE__ */ jsxs31(View37, { style: styles38.brandLockup, children: [
18790
- /* @__PURE__ */ jsx48(PCAvatar, { name: brandLabel, imageUrl: branding == null ? void 0 : branding.icon_url, size: 24 }),
18791
- /* @__PURE__ */ jsx48(Text29, { style: [styles38.brandText, { color: colors.text }], numberOfLines: 1, children: brandLabel })
18870
+ /* @__PURE__ */ jsx49(PCAvatar, { name: brandLabel, imageUrl: branding == null ? void 0 : branding.icon_url, size: 24 }),
18871
+ /* @__PURE__ */ jsx49(Text29, { style: [styles38.brandText, { color: colors.text }], numberOfLines: 1, children: brandLabel })
18792
18872
  ] }) }),
18793
18873
  /* @__PURE__ */ jsxs31(View37, { style: styles38.actions, children: [
18794
- /* @__PURE__ */ jsx48(NotificationBell, { count: unreadCount, onPress: () => navigateTo("notifications") }),
18795
- /* @__PURE__ */ jsx48(
18874
+ switchProfile ? /* @__PURE__ */ jsx49(
18875
+ TouchableOpacity14,
18876
+ {
18877
+ style: styles38.iconButton,
18878
+ onPress: switchProfile,
18879
+ activeOpacity: 0.7,
18880
+ hitSlop: DEFAULT_HIT_SLOP,
18881
+ accessibilityRole: "button",
18882
+ accessibilityLabel: t("switchProfile"),
18883
+ children: /* @__PURE__ */ jsx49(Icon, { name: "users", size: 22, color: colors.text })
18884
+ }
18885
+ ) : null,
18886
+ /* @__PURE__ */ jsx49(NotificationBell, { count: unreadCount, onPress: () => navigateTo("notifications") }),
18887
+ /* @__PURE__ */ jsx49(
18796
18888
  TouchableOpacity14,
18797
18889
  {
18798
18890
  style: styles38.iconButton,
@@ -18801,14 +18893,14 @@ var SlimTopBar = ({ mode = "primary", onBack }) => {
18801
18893
  hitSlop: DEFAULT_HIT_SLOP,
18802
18894
  accessibilityRole: "button",
18803
18895
  accessibilityLabel: t("menu") || "Menu",
18804
- children: /* @__PURE__ */ jsx48(Icon, { name: "menu", size: 22, color: colors.text })
18896
+ children: /* @__PURE__ */ jsx49(Icon, { name: "menu", size: 22, color: colors.text })
18805
18897
  }
18806
18898
  )
18807
18899
  ] })
18808
18900
  ] })
18809
18901
  }
18810
18902
  ),
18811
- /* @__PURE__ */ jsx48(NavDrawer, { visible: menuOpen, onClose: () => setMenuOpen(false), onBack })
18903
+ /* @__PURE__ */ jsx49(NavDrawer, { visible: menuOpen, onClose: () => setMenuOpen(false), onBack })
18812
18904
  ] });
18813
18905
  };
18814
18906
  var styles38 = StyleSheet39.create({
@@ -18869,18 +18961,18 @@ var styles38 = StyleSheet39.create({
18869
18961
 
18870
18962
  // src/RedactoPrivacyCenter/components/PrivacyCenterEmptyState.tsx
18871
18963
  import { useTranslation as useTranslation19 } from "react-i18next";
18872
- import { jsx as jsx49 } from "react/jsx-runtime";
18964
+ import { jsx as jsx50 } from "react/jsx-runtime";
18873
18965
  function PrivacyCenterEmptyState() {
18874
18966
  const { t } = useTranslation19();
18875
- return /* @__PURE__ */ jsx49(PCEmpty, { iconName: "shield", title: t("noDataTitle"), description: t("noDataDescription") });
18967
+ return /* @__PURE__ */ jsx50(PCEmpty, { iconName: "shield", title: t("noDataTitle"), description: t("noDataDescription") });
18876
18968
  }
18877
18969
 
18878
18970
  // src/RedactoPrivacyCenter/components/PrivacyCenterSessionExpired.tsx
18879
18971
  import { useTranslation as useTranslation20 } from "react-i18next";
18880
- import { jsx as jsx50 } from "react/jsx-runtime";
18972
+ import { jsx as jsx51 } from "react/jsx-runtime";
18881
18973
  function PrivacyCenterSessionExpired() {
18882
18974
  const { t } = useTranslation20();
18883
- return /* @__PURE__ */ jsx50(
18975
+ return /* @__PURE__ */ jsx51(
18884
18976
  PCEmpty,
18885
18977
  {
18886
18978
  iconName: "shield",
@@ -18894,22 +18986,6 @@ function PrivacyCenterSessionExpired() {
18894
18986
  import { useCallback as useCallback11, useEffect as useEffect16, useState as useState22 } from "react";
18895
18987
  import { StyleSheet as StyleSheet41, View as View39 } from "react-native";
18896
18988
 
18897
- // src/RedactoPrivacyCenter/context/ProfileSwitchContext.tsx
18898
- import { createContext as createContext7, useContext as useContext7 } from "react";
18899
- import { jsx as jsx51 } from "react/jsx-runtime";
18900
- var ProfileSwitchContext = createContext7({
18901
- switchProfile: null
18902
- });
18903
- function ProfileSwitchProvider({
18904
- switchProfile,
18905
- children
18906
- }) {
18907
- return /* @__PURE__ */ jsx51(ProfileSwitchContext.Provider, { value: { switchProfile }, children });
18908
- }
18909
- function useProfileSwitch() {
18910
- return useContext7(ProfileSwitchContext);
18911
- }
18912
-
18913
18989
  // src/RedactoPrivacyCenter/components/SelectUser.tsx
18914
18990
  import { ScrollView as ScrollView8, StyleSheet as StyleSheet40, Text as Text30, TouchableOpacity as TouchableOpacity15, View as View38 } from "react-native";
18915
18991
  import { useTranslation as useTranslation21 } from "react-i18next";
@@ -21685,6 +21761,7 @@ function Navbar({ mode = "primary", onBack }) {
21685
21761
  const [menuOpen, setMenuOpen] = useState26(false);
21686
21762
  const unreadCount = useUnreadCount();
21687
21763
  const { status: pageStatus } = usePageStatus();
21764
+ const { switchProfile } = useProfileSwitch();
21688
21765
  const pageChrome = PAGE_CHROME_BY_PAGE[currentPage] || PAGE_CHROME_BY_PAGE["consent-manager"];
21689
21766
  const isDetail = mode === "detail";
21690
21767
  useEffect22(() => {
@@ -21787,6 +21864,36 @@ function Navbar({ mode = "primary", onBack }) {
21787
21864
  ) : null,
21788
21865
  /* @__PURE__ */ jsx71(View55, { style: styles57.brandWrap, children: (branding == null ? void 0 : branding.logo_url) ? /* @__PURE__ */ jsx71(BrandImage, { uri: branding.logo_url, height: 34, maxWidth: 170, fallback: brandLockup }) : brandLockup }),
21789
21866
  /* @__PURE__ */ jsxs48(View55, { style: styles57.actions, children: [
21867
+ switchProfile ? /* @__PURE__ */ jsx71(
21868
+ TouchableOpacity25,
21869
+ {
21870
+ style: styles57.iconButton,
21871
+ onPress: switchProfile,
21872
+ activeOpacity: 0.7,
21873
+ hitSlop: DEFAULT_HIT_SLOP,
21874
+ accessibilityRole: "button",
21875
+ accessibilityLabel: t("switchProfile"),
21876
+ children: /* @__PURE__ */ jsx71(
21877
+ View55,
21878
+ {
21879
+ style: [
21880
+ styles57.iconCircle,
21881
+ { backgroundColor: colors.surface, borderColor: colors.border }
21882
+ ],
21883
+ children: /* @__PURE__ */ jsx71(Svg4, { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx71(
21884
+ Path4,
21885
+ {
21886
+ d: "M16 3h5v5 M21 3l-7 7 M8 21H3v-5 M3 21l7-7",
21887
+ stroke: colors.text,
21888
+ strokeWidth: 2,
21889
+ strokeLinecap: "round",
21890
+ strokeLinejoin: "round"
21891
+ }
21892
+ ) })
21893
+ }
21894
+ )
21895
+ }
21896
+ ) : null,
21790
21897
  /* @__PURE__ */ jsx71(NotificationBell, { count: unreadCount, onPress: () => navigateTo("notifications") }),
21791
21898
  /* @__PURE__ */ jsx71(PCSelect, { value: locale, options: languageOptions, onChange: handleLanguageChange, placeholder: t("language"), compact: true }),
21792
21899
  /* @__PURE__ */ jsx71(
@@ -21863,6 +21970,21 @@ var styles57 = StyleSheet58.create({
21863
21970
  alignItems: "center",
21864
21971
  justifyContent: "center"
21865
21972
  },
21973
+ iconButton: {
21974
+ width: MIN_TAP_TARGET,
21975
+ height: MIN_TAP_TARGET,
21976
+ alignItems: "center",
21977
+ justifyContent: "center"
21978
+ },
21979
+ // Matches the Flutter navbar's 34pt bordered circle.
21980
+ iconCircle: {
21981
+ width: 34,
21982
+ height: 34,
21983
+ borderRadius: 17,
21984
+ borderWidth: 1,
21985
+ alignItems: "center",
21986
+ justifyContent: "center"
21987
+ },
21866
21988
  pageHeader: {
21867
21989
  marginTop: spacing.sm
21868
21990
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redacto.io/consent-sdk-react-native",
3
- "version": "5.0.0-beta.8",
3
+ "version": "5.0.0",
4
4
  "description": "React Native SDK for integrating Redacto consent notices and privacy center in mobile apps.",
5
5
  "keywords": [
6
6
  "consent",