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

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.
@@ -33,12 +33,20 @@ var languageOptions = [
33
33
  ];
34
34
  var codeByLabel = new Map(languageOptions.map((o) => [o.label, o.value]));
35
35
  var codeByLower = new Map(languageOptions.map((o) => [o.value.toLowerCase(), o.value]));
36
- function toLanguageCode(lang) {
36
+ var englishName = (label) => {
37
37
  var _a, _b;
38
+ return (_b = (_a = label.match(/\(([^)]+)\)\s*$/)) == null ? void 0 : _a[1]) != null ? _b : label;
39
+ };
40
+ var codeByName = new Map(
41
+ languageOptions.map((o) => [englishName(o.label).toLowerCase(), o.value])
42
+ );
43
+ function toLanguageCode(lang) {
44
+ var _a, _b, _c;
38
45
  if (!lang) return void 0;
39
46
  const trimmed = lang.trim();
40
47
  if (!trimmed) return void 0;
41
- return (_b = (_a = codeByLabel.get(trimmed)) != null ? _a : codeByLower.get(trimmed.toLowerCase())) != null ? _b : trimmed;
48
+ const lower = trimmed.toLowerCase();
49
+ return (_c = (_b = (_a = codeByLabel.get(trimmed)) != null ? _a : codeByName.get(lower)) != null ? _b : codeByLower.get(lower)) != null ? _c : trimmed;
42
50
  }
43
51
 
44
52
  export {
package/dist/index.js CHANGED
@@ -74,12 +74,20 @@ var languageOptions = [
74
74
  ];
75
75
  var codeByLabel = new Map(languageOptions.map((o) => [o.label, o.value]));
76
76
  var codeByLower = new Map(languageOptions.map((o) => [o.value.toLowerCase(), o.value]));
77
- function toLanguageCode(lang) {
77
+ var englishName = (label) => {
78
78
  var _a, _b;
79
+ return (_b = (_a = label.match(/\(([^)]+)\)\s*$/)) == null ? void 0 : _a[1]) != null ? _b : label;
80
+ };
81
+ var codeByName = new Map(
82
+ languageOptions.map((o) => [englishName(o.label).toLowerCase(), o.value])
83
+ );
84
+ function toLanguageCode(lang) {
85
+ var _a, _b, _c;
79
86
  if (!lang) return void 0;
80
87
  const trimmed = lang.trim();
81
88
  if (!trimmed) return void 0;
82
- return (_b = (_a = codeByLabel.get(trimmed)) != null ? _a : codeByLower.get(trimmed.toLowerCase())) != null ? _b : trimmed;
89
+ const lower = trimmed.toLowerCase();
90
+ return (_c = (_b = (_a = codeByLabel.get(trimmed)) != null ? _a : codeByName.get(lower)) != null ? _b : codeByLower.get(lower)) != null ? _c : trimmed;
83
91
  }
84
92
 
85
93
  // src/RedactoNoticeConsent/api/index.ts
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  toLanguageCode
3
- } from "./chunk-IVOOB4JK.mjs";
3
+ } from "./chunk-UVRSRLYW.mjs";
4
4
 
5
5
  // src/RedactoNoticeConsent/RedactoNoticeConsent.tsx
