@redacto.io/consent-sdk-react 9.2.0-beta.2 → 9.3.0-beta.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.
Files changed (39) hide show
  1. package/.turbo/turbo-build.log +25 -26
  2. package/.turbo/turbo-test.log +203 -0
  3. package/.turbo/turbo-verify-pack.log +6 -0
  4. package/CHANGELOG.md +24 -0
  5. package/dist/privacy-center.js +2428 -2223
  6. package/dist/privacy-center.mjs +2572 -2359
  7. package/package.json +3 -3
  8. package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +6 -3
  9. package/src/RedactoPrivacyCenter/components/AppShell/AppShell.tsx +36 -5
  10. package/src/RedactoPrivacyCenter/components/AppShell/TopAppBar.tsx +3 -2
  11. package/src/RedactoPrivacyCenter/components/PrivacyCenterEmptyState.tsx +76 -0
  12. package/src/RedactoPrivacyCenter/components/ReceiptsList.tsx +3 -41
  13. package/src/RedactoPrivacyCenter/context/DataAvailabilityContext.tsx +169 -0
  14. package/src/RedactoPrivacyCenter/locales/as/translation.json +2 -0
  15. package/src/RedactoPrivacyCenter/locales/bho/translation.json +2 -0
  16. package/src/RedactoPrivacyCenter/locales/bn/translation.json +2 -0
  17. package/src/RedactoPrivacyCenter/locales/brx/translation.json +2 -0
  18. package/src/RedactoPrivacyCenter/locales/doi/translation.json +2 -0
  19. package/src/RedactoPrivacyCenter/locales/en/translation.json +2 -0
  20. package/src/RedactoPrivacyCenter/locales/gom/translation.json +2 -0
  21. package/src/RedactoPrivacyCenter/locales/gu/translation.json +2 -0
  22. package/src/RedactoPrivacyCenter/locales/hi/translation.json +2 -0
  23. package/src/RedactoPrivacyCenter/locales/kn/translation.json +2 -0
  24. package/src/RedactoPrivacyCenter/locales/ks/translation.json +2 -0
  25. package/src/RedactoPrivacyCenter/locales/mai/translation.json +2 -0
  26. package/src/RedactoPrivacyCenter/locales/ml/translation.json +2 -0
  27. package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +2 -0
  28. package/src/RedactoPrivacyCenter/locales/mr/translation.json +2 -0
  29. package/src/RedactoPrivacyCenter/locales/ne/translation.json +2 -0
  30. package/src/RedactoPrivacyCenter/locales/or/translation.json +2 -0
  31. package/src/RedactoPrivacyCenter/locales/pa/translation.json +2 -0
  32. package/src/RedactoPrivacyCenter/locales/sa/translation.json +2 -0
  33. package/src/RedactoPrivacyCenter/locales/sat/translation.json +2 -0
  34. package/src/RedactoPrivacyCenter/locales/sd/translation.json +2 -0
  35. package/src/RedactoPrivacyCenter/locales/ta/translation.json +2 -0
  36. package/src/RedactoPrivacyCenter/locales/te/translation.json +2 -0
  37. package/src/RedactoPrivacyCenter/locales/ur/translation.json +2 -0
  38. package/src/RedactoPrivacyCenter/styles/injectStyles.ts +1 -1
  39. package/tests/DataAvailabilityContext.test.tsx +123 -0
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "ꯁꯤꯕꯒꯤ ꯄꯣꯠꯁꯤꯡ",
183
183
  "close": "ꯁꯥꯕ",
184
184
  "noData": "ꯗꯦꯇꯥ ꯂꯩꯇꯦ",
185
+ "noDataTitle": "ꯍꯧꯖꯤꯛ ꯐꯥꯎꯕ ꯎꯠꯅꯕ ꯀꯔꯤꯁꯨ ꯂꯩꯇꯦ",
186
+ "noDataDescription": "ꯍꯧꯖꯤꯛ ꯐꯥꯎꯕ ꯑꯗꯣꯝꯒꯤ ꯑꯀꯥꯎꯟꯇꯀ ꯁꯝꯅꯗꯨꯅ ꯀꯅꯁꯦꯟꯇ, ꯍꯧꯔꯛꯐꯝ, ꯅꯠꯇ꯭ꯔꯒ ꯈꯨꯗꯝꯕꯤꯠ ꯑꯃꯠꯇ ꯐꯪꯗꯔꯦ꯫ ꯑꯗꯣꯝꯒꯤ ꯄ꯭ꯔꯥꯏꯚꯦꯁꯤ ꯔꯤꯀꯣꯔꯗꯁꯤꯡ ꯐꯪꯂꯛꯄ ꯃꯇꯃꯗ ꯃꯐꯝ ꯑꯁꯤꯗ ꯎꯔꯛꯀꯅꯤ꯫",
185
187
  "rowsPerPage": "ꯂꯦꯡꯒꯤ ꯃꯔꯨꯑꯣꯏꯕ:",
