@redacto.io/consent-sdk-react 10.0.0-beta.9 → 10.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.
- package/NOTICE.md +17 -0
- package/README.md +141 -3
- package/dist/chunk-FEGTW73Q.mjs +182 -0
- package/dist/fonts.d.mts +35 -0
- package/dist/fonts.d.ts +35 -0
- package/dist/fonts.js +183 -0
- package/dist/fonts.mjs +10 -0
- package/dist/index.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +724 -365
- package/dist/index.mjs +346 -201
- package/dist/montserrat.generated-NBTECYRW.mjs +22 -0
- package/dist/privacy-center.d.mts +0 -1
- package/dist/privacy-center.d.ts +0 -1
- package/dist/privacy-center.js +2 -66
- package/dist/privacy-center.mjs +2 -66
- package/dist/types-6Aj7faxL.d.mts +57 -0
- package/dist/types-6Aj7faxL.d.ts +57 -0
- package/package.json +10 -1
- package/.turbo/turbo-build.log +0 -22
- package/.turbo/turbo-test.log +0 -203
- package/.turbo/turbo-verify-pack.log +0 -6
- package/CHANGELOG.md +0 -353
- package/src/RedactoNoticeAssisted/RedactoNoticeAssisted.test.tsx +0 -934
- package/src/RedactoNoticeAssisted/RedactoNoticeAssisted.tsx +0 -2160
- package/src/RedactoNoticeAssisted/api/index.ts +0 -275
- package/src/RedactoNoticeAssisted/api/types.ts +0 -182
- package/src/RedactoNoticeAssisted/assets/redacto-logo.png +0 -0
- package/src/RedactoNoticeAssisted/constants.ts +0 -51
- package/src/RedactoNoticeAssisted/i18n.ts +0 -1408
- package/src/RedactoNoticeAssisted/index.ts +0 -1
- package/src/RedactoNoticeAssisted/injectStyles.ts +0 -251
- package/src/RedactoNoticeAssisted/styles.ts +0 -730
- package/src/RedactoNoticeAssisted/types.ts +0 -26
- package/src/RedactoNoticeAssisted/useMediaQuery.ts +0 -36
- package/src/RedactoNoticeConsent/RedactoNoticeConsent.test.tsx +0 -1152
- package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +0 -4308
- package/src/RedactoNoticeConsent/api/index.ts +0 -542
- package/src/RedactoNoticeConsent/api/sandbox.ts +0 -150
- package/src/RedactoNoticeConsent/api/types.ts +0 -515
- package/src/RedactoNoticeConsent/assets/redacto-logo.png +0 -0
- package/src/RedactoNoticeConsent/components/DigiLockerCallback.tsx +0 -602
- package/src/RedactoNoticeConsent/components/index.ts +0 -7
- package/src/RedactoNoticeConsent/constants.ts +0 -20
- package/src/RedactoNoticeConsent/index.ts +0 -1
- package/src/RedactoNoticeConsent/injectStyles.ts +0 -151
- package/src/RedactoNoticeConsent/language-codes.ts +0 -95
- package/src/RedactoNoticeConsent/services/storage.ts +0 -122
- package/src/RedactoNoticeConsent/styles.ts +0 -409
- package/src/RedactoNoticeConsent/types.ts +0 -80
- package/src/RedactoNoticeConsent/useMediaQuery.ts +0 -36
- package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.test.tsx +0 -369
- package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +0 -687
- package/src/RedactoNoticeConsentInline/api/index.ts +0 -106
- package/src/RedactoNoticeConsentInline/api/types.ts +0 -183
- package/src/RedactoNoticeConsentInline/assets/redacto-logo.png +0 -0
- package/src/RedactoNoticeConsentInline/index.ts +0 -1
- package/src/RedactoNoticeConsentInline/injectStyles.ts +0 -40
- package/src/RedactoNoticeConsentInline/styles.ts +0 -397
- package/src/RedactoNoticeConsentInline/types.ts +0 -51
- package/src/RedactoNoticeConsentInline/useMediaQuery.ts +0 -36
- package/src/RedactoPrivacyCenter/NotificationsPage.tsx +0 -182
- package/src/RedactoPrivacyCenter/PrivacyCenterActivityPage.tsx +0 -19
- package/src/RedactoPrivacyCenter/PrivacyCenterCaseDetailsPage.tsx +0 -156
- package/src/RedactoPrivacyCenter/PrivacyCenterConsentManagerPage.tsx +0 -17
- package/src/RedactoPrivacyCenter/PrivacyCenterFormPage.tsx +0 -79
- package/src/RedactoPrivacyCenter/PrivacyCenterHomePage.tsx +0 -36
- package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +0 -177
- package/src/RedactoPrivacyCenter/PrivacyCenterMyReceiptPage.tsx +0 -26
- package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +0 -93
- package/src/RedactoPrivacyCenter/api/actions.ts +0 -695
- package/src/RedactoPrivacyCenter/api/client.ts +0 -1003
- package/src/RedactoPrivacyCenter/api/config.ts +0 -33
- package/src/RedactoPrivacyCenter/api/fetcher.ts +0 -275
- package/src/RedactoPrivacyCenter/api/orgBranding.ts +0 -16
- package/src/RedactoPrivacyCenter/api/upload.ts +0 -93
- package/src/RedactoPrivacyCenter/assets/character.svg +0 -31
- package/src/RedactoPrivacyCenter/assets/fileAttach.svg +0 -9
- package/src/RedactoPrivacyCenter/assets/greenTick.svg +0 -4
- package/src/RedactoPrivacyCenter/assets/mail.svg +0 -3
- package/src/RedactoPrivacyCenter/assets/poweredByRedacto.svg +0 -9
- package/src/RedactoPrivacyCenter/assets/sentImg.svg +0 -9
- package/src/RedactoPrivacyCenter/assets/uploadFileIcon.svg +0 -9
- package/src/RedactoPrivacyCenter/components/ActivitiesList.tsx +0 -252
- package/src/RedactoPrivacyCenter/components/ActivityTimeline.tsx +0 -239
- package/src/RedactoPrivacyCenter/components/AppShell/AppShell.tsx +0 -268
- package/src/RedactoPrivacyCenter/components/AppShell/MobileNavDrawer.tsx +0 -218
- package/src/RedactoPrivacyCenter/components/AppShell/NavItem.tsx +0 -205
- package/src/RedactoPrivacyCenter/components/AppShell/PageHeader.tsx +0 -107
- package/src/RedactoPrivacyCenter/components/AppShell/SidebarNav.tsx +0 -100
- package/src/RedactoPrivacyCenter/components/AppShell/TopAppBar.tsx +0 -339
- package/src/RedactoPrivacyCenter/components/AppShell/UserMenu.tsx +0 -245
- package/src/RedactoPrivacyCenter/components/AppShell/hooks/useIsTruncated.ts +0 -28
- package/src/RedactoPrivacyCenter/components/AppShell/hooks/useKeyboardShortcut.ts +0 -40
- package/src/RedactoPrivacyCenter/components/AppShell/hooks/useSidebarState.ts +0 -62
- package/src/RedactoPrivacyCenter/components/AppShell/usePrivacyCenterExitAction.ts +0 -36
- package/src/RedactoPrivacyCenter/components/CaseDetails/AttachmentCard.tsx +0 -38
- package/src/RedactoPrivacyCenter/components/CaseDetails/ChatBubble.tsx +0 -31
- package/src/RedactoPrivacyCenter/components/CaseDetails/DocumentRequestCard.tsx +0 -79
- package/src/RedactoPrivacyCenter/components/CaseDetails/FinalizedTooltipWrapper.tsx +0 -25
- package/src/RedactoPrivacyCenter/components/CaseDetails/MessageComposer.tsx +0 -96
- package/src/RedactoPrivacyCenter/components/CaseDetails/MessageItem.tsx +0 -97
- package/src/RedactoPrivacyCenter/components/CaseDetails/MessagesTab.tsx +0 -156
- package/src/RedactoPrivacyCenter/components/CaseDetails/RequestDetailsTab.tsx +0 -171
- package/src/RedactoPrivacyCenter/components/CaseDetails/StatusEvent.tsx +0 -23
- package/src/RedactoPrivacyCenter/components/CaseDetails/useFileUpload.ts +0 -116
- package/src/RedactoPrivacyCenter/components/CaseDetails/useMessagePolling.ts +0 -43
- package/src/RedactoPrivacyCenter/components/CaseDetails/utils.ts +0 -71
- package/src/RedactoPrivacyCenter/components/CaseDetailsModal.tsx +0 -469
- package/src/RedactoPrivacyCenter/components/CaseHistory.tsx +0 -426
- package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +0 -1206
- package/src/RedactoPrivacyCenter/components/ConsentManagerCells.tsx +0 -218
- package/src/RedactoPrivacyCenter/components/ConsentManagerColumns.tsx +0 -138
- package/src/RedactoPrivacyCenter/components/ConsentManagerConstants.ts +0 -7
- package/src/RedactoPrivacyCenter/components/ConsentManagerExpandedRow.tsx +0 -179
- package/src/RedactoPrivacyCenter/components/ConsentManagerGroupedColumns.tsx +0 -318
- package/src/RedactoPrivacyCenter/components/ConsentManagerProductCards.tsx +0 -333
- package/src/RedactoPrivacyCenter/components/ConsentManagerPurposeCards.tsx +0 -102
- package/src/RedactoPrivacyCenter/components/ConsentManagerTableSkeleton.tsx +0 -159
- package/src/RedactoPrivacyCenter/components/DataRequest/CorrectionDataSection.tsx +0 -189
- package/src/RedactoPrivacyCenter/components/DataRequest/GrievanceDataSection.tsx +0 -118
- package/src/RedactoPrivacyCenter/components/DataRequest/NominationDataSection.tsx +0 -66
- package/src/RedactoPrivacyCenter/components/DataRequest/ProductSelectionSection.tsx +0 -222
- package/src/RedactoPrivacyCenter/components/DataRequest/PurposeSelectionSection.tsx +0 -331
- package/src/RedactoPrivacyCenter/components/Form.tsx +0 -1821
- package/src/RedactoPrivacyCenter/components/GrievanceTable.tsx +0 -174
- package/src/RedactoPrivacyCenter/components/GrievanceTablePagination.tsx +0 -337
- package/src/RedactoPrivacyCenter/components/ModifyConsentModal.tsx +0 -334
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationBell.tsx +0 -173
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationCTAButton.tsx +0 -18
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationDropdown.tsx +0 -54
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationDropdownItem.tsx +0 -57
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationIcon.tsx +0 -19
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationListPanel.tsx +0 -92
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationRefreshButton.tsx +0 -20
- package/src/RedactoPrivacyCenter/components/NotificationHub/NotificationRow.tsx +0 -58
- package/src/RedactoPrivacyCenter/components/NotificationHub/StatCard.tsx +0 -10
- package/src/RedactoPrivacyCenter/components/NotificationHub/useNotificationActions.ts +0 -112
- package/src/RedactoPrivacyCenter/components/NotificationHub/utils.ts +0 -27
- package/src/RedactoPrivacyCenter/components/Pagination.tsx +0 -140
- package/src/RedactoPrivacyCenter/components/PrivacyCenterEmptyState.tsx +0 -76
- package/src/RedactoPrivacyCenter/components/PrivacyCenterSessionExpired.tsx +0 -97
- package/src/RedactoPrivacyCenter/components/ReceiptsList.tsx +0 -454
- package/src/RedactoPrivacyCenter/components/RequestSubmit.tsx +0 -270
- package/src/RedactoPrivacyCenter/components/SelectUser.tsx +0 -95
- package/src/RedactoPrivacyCenter/components/SelectUserGate.tsx +0 -195
- package/src/RedactoPrivacyCenter/components/SideMenuBarPC/constants.tsx +0 -25
- package/src/RedactoPrivacyCenter/components/SideMenuBarPC/types.ts +0 -21
- package/src/RedactoPrivacyCenter/components/caseHistoryColumns.tsx +0 -159
- package/src/RedactoPrivacyCenter/components/constant.ts +0 -52
- package/src/RedactoPrivacyCenter/components/groupHelpers.ts +0 -155
- package/src/RedactoPrivacyCenter/components/receiptColumns.tsx +0 -203
- package/src/RedactoPrivacyCenter/components/types.ts +0 -123
- package/src/RedactoPrivacyCenter/components/utils.tsx +0 -10
- package/src/RedactoPrivacyCenter/config/routes.ts +0 -9
- package/src/RedactoPrivacyCenter/config/table.ts +0 -25
- package/src/RedactoPrivacyCenter/context/AuthContext.tsx +0 -252
- package/src/RedactoPrivacyCenter/context/BaseUrlContext.tsx +0 -47
- package/src/RedactoPrivacyCenter/context/BrandingContext.tsx +0 -52
- package/src/RedactoPrivacyCenter/context/DataAvailabilityContext.session-expired.test.tsx +0 -92
- package/src/RedactoPrivacyCenter/context/DataAvailabilityContext.tsx +0 -181
- package/src/RedactoPrivacyCenter/context/LocaleContext.tsx +0 -11
- package/src/RedactoPrivacyCenter/context/NavigationContext.tsx +0 -96
- package/src/RedactoPrivacyCenter/context/OrganizationContext.tsx +0 -30
- package/src/RedactoPrivacyCenter/context/PageChromeContext.tsx +0 -80
- package/src/RedactoPrivacyCenter/context/ProfileSwitchContext.tsx +0 -15
- package/src/RedactoPrivacyCenter/context/types.ts +0 -57
- package/src/RedactoPrivacyCenter/lib/api.ts +0 -759
- package/src/RedactoPrivacyCenter/lib/consent-manager/utils.tsx +0 -67
- package/src/RedactoPrivacyCenter/lib/constants.ts +0 -283
- package/src/RedactoPrivacyCenter/lib/i18n.ts +0 -81
- package/src/RedactoPrivacyCenter/lib/locales.ts +0 -102
- package/src/RedactoPrivacyCenter/lib/queries.ts +0 -141
- package/src/RedactoPrivacyCenter/lib/sandbox.ts +0 -104
- package/src/RedactoPrivacyCenter/lib/types.ts +0 -896
- package/src/RedactoPrivacyCenter/lib/useCurrentLanguage.ts +0 -37
- package/src/RedactoPrivacyCenter/lib/utils.refresh-circuit.test.ts +0 -127
- package/src/RedactoPrivacyCenter/lib/utils.refresh-storage.test.ts +0 -85
- package/src/RedactoPrivacyCenter/lib/utils.session-expired.test.ts +0 -109
- package/src/RedactoPrivacyCenter/lib/utils.ts +0 -798
- package/src/RedactoPrivacyCenter/locales/as/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/bn/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/brx/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/doi/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/en/translation.json +0 -357
- package/src/RedactoPrivacyCenter/locales/gom/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/gu/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/hi/translation.json +0 -345
- package/src/RedactoPrivacyCenter/locales/kn/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ks/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/mai/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ml/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/mr/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ne/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/or/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/pa/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/sa/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/sat/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/sd/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ta/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/te/translation.json +0 -342
- package/src/RedactoPrivacyCenter/locales/ur/translation.json +0 -342
- package/src/RedactoPrivacyCenter/styles/applyBrandingTheme.ts +0 -66
- package/src/RedactoPrivacyCenter/styles/base.css +0 -117
- package/src/RedactoPrivacyCenter/styles/injectStyles.ts +0 -3108
- package/src/RedactoPrivacyCenter/styles/pcStyles.ts +0 -831
- package/src/RedactoPrivacyCenter/styles/responsive.ts +0 -138
- package/src/RedactoPrivacyCenter/styles/variables.css +0 -96
- package/src/RedactoPrivacyCenter/table/AdvancedTable.tsx +0 -387
- package/src/RedactoPrivacyCenter/table/AdvancedTablePagination.tsx +0 -468
- package/src/RedactoPrivacyCenter/table/index.ts +0 -2
- package/src/RedactoPrivacyCenter/types/images.d.ts +0 -29
- package/src/RedactoPrivacyCenter/ui/Footer.tsx +0 -69
- package/src/RedactoPrivacyCenter/ui/FormBlockWrapper.tsx +0 -54
- package/src/RedactoPrivacyCenter/ui/PCAccordion.tsx +0 -93
- package/src/RedactoPrivacyCenter/ui/PCActionIcon.tsx +0 -47
- package/src/RedactoPrivacyCenter/ui/PCAvatar.test.tsx +0 -83
- package/src/RedactoPrivacyCenter/ui/PCAvatar.tsx +0 -93
- package/src/RedactoPrivacyCenter/ui/PCBadge.tsx +0 -48
- package/src/RedactoPrivacyCenter/ui/PCButton.tsx +0 -77
- package/src/RedactoPrivacyCenter/ui/PCCheckbox.tsx +0 -55
- package/src/RedactoPrivacyCenter/ui/PCCollapse.tsx +0 -107
- package/src/RedactoPrivacyCenter/ui/PCEmpty.tsx +0 -35
- package/src/RedactoPrivacyCenter/ui/PCInput.tsx +0 -132
- package/src/RedactoPrivacyCenter/ui/PCLoader.tsx +0 -31
- package/src/RedactoPrivacyCenter/ui/PCModal.tsx +0 -106
- package/src/RedactoPrivacyCenter/ui/PCPopover.tsx +0 -206
- package/src/RedactoPrivacyCenter/ui/PCSelect.tsx +0 -433
- package/src/RedactoPrivacyCenter/ui/PCTable.tsx +0 -149
- package/src/RedactoPrivacyCenter/ui/PCText.tsx +0 -41
- package/src/RedactoPrivacyCenter/ui/PCTextarea.tsx +0 -43
- package/src/RedactoPrivacyCenter/ui/PCTitle.tsx +0 -37
- package/src/RedactoPrivacyCenter/ui/PCTooltip.tsx +0 -121
- package/src/RedactoPrivacyCenter/ui/SimpleBar.tsx +0 -25
- package/src/RedactoPrivacyCenter/ui/StatusBadge.tsx +0 -53
- package/src/RedactoPrivacyCenter/ui/index.ts +0 -18
- package/src/RedactoPrivacyCenter/utils/cn.ts +0 -28
- package/src/RedactoPrivacyCenter/utils/date.ts +0 -48
- package/src/RedactoPrivacyCenter/utils/status.ts +0 -111
- package/src/RedactoPrivacyCenter/utils/toast.ts +0 -130
- package/src/index.ts +0 -19
- package/src/privacy-center.ts +0 -113
- package/src/shared/api-errors.ts +0 -180
- package/src/shared/notice-consent-status.ts +0 -190
- package/src/shared/sandbox.ts +0 -6
- package/src/types/css.d.ts +0 -4
- package/src/types/images.d.ts +0 -19
- package/src/types/react-jsx.d.ts +0 -26
- package/tests/DataAvailabilityContext.test.tsx +0 -123
- package/tests/Form.test.tsx +0 -1424
- package/tests/ManageConsentErrorMapping.test.tsx +0 -85
- package/tests/ProductSelectionSection.test.tsx +0 -328
- package/tests/RequestSubmit.test.tsx +0 -135
- package/tests/RevocablePurpose.test.tsx +0 -146
- package/tests/RevokeWarningMessage.test.tsx +0 -151
- package/tests/consentClient.test.ts +0 -217
- package/tests/manageConsentServer.test.ts +0 -38
- package/tests/mocks.ts +0 -257
- package/tests/resolveContactFromJwt.test.ts +0 -44
- package/tests/setup.ts +0 -16
- package/tsconfig.json +0 -16
- package/tsup.config.ts +0 -31
- package/vitest.config.ts +0 -16
package/src/shared/api-errors.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared API error handling for the consent-sdk-react package.
|
|
3
|
-
*
|
|
4
|
-
* The backend (consent-server) owns the user-facing copy. Each error
|
|
5
|
-
* response carries:
|
|
6
|
-
* - `message`: user-safe text the SDK displays verbatim
|
|
7
|
-
* - `error_code`: stable identifier for programmatic branching
|
|
8
|
-
*
|
|
9
|
-
* The SDK never re-translates a code into a message. To change wording,
|
|
10
|
-
* update the server titles registry -- no SDK release required.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
export type ApiErrorCode =
|
|
14
|
-
| "INVALID_TOKEN"
|
|
15
|
-
| "TOKEN_TENANT_MISMATCH"
|
|
16
|
-
| "UNAUTHORIZED"
|
|
17
|
-
| "USER_NOT_FOUND"
|
|
18
|
-
| "USER_EMAIL_MISMATCH"
|
|
19
|
-
| "USER_MOBILE_MISMATCH"
|
|
20
|
-
| "USER_CONTACT_MISMATCH"
|
|
21
|
-
| "NO_IDENTIFIER_PROVIDED"
|
|
22
|
-
| "INVALID_PAYLOAD"
|
|
23
|
-
| "VALIDATION_ERROR"
|
|
24
|
-
| "NOTICE_NOT_FOUND"
|
|
25
|
-
| "NOTICE_CONFIGURATION_NOT_FOUND"
|
|
26
|
-
| "NOTICE_STILL_IN_DRAFT"
|
|
27
|
-
| "CONSENT_ALREADY_PROVIDED"
|
|
28
|
-
| "PURPOSE_NOT_FOUND"
|
|
29
|
-
| "INVALID_PURPOSE"
|
|
30
|
-
| "INVALID_DATA_ELEMENTS"
|
|
31
|
-
| "MISSING_PURPOSE"
|
|
32
|
-
| "MISSING_DATA_ELEMENTS"
|
|
33
|
-
| "REQUIRED_DATA_ELEMENT_NOT_ENABLED"
|
|
34
|
-
| "AUDIO_NOT_FOUND"
|
|
35
|
-
| "INVALID_LANGUAGE"
|
|
36
|
-
| "VERIFICATION_FAILED"
|
|
37
|
-
| "VERIFICATION_EXPIRED"
|
|
38
|
-
| "GUARDIAN_INFO_NOT_FOUND"
|
|
39
|
-
| "GUARDIAN_SESSION_INVALID"
|
|
40
|
-
| "SESSION_EXPIRED"
|
|
41
|
-
| "INTERNAL_ERROR";
|
|
42
|
-
|
|
43
|
-
interface ApiErrorDetail {
|
|
44
|
-
message?: string;
|
|
45
|
-
error_code?: string | null;
|
|
46
|
-
// Ninja's auth-pipeline auto-401 returns `{detail: {detail: "Unauthorized"}}`
|
|
47
|
-
// -- the inner `detail` is a string. Captured here so the parser can use
|
|
48
|
-
// it as a last-resort message extraction.
|
|
49
|
-
detail?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
interface ApiErrorBody {
|
|
53
|
-
message?: string;
|
|
54
|
-
error_code?: string | null;
|
|
55
|
-
// Some endpoints (e.g. OTP verify) signal "this code is dead, request a fresh
|
|
56
|
-
// one" via a top-level boolean instead of an `error_code`. Captured so callers
|
|
57
|
-
// can branch on it (e.g. to distinguish an expired code from a wrong one).
|
|
58
|
-
should_request_new?: boolean;
|
|
59
|
-
// `detail` may arrive as:
|
|
60
|
-
// { message: "...", error_code: "..." } -- our MessageResponse via Ninja
|
|
61
|
-
// { detail: "..." } -- Ninja auto-401
|
|
62
|
-
// "..." -- direct string from some endpoints
|
|
63
|
-
// [...] -- Ninja auto-422 Pydantic errors
|
|
64
|
-
detail?: ApiErrorDetail | string | unknown[];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// `ApiErrorCode | (string & {})` keeps literal autocomplete on `code` while
|
|
68
|
-
// still permitting unknown strings from forward-compatible server versions.
|
|
69
|
-
// A bare `ApiErrorCode | string` would widen to `string` and lose the
|
|
70
|
-
// literal suggestions.
|
|
71
|
-
export type ApiErrorCodeLike = ApiErrorCode | (string & {});
|
|
72
|
-
|
|
73
|
-
export class ApiError extends Error {
|
|
74
|
-
readonly status: number;
|
|
75
|
-
readonly code?: ApiErrorCodeLike;
|
|
76
|
-
// Mirrors the server's `should_request_new` flag, when present.
|
|
77
|
-
readonly shouldRequestNew?: boolean;
|
|
78
|
-
|
|
79
|
-
constructor(opts: {
|
|
80
|
-
status: number;
|
|
81
|
-
code?: ApiErrorCodeLike;
|
|
82
|
-
message: string;
|
|
83
|
-
shouldRequestNew?: boolean;
|
|
84
|
-
}) {
|
|
85
|
-
super(opts.message);
|
|
86
|
-
this.name = "ApiError";
|
|
87
|
-
this.status = opts.status;
|
|
88
|
-
this.code = opts.code;
|
|
89
|
-
this.shouldRequestNew = opts.shouldRequestNew;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Tier-3 fallbacks for failure modes where the server did not produce
|
|
94
|
-
// a parseable body with `message`. Common case: Ninja's auth pipeline
|
|
95
|
-
// rejects a request before reaching our handler, returning
|
|
96
|
-
// `{detail: {detail: "Unauthorized"}}` with no message field. The
|
|
97
|
-
// fallback is a static, user-safe hint -- never an override of a
|
|
98
|
-
// server-supplied message.
|
|
99
|
-
function statusFallback(status: number): string | undefined {
|
|
100
|
-
if (status === 401) {
|
|
101
|
-
return "Your session has expired. Please request a new access link.";
|
|
102
|
-
}
|
|
103
|
-
if (status === 403) {
|
|
104
|
-
return "You do not have access to this resource.";
|
|
105
|
-
}
|
|
106
|
-
if (status >= 500) {
|
|
107
|
-
return "Something went wrong on our end. Please try again later.";
|
|
108
|
-
}
|
|
109
|
-
return undefined;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Build an ApiError from a non-OK fetch Response.
|
|
114
|
-
*
|
|
115
|
-
* Order of preference for the user-facing message:
|
|
116
|
-
* 1. `message` field from the backend response body (preferred -- the
|
|
117
|
-
* SDK-consumed endpoints always populate this with user-safe copy).
|
|
118
|
-
* 2. Status-based fallback (only when the server omitted a message,
|
|
119
|
-
* e.g. Ninja's auto-401 for an expired JWT).
|
|
120
|
-
* 3. The caller-supplied fallback (used when the body is missing or
|
|
121
|
-
* unparseable -- network error, non-JSON proxy page).
|
|
122
|
-
*
|
|
123
|
-
* The `code` field is exposed as-is for programmatic branching. Consumers
|
|
124
|
-
* that want compile-time safety should narrow against `ApiErrorCode`.
|
|
125
|
-
*/
|
|
126
|
-
function extractFromDetail(
|
|
127
|
-
detail: ApiErrorBody["detail"]
|
|
128
|
-
): { message?: string; code?: string | null } {
|
|
129
|
-
// String detail (e.g. some endpoints return `{detail: "..."}` directly).
|
|
130
|
-
if (typeof detail === "string") {
|
|
131
|
-
return { message: detail };
|
|
132
|
-
}
|
|
133
|
-
// Array detail (Ninja's auto-422 Pydantic validation errors): no usable
|
|
134
|
-
// single message; let the caller fall back to status/generic copy.
|
|
135
|
-
if (Array.isArray(detail)) {
|
|
136
|
-
return {};
|
|
137
|
-
}
|
|
138
|
-
// Object detail covers both shapes:
|
|
139
|
-
// our MessageResponse: { message, error_code }
|
|
140
|
-
// Ninja auto-401: { detail: "Unauthorized" }
|
|
141
|
-
if (detail && typeof detail === "object") {
|
|
142
|
-
const obj = detail as ApiErrorDetail;
|
|
143
|
-
return { message: obj.message ?? obj.detail, code: obj.error_code };
|
|
144
|
-
}
|
|
145
|
-
return {};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export async function parseApiError(
|
|
149
|
-
response: Response,
|
|
150
|
-
fallbackMessage: string
|
|
151
|
-
): Promise<ApiError> {
|
|
152
|
-
let body: ApiErrorBody | undefined;
|
|
153
|
-
let parsedBody = false;
|
|
154
|
-
try {
|
|
155
|
-
body = (await response.json()) as ApiErrorBody;
|
|
156
|
-
parsedBody = true;
|
|
157
|
-
} catch {
|
|
158
|
-
body = undefined;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const fromDetail = extractFromDetail(body?.detail);
|
|
162
|
-
const serverMessage = body?.message ?? fromDetail.message;
|
|
163
|
-
// Status fallback only applies when the body parsed but had no message
|
|
164
|
-
// (e.g. Ninja auto-401's `{detail: {detail: "Unauthorized"}}`). When the
|
|
165
|
-
// body is unparseable (proxy HTML 502, empty body, network jank) the
|
|
166
|
-
// caller's per-endpoint fallback is the more accurate hint -- a 401 from
|
|
167
|
-
// a misbehaving proxy is not necessarily an expired session.
|
|
168
|
-
const message =
|
|
169
|
-
serverMessage ??
|
|
170
|
-
(parsedBody ? statusFallback(response.status) : undefined) ??
|
|
171
|
-
fallbackMessage;
|
|
172
|
-
const code = body?.error_code ?? fromDetail.code ?? undefined;
|
|
173
|
-
|
|
174
|
-
return new ApiError({
|
|
175
|
-
status: response.status,
|
|
176
|
-
code,
|
|
177
|
-
message,
|
|
178
|
-
shouldRequestNew: body?.should_request_new,
|
|
179
|
-
});
|
|
180
|
-
}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { jwtDecode } from "jwt-decode";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Shared Go-ledger notice `check-consent` read for the consent-sdk-react
|
|
5
|
-
* package.
|
|
6
|
-
*
|
|
7
|
-
* Post-cutover, consent records live in the Go ledger, so the Python
|
|
8
|
-
* `get-notice` endpoint no longer knows whether a principal has already
|
|
9
|
-
* consented (it used to answer that with a 409 `CONSENT_ALREADY_PROVIDED`).
|
|
10
|
-
* Both the banner (`RedactoNoticeConsent`) and the embedded widget
|
|
11
|
-
* (`RedactoNoticeConsentInline`) ask the ledger directly instead — this module
|
|
12
|
-
* is the single implementation they share.
|
|
13
|
-
*
|
|
14
|
-
* Every failure mode (no ledger configured, undecodable token, non-OK
|
|
15
|
-
* response, network/abort/parse error) degrades to `null` so callers can fall
|
|
16
|
-
* back to the legacy Python-driven flow.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
type NoticeConsentJwtPayload = {
|
|
20
|
-
organisation_uuid: string;
|
|
21
|
-
workspace_uuid: string;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// Mirrors the Go ledger's `NoticeConsentStatusResponse`. Used to overlay the
|
|
25
|
-
// prior-consent / reconsent state from the ledger, since Python's
|
|
26
|
-
// notice-validation overlay is empty after the consent cutover.
|
|
27
|
-
export type NoticeConsentStatusDataElement = {
|
|
28
|
-
uuid: string;
|
|
29
|
-
name: string;
|
|
30
|
-
selected: boolean;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export type NoticeConsentStatusPurpose = {
|
|
34
|
-
uuid: string;
|
|
35
|
-
name: string;
|
|
36
|
-
selected: boolean;
|
|
37
|
-
status: string; // ACTIVE | EXPIRED | WITHDRAW | DECLINED | INACTIVE
|
|
38
|
-
expiry_datetime?: string | null;
|
|
39
|
-
data_elements: NoticeConsentStatusDataElement[];
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export type NoticeConsentStatusResponse = {
|
|
43
|
-
consented: boolean;
|
|
44
|
-
all_mandatory_active: boolean;
|
|
45
|
-
purposes: NoticeConsentStatusPurpose[];
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export type FetchNoticeConsentStatusParams = {
|
|
49
|
-
accessToken: string;
|
|
50
|
-
ledgerBaseUrl?: string;
|
|
51
|
-
noticeUuid: string;
|
|
52
|
-
signal?: AbortSignal;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// Same read, but with org/workspace supplied explicitly instead of decoded from
|
|
56
|
-
// the JWT. Used by flows that already hold authoritative org/workspace (props)
|
|
57
|
-
// and whose token may be opaque — e.g. RedactoNoticeAssisted, whose OTP access
|
|
58
|
-
// token carries no org/workspace claims.
|
|
59
|
-
export type FetchNoticeConsentStatusForScopeParams = {
|
|
60
|
-
accessToken: string;
|
|
61
|
-
ledgerBaseUrl?: string;
|
|
62
|
-
organisationUuid: string;
|
|
63
|
-
workspaceUuid: string;
|
|
64
|
-
noticeUuid: string;
|
|
65
|
-
signal?: AbortSignal;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// Decode the JWT to resolve the org/workspace the ledger path is scoped to.
|
|
69
|
-
// Returns null on any decode failure so the caller degrades gracefully.
|
|
70
|
-
const decodeNoticeConsentToken = (
|
|
71
|
-
token: string
|
|
72
|
-
): NoticeConsentJwtPayload | null => {
|
|
73
|
-
try {
|
|
74
|
-
return jwtDecode(token) as NoticeConsentJwtPayload;
|
|
75
|
-
} catch {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Fetch the principal's current consent status for a notice from the Go
|
|
82
|
-
* ledger (`check-consent`), with org/workspace supplied explicitly. The
|
|
83
|
-
* principal resolves from the bearer token server-side, so the body is empty.
|
|
84
|
-
* Returns null on any failure so the caller can fall back to the Python-driven
|
|
85
|
-
* flow (graceful degradation). This holds the single network implementation;
|
|
86
|
-
* {@link fetchNoticeConsentStatus} decodes the JWT and delegates here.
|
|
87
|
-
*/
|
|
88
|
-
export const fetchNoticeConsentStatusForScope = async ({
|
|
89
|
-
accessToken,
|
|
90
|
-
ledgerBaseUrl,
|
|
91
|
-
organisationUuid,
|
|
92
|
-
workspaceUuid,
|
|
93
|
-
noticeUuid,
|
|
94
|
-
signal,
|
|
95
|
-
}: FetchNoticeConsentStatusForScopeParams): Promise<NoticeConsentStatusResponse | null> => {
|
|
96
|
-
if (
|
|
97
|
-
!accessToken ||
|
|
98
|
-
!ledgerBaseUrl ||
|
|
99
|
-
!organisationUuid ||
|
|
100
|
-
!workspaceUuid ||
|
|
101
|
-
!noticeUuid
|
|
102
|
-
) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
const response = await fetch(
|
|
108
|
-
`${ledgerBaseUrl}/public/organisations/${organisationUuid}/workspaces/${workspaceUuid}/notices/${noticeUuid}/check-consent`,
|
|
109
|
-
{
|
|
110
|
-
method: "POST",
|
|
111
|
-
headers: {
|
|
112
|
-
Authorization: `Bearer ${accessToken}`,
|
|
113
|
-
"Content-Type": "application/json",
|
|
114
|
-
},
|
|
115
|
-
body: "{}",
|
|
116
|
-
signal,
|
|
117
|
-
}
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
if (!response.ok) {
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const data = (await response.json()) as
|
|
125
|
-
| NoticeConsentStatusResponse
|
|
126
|
-
| { detail?: NoticeConsentStatusResponse };
|
|
127
|
-
// The ledger returns the response directly; tolerate a {detail} envelope too.
|
|
128
|
-
const body =
|
|
129
|
-
data && typeof data === "object" && "detail" in data && data.detail
|
|
130
|
-
? data.detail
|
|
131
|
-
: (data as NoticeConsentStatusResponse);
|
|
132
|
-
|
|
133
|
-
if (!body || !Array.isArray(body.purposes)) {
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
return body;
|
|
137
|
-
} catch {
|
|
138
|
-
// Network / abort / parse failure — degrade to the Python-driven flow.
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Fetch the principal's current consent status for a notice from the Go
|
|
145
|
-
* ledger (`check-consent`). The org/workspace are resolved by decoding the
|
|
146
|
-
* JWT. Returns null on any failure so the caller can fall back to the
|
|
147
|
-
* Python-provided overlay (graceful degradation).
|
|
148
|
-
*/
|
|
149
|
-
export const fetchNoticeConsentStatus = async ({
|
|
150
|
-
accessToken,
|
|
151
|
-
ledgerBaseUrl,
|
|
152
|
-
noticeUuid,
|
|
153
|
-
signal,
|
|
154
|
-
}: FetchNoticeConsentStatusParams): Promise<NoticeConsentStatusResponse | null> => {
|
|
155
|
-
if (!accessToken || !ledgerBaseUrl || !noticeUuid) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const decodedToken = decodeNoticeConsentToken(accessToken);
|
|
160
|
-
if (!decodedToken) {
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const {
|
|
165
|
-
organisation_uuid: ORGANISATION_UUID,
|
|
166
|
-
workspace_uuid: WORKSPACE_UUID,
|
|
167
|
-
} = decodedToken;
|
|
168
|
-
if (!ORGANISATION_UUID || !WORKSPACE_UUID) {
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return fetchNoticeConsentStatusForScope({
|
|
173
|
-
accessToken,
|
|
174
|
-
ledgerBaseUrl,
|
|
175
|
-
organisationUuid: ORGANISATION_UUID,
|
|
176
|
-
workspaceUuid: WORKSPACE_UUID,
|
|
177
|
-
noticeUuid,
|
|
178
|
-
signal,
|
|
179
|
-
});
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Whether the principal has already fully consented to this notice with no
|
|
184
|
-
* reconsent needed — the ledger equivalent of Python's 409
|
|
185
|
-
* `CONSENT_ALREADY_PROVIDED`. Requires an active consent record with every
|
|
186
|
-
* mandatory purpose still ACTIVE.
|
|
187
|
-
*/
|
|
188
|
-
export const isNoticeFullyConsented = (
|
|
189
|
-
status: NoticeConsentStatusResponse
|
|
190
|
-
): boolean => status.consented && status.all_mandatory_active;
|
package/src/shared/sandbox.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTTP header carrying the static sandbox token (the credential). Its presence
|
|
3
|
-
* marks a request as `environment=test`. Shared by the Notice-consent and
|
|
4
|
-
* Privacy-Center sandbox paths so the header name is defined once.
|
|
5
|
-
*/
|
|
6
|
-
export const SANDBOX_TOKEN_HEADER = "X-Consent-Token";
|
package/src/types/css.d.ts
DELETED
package/src/types/images.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
declare module "*.png" {
|
|
2
|
-
const content: string;
|
|
3
|
-
export default content;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
declare module "*.jpg" {
|
|
7
|
-
const content: string;
|
|
8
|
-
export default content;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
declare module "*.jpeg" {
|
|
12
|
-
const content: string;
|
|
13
|
-
export default content;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
declare module "*.svg" {
|
|
17
|
-
const content: string;
|
|
18
|
-
export default content;
|
|
19
|
-
}
|
package/src/types/react-jsx.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* React 19 JSX compatibility: ensures intrinsic elements (div, button, etc.)
|
|
3
|
-
* and Element type align with React's types to fix "Element is not assignable to ReactNode".
|
|
4
|
-
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/71395
|
|
5
|
-
*/
|
|
6
|
-
import type React from "react";
|
|
7
|
-
|
|
8
|
-
declare global {
|
|
9
|
-
namespace JSX {
|
|
10
|
-
type Element = React.ReactElement;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
declare module "react/jsx-runtime" {
|
|
15
|
-
namespace JSX {
|
|
16
|
-
type Element = React.ReactElement;
|
|
17
|
-
interface IntrinsicElements extends React.JSX.IntrinsicElements {}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
declare module "react/jsx-dev-runtime" {
|
|
22
|
-
namespace JSX {
|
|
23
|
-
type Element = React.ReactElement;
|
|
24
|
-
interface IntrinsicElements extends React.JSX.IntrinsicElements {}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
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
|
-
});
|