6
6
  import {
@@ -5,6 +5,63 @@ import * as react_native from 'react-native';
5
5
  import { StyleProp, ViewStyle, TextStyle, KeyboardTypeOptions, DimensionValue, Animated } from 'react-native';
6
6
  import * as lucide_react_native from 'lucide-react-native';
7
7
 
8
+ interface ThemeColors {
9
+ background: string;
10
+ /** Page canvas. Flat mode keeps this equal to background. */
11
+ canvas: string;
12
+ surface: string;
13
+ text: string;
14
+ textSecondary: string;
15
+ border: string;
16
+ primary: string;
17
+ primaryText: string;
18
+ error: string;
19
+ success: string;
20
+ warning: string;
21
+ /** Hyperlink / accent text color. Falls back to primary. */
22
+ link: string;
23
+ /** Secondary brand color. Falls back to primary. */
24
+ secondary: string;
25
+ /** Quiet gray app background that cards sit on. */
26
+ canvasSubtle: string;
27
+ /** Secondary surface fill — inset rows, pressed states, skeletons. */
28
+ surfaceAlt: string;
29
+ /** Separator lighter than `border` (used inside cards). */
30
+ hairline: string;
31
+ /** Soft tint of `primary` for icon tiles / active pills. */
32
+ primarySoft: string;
33
+ /** Foreground (icon/label) color used on `primarySoft`. */
34
+ primaryOn: string;
35
+ /** Informational accent (badges / info states). */
36
+ info: string;
37
+ /** Soft status tints for badges, empty states, and icon tiles. */
38
+ successSoft: string;
39
+ warningSoft: string;
40
+ errorSoft: string;
41
+ infoSoft: string;
42
+ /** Scrim behind modals / bottom sheets. */
43
+ overlay: string;
44
+ }
45
+ type BrandingMeta = {
46
+ logo_url: string | null;
47
+ icon_url: string | null;
48
+ brand_name: string;
49
+ hide_platform_branding: boolean;
50
+ };
51
+ interface ThemeContextType {
52
+ colors: ThemeColors;
53
+ /** Org branding metadata (logo, brand name). Null until/unless it resolves. */
54
+ branding: BrandingMeta | null;
55
+ /** True while org branding is being fetched (used to gate first paint). */
56
+ isLoading: boolean;
57
+ }
58
+ declare function ThemeProvider({ children, slug, baseUrl, }: {
59
+ children: ReactNode;
60
+ slug?: string;
61
+ baseUrl?: string;
62
+ }): React.JSX.Element;
63
+ declare function useTheme(): ThemeContextType;
64
+
8
65
  type Workspace = {
9
66
  uuid: string;
10
67
  suid: string;
@@ -818,63 +875,6 @@ interface AuthProviderProps {
818
875
  declare function AuthProvider({ children, accessToken: initialAccessToken, refreshToken: initialRefreshToken, onError }: AuthProviderProps): React.JSX.Element;
819
876
  declare function useAuth(): AuthContextType;
820
877
 
821
- interface ThemeColors {
822
- background: string;
823
- /** Page canvas. Flat mode keeps this equal to background. */
824
- canvas: string;
825
- surface: string;
826
- text: string;
827
- textSecondary: string;
828
- border: string;
829
- primary: string;
830
- primaryText: string;
831
- error: string;
832
- success: string;
833
- warning: string;
834
- /** Hyperlink / accent text color. Falls back to primary. */
835
- link: string;
836
- /** Secondary brand color. Falls back to primary. */
837
- secondary: string;
838
- /** Quiet gray app background that cards sit on. */
839
- canvasSubtle: string;
840
- /** Secondary surface fill — inset rows, pressed states, skeletons. */
841
- surfaceAlt: string;
842
- /** Separator lighter than `border` (used inside cards). */
843
- hairline: string;
844
- /** Soft tint of `primary` for icon tiles / active pills. */
845
- primarySoft: string;
846
- /** Foreground (icon/label) color used on `primarySoft`. */
847
- primaryOn: string;
848
- /** Informational accent (badges / info states). */
849
- info: string;
850
- /** Soft status tints for badges, empty states, and icon tiles. */
851
- successSoft: string;
852
- warningSoft: string;
853
- errorSoft: string;
854
- infoSoft: string;
855
- /** Scrim behind modals / bottom sheets. */
856
- overlay: string;
857
- }
858
- type BrandingMeta = {
859
- logo_url: string | null;
860
- icon_url: string | null;
861
- brand_name: string;
862
- hide_platform_branding: boolean;
863
- };
864
- interface ThemeContextType {
865
- colors: ThemeColors;
866
- /** Org branding metadata (logo, brand name). Null until/unless it resolves. */
867
- branding: BrandingMeta | null;
868
- /** True while org branding is being fetched (used to gate first paint). */
869
- isLoading: boolean;
870
- }
871
- declare function ThemeProvider({ children, slug, baseUrl, }: {
872
- children: ReactNode;
873
- slug?: string;
874
- baseUrl?: string;
875
- }): React.JSX.Element;
876
- declare function useTheme(): ThemeContextType;
877
-
878
878
  /**
879
879
  * Curated icon registry. The whole Privacy Center draws icons through this one
880
880
  * component so sizing, stroke weight and color stay consistent and the icon
@@ -5,6 +5,63 @@ import * as react_native from 'react-native';
5
5
  import { StyleProp, ViewStyle, TextStyle, KeyboardTypeOptions, DimensionValue, Animated } from 'react-native';
6
6
  import * as lucide_react_native from 'lucide-react-native';
7
7
 
8
+ interface ThemeColors {
9
+ background: string;
10
+ /** Page canvas. Flat mode keeps this equal to background. */
11
+ canvas: string;
12
+ surface: string;
13
+ text: string;
14
+ textSecondary: string;
15
+ border: string;
16
+ primary: string;
17
+ primaryText: string;
18
+ error: string;
19
+ success: string;
20
+ warning: string;
21
+ /** Hyperlink / accent text color. Falls back to primary. */
22
+ link: string;
23
+ /** Secondary brand color. Falls back to primary. */
24
+ secondary: string;
25
+ /** Quiet gray app background that cards sit on. */
26
+ canvasSubtle: string;
27
+ /** Secondary surface fill — inset rows, pressed states, skeletons. */
28
+ surfaceAlt: string;
29
+ /** Separator lighter than `border` (used inside cards). */
30
+ hairline: string;
31
+ /** Soft tint of `primary` for icon tiles / active pills. */
32
+ primarySoft: string;
33
+ /** Foreground (icon/label) color used on `primarySoft`. */
34
+ primaryOn: string;
35
+ /** Informational accent (badges / info states). */
36
+ info: string;
37
+ /** Soft status tints for badges, empty states, and icon tiles. */
38
+ successSoft: string;
39
+ warningSoft: string;
40
+ errorSoft: string;
41
+ infoSoft: string;
42
+ /** Scrim behind modals / bottom sheets. */
43
+ overlay: string;
44
+ }
45
+ type BrandingMeta = {
46
+ logo_url: string | null;
47
+ icon_url: string | null;
48
+ brand_name: string;
49
+ hide_platform_branding: boolean;
50
+ };
51
+ interface ThemeContextType {
52
+ colors: ThemeColors;
53
+ /** Org branding metadata (logo, brand name). Null until/unless it resolves. */
54
+ branding: BrandingMeta | null;
55
+ /** True while org branding is being fetched (used to gate first paint). */
56
+ isLoading: boolean;
57
+ }
58
+ declare function ThemeProvider({ children, slug, baseUrl, }: {
59
+ children: ReactNode;
60
+ slug?: string;
61
+ baseUrl?: string;
62
+ }): React.JSX.Element;
63
+ declare function useTheme(): ThemeContextType;
64
+
8
65
  type Workspace = {
9
66
  uuid: string;
10
67
  suid: string;
@@ -818,63 +875,6 @@ interface AuthProviderProps {
818
875
  declare function AuthProvider({ children, accessToken: initialAccessToken, refreshToken: initialRefreshToken, onError }: AuthProviderProps): React.JSX.Element;
819
876
  declare function useAuth(): AuthContextType;
820
877
 
821
- interface ThemeColors {
822
- background: string;
823
- /** Page canvas. Flat mode keeps this equal to background. */
824
- canvas: string;
825
- surface: string;
826
- text: string;
827
- textSecondary: string;
828
- border: string;
829
- primary: string;
830
- primaryText: string;
831
- error: string;
832
- success: string;
833
- warning: string;
834
- /** Hyperlink / accent text color. Falls back to primary. */
835
- link: string;
836
- /** Secondary brand color. Falls back to primary. */
837
- secondary: string;
838
- /** Quiet gray app background that cards sit on. */
839
- canvasSubtle: string;
840
- /** Secondary surface fill — inset rows, pressed states, skeletons. */
841
- surfaceAlt: string;
842
- /** Separator lighter than `border` (used inside cards). */
843
- hairline: string;
844
- /** Soft tint of `primary` for icon tiles / active pills. */
845
- primarySoft: string;
846
- /** Foreground (icon/label) color used on `primarySoft`. */
847
- primaryOn: string;
848
- /** Informational accent (badges / info states). */
849
- info: string;
850
- /** Soft status tints for badges, empty states, and icon tiles. */
851
- successSoft: string;
852
- warningSoft: string;
853
- errorSoft: string;
854
- infoSoft: string;
855
- /** Scrim behind modals / bottom sheets. */
856
- overlay: string;
857
- }
858
- type BrandingMeta = {
859
- logo_url: string | null;
860
- icon_url: string | null;
861
- brand_name: string;
862
- hide_platform_branding: boolean;
863
- };
864
- interface ThemeContextType {
865
- colors: ThemeColors;
866
- /** Org branding metadata (logo, brand name). Null until/unless it resolves. */
867
- branding: BrandingMeta | null;
868
- /** True while org branding is being fetched (used to gate first paint). */
869
- isLoading: boolean;
870
- }
871
- declare function ThemeProvider({ children, slug, baseUrl, }: {
872
- children: ReactNode;
873
- slug?: string;
874
- baseUrl?: string;
875
- }): React.JSX.Element;
876
- declare function useTheme(): ThemeContextType;
877
-
878
878
  /**
879
879
  * Curated icon registry. The whole Privacy Center draws icons through this one
880
880
  * component so sizing, stroke weight and color stay consistent and the icon
@@ -11256,7 +11256,8 @@ var manageConsent = async ({
11256
11256
  nominatorContact,
11257
11257
  dataElementUuids,
11258
11258
  noticeUuid,
11259
- dataElements
11259
+ dataElements,
11260
+ language
11260
11261
  });
11261
11262
  }
11262
11263
  console.error(`Error ${action} consent:`, error);
@@ -14247,6 +14248,13 @@ var languageOptions = [
14247
14248
  ];
14248
14249
  var codeByLabel = new Map(languageOptions.map((o) => [o.label, o.value]));
14249
14250
  var codeByLower = new Map(languageOptions.map((o) => [o.value.toLowerCase(), o.value]));
14251
+ var englishName = (label) => {
14252
+ var _a3, _b;
14253
+ return (_b = (_a3 = label.match(/\(([^)]+)\)\s*$/)) == null ? void 0 : _a3[1]) != null ? _b : label;
14254
+ };
14255
+ var codeByName = new Map(
14256
+ languageOptions.map((o) => [englishName(o.label).toLowerCase(), o.value])
14257
+ );
14250
14258
 
14251
14259
  // src/RedactoPrivacyCenter/lib/constants.ts
14252
14260
  var PAGE_CHROME_BY_PAGE = {
@@ -15630,10 +15638,10 @@ var import_react_i18next14 = require("react-i18next");
15630
15638
  // src/RedactoPrivacyCenter/lib/dateGroup.ts
15631
15639
  var import_react27 = require("react");
15632
15640
  var import_react_i18next13 = require("react-i18next");
15633
- function monthKey(ts) {
15641
+ function monthKey(ts, locale) {
15634
15642
  if (!ts) return "";
15635
15643
  try {
15636
- return new Date(ts).toLocaleDateString(void 0, { month: "long", year: "numeric" });
15644
+ return new Date(ts).toLocaleDateString(locale || void 0, { month: "long", year: "numeric" });
15637
15645
  } catch {
15638
15646
  return "";
15639
15647
  }
@@ -15709,7 +15717,7 @@ function groupByTime(items, getTs, classify) {
15709
15717
  );
15710
15718
  }
15711
15719
  function useRelativeDate() {
15712
- const { t } = (0, import_react_i18next13.useTranslation)();
15720
+ const { t, i18n: i18n2 } = (0, import_react_i18next13.useTranslation)();
15713
15721
  return (0, import_react27.useCallback)(
15714
15722
  (ts) => {
15715
15723
  if (!ts) return "";
@@ -15722,7 +15730,7 @@ function useRelativeDate() {
15722
15730
  if (dayDiff <= 0) return t("today", { defaultValue: "Today" });
15723
15731
  if (dayDiff === 1) return t("yesterday", { defaultValue: "Yesterday" });
15724
15732
  if (dayDiff < 7) return t("daysAgo", { count: dayDiff, defaultValue: "{{count}} days ago" });
15725
- return d.toLocaleDateString(void 0, {
15733
+ return d.toLocaleDateString(i18n2.language || void 0, {
15726
15734
  month: "short",
15727
15735
  day: "numeric",
15728
15736
  ...d.getFullYear() !== now.getFullYear() ? { year: "numeric" } : {}
@@ -15731,10 +15739,28 @@ function useRelativeDate() {
15731
15739
  return ts;
15732
15740
  }
15733
15741
  },
15734
- [t]
15742
+ [t, i18n2.language]
15735
15743
  );
15736
15744
  }
15737
15745
 
15746
+ // src/RedactoPrivacyCenter/lib/receiptEvent.ts
15747
+ function eventLabelKey(eventType) {
15748
+ const v = String(eventType || "").toUpperCase();
15749
+ if (v.includes("GRANT")) {
15750
+ return "consentGranted";
15751
+ }
15752
+ if (v.includes("WITHDRAW") || v.includes("REVOK")) {
15753
+ return "consentRevoked";
15754
+ }
15755
+ if (v.includes("DECLIN")) {
15756
+ return "consentDeclined";
15757
+ }
15758
+ if (v.includes("EXPIR")) {
15759
+ return "consentExpired";
15760
+ }
15761
+ return void 0;
15762
+ }
15763
+
15738
15764
  // src/RedactoPrivacyCenter/components/ReceiptsList.tsx
15739
15765
  var import_jsx_runtime41 = require("react/jsx-runtime");
15740
15766
  var PAGE_SIZE2 = 10;
@@ -15770,11 +15796,10 @@ function receiptBadgeStatus(eventType) {
15770
15796
  if (v.includes("EXPIR")) return "warning";
15771
15797
  return "secondary";
15772
15798
  }
15773
- var ReceiptRow = import_react28.default.memo(({ item, colors, downloading, onDownload, downloadLabel, dateLabel }) => {
15799
+ var ReceiptRow = import_react28.default.memo(({ item, colors, downloading, onDownload, downloadLabel, dateLabel, eventLabel }) => {
15774
15800
  const product = item.product_name_display || item.product_name || "";
15775
- const event = item.event_type_display || item.event_type || "";
15776
- const primary = product || event || "-";
15777
- const badgeLabel = event || "-";
15801
+ const primary = product || eventLabel || "-";
15802
+ const badgeLabel = eventLabel || "-";
15778
15803
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react_native41.View, { style: styles31.row, children: [
15779
15804
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(NameAvatar, { name: primary, seed: item.uuid || primary, size: "sm" }),
15780
15805
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react_native41.View, { style: styles31.body, children: [
@@ -15801,7 +15826,7 @@ var ReceiptRow = import_react28.default.memo(({ item, colors, downloading, onDow
15801
15826
  });
15802
15827
  ReceiptRow.displayName = "ReceiptRow";
15803
15828
  function ReceiptsList() {
15804
- const { t } = (0, import_react_i18next14.useTranslation)();
15829
+ const { t, i18n: i18n2 } = (0, import_react_i18next14.useTranslation)();
15805
15830
  const { accessToken, refreshToken, organizationId, workspaceId, updateTokens, onError } = useAuth();
15806
15831
  const { consentClient } = useBaseUrl();
15807
15832
  const { colors } = useTheme();
@@ -15886,14 +15911,18 @@ function ReceiptsList() {
15886
15911
  const sections = (0, import_react28.useMemo)(() => {
15887
15912
  const map = /* @__PURE__ */ new Map();
15888
15913
  for (const r of receipts) {
15889
- const key = monthKey(r.created_at);
15914
+ const key = monthKey(r.created_at, i18n2.language);
15890
15915
  const arr = map.get(key);
15891
15916
  if (arr) arr.push(r);
15892
15917
  else map.set(key, [r]);
15893
15918
  }
15894
15919
  return Array.from(map, ([title, data]) => ({ title, data }));
15895
- }, [receipts]);
15920
+ }, [receipts, i18n2.language]);
15896
15921
  const downloadLabel = t("download") || "Download";