186
188
  "pageOf": "ꯂꯦꯡ {{current}} / {{total}}",
187
189
  "rowsSelected": "{{total}} ꯒꯤ ꯃꯔꯨꯑꯣꯏꯕ {{count}} ꯁꯤꯄ ꯈꯨꯟꯁꯥꯖꯈꯔꯦ",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "तक्रार प्रकार",
183
183
  "close": "बंद करा",
184
184
  "noData": "डेटा नाही",
185
+ "noDataTitle": "अद्याप दाखवण्यासारखे काही नाही",
186
+ "noDataDescription": "तुमच्या खात्याशी संबंधित कोणत्याही संमती, विनंत्या किंवा क्रियाकलाप अद्याप आम्हाला आढळले नाहीत. उपलब्ध होताच तुमच्या गोपनीयता नोंदी येथे दिसतील.",
185
187
  "rowsPerPage": "प्रति पृष्ठ पंक्ती:",
186
188
  "pageOf": "पृष्ठ {{current}} / {{total}}",
187
189
  "rowsSelected": "{{total}} पैकी {{count}} पंक्ती निवडली",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "गुनासो प्रकारहरू",
183
183
  "close": "बन्द गर्नुहोस्",
184
184
  "noData": "डेटा छैन",
185
+ "noDataTitle": "अहिलेसम्म देखाउने केही छैन",
186
+ "noDataDescription": "तपाईंको खातासँग जोडिएका कुनै सहमति, अनुरोध वा गतिविधि हामीले अहिलेसम्म फेला पारेनौं। उपलब्ध भएपछि तपाईंका गोपनीयता रेकर्डहरू यहाँ देखिनेछन्।",
185
187
  "rowsPerPage": "पृष्ठ प्रति पङ्क्तिहरू:",
186
188
  "pageOf": "पृष्ठ {{current}} / {{total}}",
187
189
  "rowsSelected": "{{total}} मध्ये {{count}} पङ्क्ति चयन गरियो",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "ଅଭିଯୋଗ ପ୍ରକାର",
183
183
  "close": "ବନ୍ଦ କରନ୍ତୁ",
184
184
  "noData": "ତଥ୍ୟ ନାହିଁ",
185
+ "noDataTitle": "ଏପର୍ଯ୍ୟନ୍ତ ଦେଖାଇବାକୁ କିଛି ନାହିଁ",
186
+ "noDataDescription": "ଆପଣଙ୍କ ଆକାଉଣ୍ଟ ସହିତ ସଂଯୁକ୍ତ କୌଣସି ସମ୍ମତି, ଅନୁରୋଧ କିମ୍ବା କାର୍ଯ୍ୟକଳାପ ଆମେ ଏପର୍ଯ୍ୟନ୍ତ ପାଇଲୁ ନାହିଁ। ଉପଲବ୍ଧ ହେବା ମାତ୍ରେ ଆପଣଙ୍କ ଗୋପନୀୟତା ରେକର୍ଡ ଏଠାରେ ଦେଖାଯିବ।",
185
187
  "rowsPerPage": "ପୃଷ୍ଠାକୁ ଧାଡ଼ି:",
186
188
  "pageOf": "ପୃଷ୍ଠା {{current}} / {{total}}",
187
189
  "rowsSelected": "{{total}} ରୁ {{count}} ଧାଡ଼ି ବାଛିଲେ",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "ਸ਼ਿਕਾਇਤ ਕਿਸਮਾਂ",
183
183
  "close": "ਬੰਦ ਕਰੋ",
184
184
  "noData": "ਕੋਈ ਡੇਟਾ ਨਹੀਂ",
185
+ "noDataTitle": "ਅਜੇ ਦਿਖਾਉਣ ਲਈ ਕੁਝ ਨਹੀਂ",
186
+ "noDataDescription": "ਅਸੀਂ ਤੁਹਾਡੇ ਖਾਤੇ ਨਾਲ ਜੁੜੀ ਕੋਈ ਸਹਿਮਤੀ, ਬੇਨਤੀ ਜਾਂ ਗਤੀਵਿਧੀ ਅਜੇ ਨਹੀਂ ਲੱਭ ਸਕੇ। ਤੁਹਾਡੇ ਗੋਪਨੀਯਤਾ ਰਿਕਾਰਡ ਉਪਲਬਧ ਹੁੰਦੇ ਹੀ ਇੱਥੇ ਦਿਖਾਈ ਦੇਣਗੇ।",
185
187
  "rowsPerPage": "ਪੰਨੇ ਪ੍ਰਤੀ ਕਤਾਰਾਂ:",
186
188
  "pageOf": "ਪੰਨਾ {{current}} / {{total}}",
187
189
  "rowsSelected": "{{total}} ਵਿੱਚੋਂ {{count}} ਕਤਾਰ ਚੁਣੀ ਗਈ",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "अभियोगप्रकाराः",
183
183
  "close": "समापय",
184
184
  "noData": "डेटा नास्ति",
185
+ "noDataTitle": "अद्यापि किमपि दर्शयितुं नास्ति",
186
+ "noDataDescription": "भवतः खातया सह सम्बद्धाः काश्चन सम्मतयः, अनुरोधाः, कार्यकलापाः वा अद्यापि अस्माभिः न प्राप्ताः। उपलब्धाः सति भवतः गोपनीयता-अभिलेखाः अत्र दर्शयिष्यन्ते।",
185
187
  "rowsPerPage": "पृष्ठे पंक्तयः:",
186
188
  "pageOf": "पृष्ठम् {{current}} / {{total}}",
187
189
  "rowsSelected": "{{total}} मध्ये {{count}} पंक्तिः चिता",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "ᱩᱯᱟᱹᱭ ᱞᱮᱠᱟᱱ",
183
183
  "close": "ᱵᱚᱸᱫᱚ",
184
184
  "noData": "ᱰᱮᱴᱟ ᱵᱟᱹᱱᱩᱜᱼᱟ",
185
+ "noDataTitle": "ᱱᱤᱛ ᱛᱟᱠ ᱡᱟᱦᱟᱸ ᱫᱮᱠᱷᱟᱣ ᱞᱟᱹᱜᱤᱫ ᱵᱟᱝ",
186
+ "noDataDescription": "ᱟᱞᱮ ᱱᱤᱛ ᱛᱟᱠ ᱟᱢᱟᱜ ᱮᱠᱟᱣᱩᱱᱴ ᱥᱟᱞᱟᱜ ᱡᱚᱲᱟᱣ ᱡᱟᱦᱟᱸ ᱥᱚᱦᱚᱢᱚᱛᱤ, ᱦᱟᱵᱟᱭ, ᱟᱨᱵᱟᱝ ᱠᱟᱹᱢᱤ ᱵᱟᱝ ᱧᱟᱢ ᱫᱟᱲᱮᱭᱟᱫᱼᱟ᱾ ᱟᱢᱟᱜ ᱯᱨᱟᱭᱣᱮᱥᱤ ᱨᱤᱠᱚᱨᱰ ᱠᱚ ᱧᱟᱢᱚᱜ ᱠᱷᱟᱱ ᱱᱚᱸᱰᱮ ᱫᱮᱠᱷᱟᱣᱚᱜᱼᱟ᱾",
185
187
  "rowsPerPage": "ᱯᱮᱡᱽ ᱯᱤᱨᱤ ᱪᱷᱩᱴᱟᱹ:",
186
188
  "pageOf": "ᱯᱮᱡᱽ {{current}} / {{total}}",
187
189
  "rowsSelected": "{{total}} ᱠᱷᱚᱱ {{count}} ᱪᱷᱩᱴᱟᱹ ᱵᱟᱪᱷᱟᱣ",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "شڪايت قسمن",
183
183
  "close": "بند ڪريو",
184
184
  "noData": "ڊيٽا ڪانهي",
185
+ "noDataTitle": "اڃا ڏيکارڻ لاءِ ڪجهه ناهي",
186
+ "noDataDescription": "اسان کي اڃا تائين توهان جي اڪائونٽ سان لاڳاپيل ڪابه رضامندي، درخواست يا سرگرمي نه ملي. توهان جا رازداري رڪارڊ موجود ٿيندي ئي هتي ظاهر ٿيندا.",
185
187
  "rowsPerPage": "صفحي في قطارون:",