15922
+ const eventLabelFor = (r) => {
15923
+ const key = eventLabelKey(r.event_type);
15924
+ return key ? t(key) : r.event_type_display || r.event_type || "-";
15925
+ };
15897
15926
  const handleScroll = (0, import_react28.useCallback)(
15898
15927
  (e) => {
15899
15928
  const { layoutMeasurement, contentOffset, contentSize } = e.nativeEvent;
@@ -15975,7 +16004,8 @@ function ReceiptsList() {
15975
16004
  downloading: downloadingUuid === item.uuid,
15976
16005
  onDownload: handleDownload,
15977
16006
  downloadLabel,
15978
- dateLabel: relativeLabel(item.created_at)
16007
+ dateLabel: relativeLabel(item.created_at),
16008
+ eventLabel: eventLabelFor(item)
15979
16009
  }
15980
16010
  )
15981
16011
  ] }, `${item.uuid || item.created_at}-${index}`)) }, section2.title)),
@@ -16659,6 +16689,11 @@ function Form({ onCreateRequest }) {
16659
16689
  const isFormValid = (0, import_react29.useMemo)(() => detailsValid && confirmChecked, [detailsValid, confirmChecked]);
16660
16690
  const handleUpload = (0, import_react29.useCallback)(async () => {
16661
16691
  if (!organizationId || !workspaceId) return;
16692
+ const caseUuid = formDataResponse == null ? void 0 : formDataResponse.uuid;
16693
+ if (!caseUuid) {
16694
+ import_react_native44.Alert.alert(t("uploadFile"), t("unableToUpload") || "Unable to upload file. Please try again.");
16695
+ return;
16696
+ }
16662
16697
  try {
16663
16698
  const file = await pickFile();
16664
16699
  if (!file) return;
@@ -16675,11 +16710,11 @@ function Form({ onCreateRequest }) {
16675
16710
  "payload",
16676
16711
  JSON.stringify({
16677
16712
  organization_uuid: organizationId || "",
16678
- space: `privacy/${docUuid}`,
16713
+ space: `privacy/${caseUuid}`,
16679
16714
  uuid: docUuid,
16680
16715
  is_public: true,
16681
16716
  allow_ai_processing: true,
16682
- metadata: { group_by: "privacy", product: "privacy_center" }
16717
+ metadata: { group_by: "privacy", case_uuid: caseUuid, product: "privacy_center" }
16683
16718
  })
16684
16719
  );
16685
16720
  const result = await uploadFileWithS2S({
@@ -16699,7 +16734,7 @@ function Form({ onCreateRequest }) {
16699
16734
  } finally {
16700
16735
  setIsUploading(false);
16701
16736
  }
16702
- }, [organizationId, workspaceId, authContext, consentClient, baseUrl, t]);
16737
+ }, [organizationId, workspaceId, authContext, consentClient, baseUrl, t, formDataResponse]);
16703
16738
  const removeUploadedDoc = (0, import_react29.useCallback)((uuid) => {
16704
16739
  setUploadedDocs((prev) => prev.filter((d) => d.uuid !== uuid));
16705
16740
  }, []);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  __require,
3
3
  languageOptions
4
- } from "./chunk-IVOOB4JK.mjs";
4
+ } from "./chunk-UVRSRLYW.mjs";
5
5
 