186
188
  "pageOf": "صفحو {{current}} / {{total}}",
187
189
  "rowsSelected": "{{total}} مان {{count}} قطار چونڊيل",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "முறையீட்டு வகைகள்",
183
183
  "close": "மூடு",
184
184
  "noData": "தரவு இல்லை",
185
+ "noDataTitle": "இன்னும் காட்ட எதுவும் இல்லை",
186
+ "noDataDescription": "உங்கள் கணக்குடன் இணைக்கப்பட்ட ஒப்புதல்கள், கோரிக்கைகள் அல்லது செயல்பாடு எதையும் இன்னும் எங்களால் கண்டறிய முடியவில்லை. உங்கள் தனியுரிமை பதிவுகள் கிடைக்கும்போது அவை இங்கே தோன்றும்.",
185
187
  "rowsPerPage": "பக்கத்திற்கு வரிசைகள்:",
186
188
  "pageOf": "பக்கம் {{current}} / {{total}}",
187
189
  "rowsSelected": "{{count}} / {{total}} வரிசைத் தேர்ந்தெடுக்கப்பட்டது",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "ఫిర్యాదు రకాలు",
183
183
  "close": "మూసివేయండి",
184
184
  "noData": "డేటా లేదు",
185
+ "noDataTitle": "చూపించడానికి ఇంకా ఏమీ లేదు",
186
+ "noDataDescription": "మీ ఖాతాకు అనుసంధానించబడిన ఏ సమ్మతులు, అభ్యర్థనలు లేదా కార్యాచరణ ఇంకా మాకు కనుగొనబడలేదు. అందుబాటులోకి వచ్చిన తర్వాత మీ గోప్యతా రికార్డులు ఇక్కడ కనిపిస్తాయి.",
185
187
  "rowsPerPage": "పేజీకి వరుసలు:",
186
188
  "pageOf": "పేజీ {{current}} / {{total}}",
187
189
  "rowsSelected": "{{total}}లో {{count}} వరుస ఎంచుకోబడింది",
@@ -182,6 +182,8 @@
182
182
  "grievanceTypes": "شکایت کی اقسام",
183
183
  "close": "بند کریں",
184
184
  "noData": "کوئی ڈیٹا نہیں",
185
+ "noDataTitle": "ابھی دکھانے کے لیے کچھ نہیں",
186
+ "noDataDescription": "ہمیں ابھی تک آپ کے اکاؤنٹ سے منسلک کوئی رضامندی، درخواست یا سرگرمی نہیں ملی۔ آپ کے پرائیویسی ریکارڈ دستیاب ہوتے ہی یہاں ظاہر ہو جائیں گے۔",
185
187
  "rowsPerPage": "فی صفحہ قطاریں:",
186
188
  "pageOf": "صفحہ {{current}} / {{total}}",
187
189
  "rowsSelected": "{{count}} از {{total}} قطار منتخب",
@@ -1175,7 +1175,7 @@ export const injectPCStyles = () => {
1175
1175
  }
1176
1176
  @media (min-width: 1024px) {
1177
1177
  .pc-receipts-filters-grid {
1178
- grid-template-columns: repeat(3, minmax(0, 1fr));
1178
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1179
1179
  }
1180
1180
  }
1181
1181
 
@@ -0,0 +1,123 @@
1
+ import { render, screen, waitFor } from '@testing-library/react';
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
+
4
+ // ─── API stubs ───────────────────────────────────────────────────────────────
5
+ // The gate calls the direct fetchers (NOT react-query hooks). Each returns
6
+ // `null` on error in production; we exercise both null and rejection paths.
7
+ const fetchUserConsents = vi.fn();
8
+ const fetchCaseHistory = vi.fn();
9
+ const fetchActivities = vi.fn();
10
+ vi.mock('../src/RedactoPrivacyCenter/lib/api', () => ({
11
+ fetchUserConsents: (...args: unknown[]) => fetchUserConsents(...args),
12
+ fetchCaseHistory: (...args: unknown[]) => fetchCaseHistory(...args),
13
+ fetchActivities: (...args: unknown[]) => fetchActivities(...args),
14
+ }));
15
+
16
+ // ─── Language stub (avoids subscribing to the real i18n event emitter) ───────
17
+ vi.mock('../src/RedactoPrivacyCenter/lib/useCurrentLanguage', () => ({
18
+ useCurrentLanguage: () => ({ currentLanguage: 'en', langParam: undefined }),
19
+ }));
20
+
21
+ // ─── Auth / BaseUrl / Organization context stubs ─────────────────────────────
22
+ vi.mock('../src/RedactoPrivacyCenter/context/AuthContext', () => {
23
+ const auth = {
24
+ accessToken: 'tok',
25
+ refreshToken: 'rtok',
26
+ onError: () => false,
27
+ updateTokens: () => {},
28
+ };
29
+ return { useAuth: () => auth };
30
+ });
31
+ vi.mock('../src/RedactoPrivacyCenter/context/BaseUrlContext', () => {
32
+ const base = { consentClient: {}, baseUrl: 'https://consent.test' };
33
+ return { useBaseUrl: () => base };
34
+ });
35
+ vi.mock('../src/RedactoPrivacyCenter/context/OrganizationContext', () => {
36
+ const org = {
37
+ organization: { uuid: 'org-uuid', slug: 'acme', name: 'Acme', workspaces: [{ uuid: 'ws-uuid' }] },
38
+ };
39
+ return { useOrganization: () => org };
40
+ });
41
+
42
+ import {
43
+ DataAvailabilityProvider,
44
+ useDataAvailability,
45
+ } from '../src/RedactoPrivacyCenter/context/DataAvailabilityContext';
46
+
47
+ const emptyConsents = { status_summary: { total_purposes: 0 }, direct: [], nominated: [], nominators: [] };
48
+ const emptyCases = { data: [] };
49
+ const emptyActivities = { pagination: { total_count: 0 } };
50
+
51
+ function StatusProbe() {
52
+ const { status } = useDataAvailability();
53
+ return <div data-testid="status">{status}</div>;
54
+ }
55
+
56
+ function renderGate() {
57
+ return render(
58
+ <DataAvailabilityProvider>
59
+ <StatusProbe />
60
+ </DataAvailabilityProvider>,
61
+ );
62
+ }
63
+
64
+ const waitForStatus = (value: string) =>
65
+ waitFor(() => expect(screen.getByTestId('status').textContent).toBe(value));
66
+
67
+ describe('DataAvailabilityContext', () => {
68
+ beforeEach(() => {
69
+ sessionStorage.setItem('email', 'user@example.com');
70
+ // Default: everything empty.
71
+ fetchUserConsents.mockResolvedValue(emptyConsents);
72
+ fetchCaseHistory.mockResolvedValue(emptyCases);
73
+ fetchActivities.mockResolvedValue(emptyActivities);
74
+ });
75
+
76
+ afterEach(() => {
77
+ vi.clearAllMocks();
78
+ sessionStorage.clear();
79
+ });
80
+
81
+ it("resolves to 'empty' only when consents, cases, and activity are all empty", async () => {
82
+ renderGate();
83
+ await waitForStatus('empty');
84
+ });
85
+
86
+ it("resolves to 'has-data' when there are consents", async () => {
87
+ fetchUserConsents.mockResolvedValue({ status_summary: { total_purposes: 2 }, direct: [{}], nominated: [], nominators: [] });
88
+ renderGate();
89
+ await waitForStatus('has-data');
90
+ });
91
+
92
+ it("resolves to 'has-data' when there are cases", async () => {
93
+ fetchCaseHistory.mockResolvedValue({ data: [{ uuid: 'c1' }] });
94
+ renderGate();
95
+ await waitForStatus('has-data');
96
+ });
97
+
98
+ it("resolves to 'has-data' when there is activity", async () => {
99
+ fetchActivities.mockResolvedValue({ pagination: { total_count: 4 } });
100
+ renderGate();
101
+ await waitForStatus('has-data');
102
+ });
103
+
104
+ it("fails open to 'has-data' when a signal returns null", async () => {
105
+ // Consents + cases empty, but activity could not be read (null).
106
+ fetchActivities.mockResolvedValue(null);
107
+ renderGate();
108
+ await waitForStatus('has-data');
109
+ });
110
+
111
+ it("fails open to 'has-data' when a signal rejects", async () => {
112
+ fetchUserConsents.mockRejectedValue(new Error('boom'));
113
+ renderGate();
114
+ await waitForStatus('has-data');
115
+ });
116
+
117
+ it("skips the cases fetch when no email is present, treating cases as empty", async () => {
118
+ sessionStorage.removeItem('email');
119
+ renderGate();
120
+ await waitForStatus('empty');
121
+ expect(fetchCaseHistory).not.toHaveBeenCalled();
122
+ });
123
+ });