6
6
  // src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx
7
7
  import { useEffect as useEffect20 } from "react";
@@ -11143,7 +11143,8 @@ var manageConsent = async ({
11143
11143
  nominatorContact,
11144
11144
  dataElementUuids,
11145
11145
  noticeUuid,
11146
- dataElements
11146
+ dataElements,
11147
+ language
11147
11148
  });
11148
11149
  }
11149
11150
  console.error(`Error ${action} consent:`, error);
@@ -15626,10 +15627,10 @@ import { useTranslation as useTranslation13 } from "react-i18next";
15626
15627
  // src/RedactoPrivacyCenter/lib/dateGroup.ts
15627
15628
  import { useCallback as useCallback8 } from "react";
15628
15629
  import { useTranslation as useTranslation12 } from "react-i18next";
15629
- function monthKey(ts) {
15630
+ function monthKey(ts, locale) {
15630
15631
  if (!ts) return "";
15631
15632
  try {
15632
- return new Date(ts).toLocaleDateString(void 0, { month: "long", year: "numeric" });
15633
+ return new Date(ts).toLocaleDateString(locale || void 0, { month: "long", year: "numeric" });
15633
15634
  } catch {
15634
15635
  return "";
15635
15636
  }
@@ -15705,7 +15706,7 @@ function groupByTime(items, getTs, classify) {
15705
15706
  );
15706
15707
  }
15707
15708
  function useRelativeDate() {
15708
- const { t } = useTranslation12();
15709
+ const { t, i18n: i18n2 } = useTranslation12();
15709
15710
  return useCallback8(
15710
15711
  (ts) => {
15711
15712
  if (!ts) return "";
@@ -15718,7 +15719,7 @@ function useRelativeDate() {
15718
15719
  if (dayDiff <= 0) return t("today", { defaultValue: "Today" });
15719
15720
  if (dayDiff === 1) return t("yesterday", { defaultValue: "Yesterday" });
15720
15721
  if (dayDiff < 7) return t("daysAgo", { count: dayDiff, defaultValue: "{{count}} days ago" });
15721
- return d.toLocaleDateString(void 0, {
15722
+ return d.toLocaleDateString(i18n2.language || void 0, {
15722
15723
  month: "short",
15723
15724
  day: "numeric",
15724
15725
  ...d.getFullYear() !== now.getFullYear() ? { year: "numeric" } : {}
@@ -15727,10 +15728,28 @@ function useRelativeDate() {
15727
15728
  return ts;
15728
15729
  }
15729
15730
  },
15730
- [t]
15731
+ [t, i18n2.language]
15731
15732
  );
15732
15733
  }
15733
15734
 
15735
+ // src/RedactoPrivacyCenter/lib/receiptEvent.ts
15736
+ function eventLabelKey(eventType) {
15737
+ const v = String(eventType || "").toUpperCase();
15738
+ if (v.includes("GRANT")) {
15739
+ return "consentGranted";
15740
+ }
15741
+ if (v.includes("WITHDRAW") || v.includes("REVOK")) {
15742
+ return "consentRevoked";
15743
+ }
15744
+ if (v.includes("DECLIN")) {
15745
+ return "consentDeclined";
15746
+ }
15747
+ if (v.includes("EXPIR")) {
15748
+ return "consentExpired";
15749
+ }
15750
+ return void 0;
15751
+ }
15752
+
15734
15753
  // src/RedactoPrivacyCenter/components/ReceiptsList.tsx
15735
15754
  import { Fragment as Fragment7, jsx as jsx41, jsxs as jsxs25 } from "react/jsx-runtime";
15736
15755
  var PAGE_SIZE2 = 10;
@@ -15766,11 +15785,10 @@ function receiptBadgeStatus(eventType) {
15766
15785
  if (v.includes("EXPIR")) return "warning";
15767
15786
  return "secondary";
15768
15787
  }
15769
- var ReceiptRow = React15.memo(({ item, colors, downloading, onDownload, downloadLabel, dateLabel }) => {
15788
+ var ReceiptRow = React15.memo(({ item, colors, downloading, onDownload, downloadLabel, dateLabel, eventLabel }) => {
15770
15789
  const product = item.product_name_display || item.product_name || "";
15771
- const event = item.event_type_display || item.event_type || "";
15772
- const primary = product || event || "-";
15773
- const badgeLabel = event || "-";
15790
+ const primary = product || eventLabel || "-";
15791
+ const badgeLabel = eventLabel || "-";
15774
15792
  return /* @__PURE__ */ jsxs25(View30, { style: styles31.row, children: [
15775
15793
  /* @__PURE__ */ jsx41(NameAvatar, { name: primary, seed: item.uuid || primary, size: "sm" }),
15776
15794
  /* @__PURE__ */ jsxs25(View30, { style: styles31.body, children: [
@@ -15797,7 +15815,7 @@ var ReceiptRow = React15.memo(({ item, colors, downloading, onDownload, download
15797
15815
  });
15798
15816
  ReceiptRow.displayName = "ReceiptRow";
15799
15817
  function ReceiptsList() {
15800
- const { t } = useTranslation13();
15818
+ const { t, i18n: i18n2 } = useTranslation13();
15801
15819
  const { accessToken, refreshToken, organizationId, workspaceId, updateTokens, onError } = useAuth();
15802
15820
  const { consentClient } = useBaseUrl();
15803
15821
  const { colors } = useTheme();
@@ -15882,14 +15900,18 @@ function ReceiptsList() {
15882
15900
  const sections = useMemo13(() => {
15883
15901
  const map = /* @__PURE__ */ new Map();
15884
15902
  for (const r of receipts) {
15885
- const key = monthKey(r.created_at);
15903
+ const key = monthKey(r.created_at, i18n2.language);
15886
15904
  const arr = map.get(key);
15887
15905
  if (arr) arr.push(r);
15888
15906
  else map.set(key, [r]);
15889
15907
  }
15890
15908
  return Array.from(map, ([title, data]) => ({ title, data }));
15891
- }, [receipts]);
15909
+ }, [receipts, i18n2.language]);
15892
15910
  const downloadLabel = t("download") || "Download";
15911
+ const eventLabelFor = (r) => {
15912
+ const key = eventLabelKey(r.event_type);
15913
+ return key ? t(key) : r.event_type_display || r.event_type || "-";
15914
+ };
15893
15915
  const handleScroll = useCallback9(
15894
15916
  (e) => {
15895
15917
  const { layoutMeasurement, contentOffset, contentSize } = e.nativeEvent;
@@ -15971,7 +15993,8 @@ function ReceiptsList() {
15971
15993
  downloading: downloadingUuid === item.uuid,
15972
15994
  onDownload: handleDownload,
15973
15995
  downloadLabel,
15974
- dateLabel: relativeLabel(item.created_at)
15996
+ dateLabel: relativeLabel(item.created_at),
15997
+ eventLabel: eventLabelFor(item)
15975
15998
  }
15976
15999
  )
15977
16000
  ] }, `${item.uuid || item.created_at}-${index}`)) }, section2.title)),
@@ -16663,6 +16686,11 @@ function Form({ onCreateRequest }) {
16663
16686
  const isFormValid = useMemo14(() => detailsValid && confirmChecked, [detailsValid, confirmChecked]);
16664
16687
  const handleUpload = useCallback10(async () => {
16665
16688
  if (!organizationId || !workspaceId) return;
16689
+ const caseUuid = formDataResponse == null ? void 0 : formDataResponse.uuid;
16690
+ if (!caseUuid) {
16691
+ Alert5.alert(t("uploadFile"), t("unableToUpload") || "Unable to upload file. Please try again.");
16692
+ return;
16693
+ }
16666
16694
  try {
16667
16695
  const file = await pickFile();
16668
16696
  if (!file) return;
@@ -16679,11 +16707,11 @@ function Form({ onCreateRequest }) {
16679
16707
  "payload",
16680
16708
  JSON.stringify({
16681
16709
  organization_uuid: organizationId || "",
16682
- space: `privacy/${docUuid}`,
16710
+ space: `privacy/${caseUuid}`,
16683
16711
  uuid: docUuid,
16684
16712
  is_public: true,
16685
16713
  allow_ai_processing: true,
16686
- metadata: { group_by: "privacy", product: "privacy_center" }
16714
+ metadata: { group_by: "privacy", case_uuid: caseUuid, product: "privacy_center" }
16687
16715
  })
16688
16716
  );
16689
16717
  const result = await uploadFileWithS2S({
@@ -16703,7 +16731,7 @@ function Form({ onCreateRequest }) {
16703
16731
  } finally {
16704
16732
  setIsUploading(false);
16705
16733
  }
16706
- }, [organizationId, workspaceId, authContext, consentClient, baseUrl, t]);
16734
+ }, [organizationId, workspaceId, authContext, consentClient, baseUrl, t, formDataResponse]);
16707
16735
  const removeUploadedDoc = useCallback10((uuid) => {
16708
16736
  setUploadedDocs((prev) => prev.filter((d) => d.uuid !== uuid));
16709
16737
  }, []);
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.3",
3
+ "version": "5.0.0-beta.5",
4
4
  "description": "React Native SDK for integrating Redacto consent notices and privacy center in mobile apps.",
5
5
  "keywords": [
6
6
  "consent",