@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
|
@@ -1,687 +0,0 @@
|
|
|
1
|
-
import { useEffect, useMemo, useState, useRef, useCallback, memo } from "react";
|
|
2
|
-
import { fetchConsentContent, submitConsentEvent } from "./api";
|
|
3
|
-
import {
|
|
4
|
-
fetchNoticeConsentStatus,
|
|
5
|
-
isNoticeFullyConsented,
|
|
6
|
-
} from "../shared/notice-consent-status";
|
|
7
|
-
import type { ConsentContent } from "./api/types";
|
|
8
|
-
import type { Props, TranslationObject } from "./types";
|
|
9
|
-
import { styles } from "./styles";
|
|
10
|
-
import { useMediaQuery } from "./useMediaQuery";
|
|
11
|
-
import { injectSpinnerAnimation } from "./injectStyles";
|
|
12
|
-
|
|
13
|
-
const RedactoConsentInlineComponent = ({
|
|
14
|
-
org_uuid,
|
|
15
|
-
workspace_uuid,
|
|
16
|
-
notice_uuid,
|
|
17
|
-
accessToken,
|
|
18
|
-
baseUrl,
|
|
19
|
-
ledgerBaseUrl,
|
|
20
|
-
language = "en",
|
|
21
|
-
onAccept,
|
|
22
|
-
onError,
|
|
23
|
-
onValidationChange,
|
|
24
|
-
settings,
|
|
25
|
-
applicationId,
|
|
26
|
-
}: Props) => {
|
|
27
|
-
const [content, setContent] = useState<
|
|
28
|
-
ConsentContent["detail"]["active_config"] | null
|
|
29
|
-
>(null);
|
|
30
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
31
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
32
|
-
const [selectedLanguage, setSelectedLanguage] = useState<string>(language);
|
|
33
|
-
const [collapsedPurposes, setCollapsedPurposes] = useState<
|
|
34
|
-
Record<string, boolean>
|
|
35
|
-
>({});
|
|
36
|
-
const [selectedPurposes, setSelectedPurposes] = useState<
|
|
37
|
-
Record<string, boolean>
|
|
38
|
-
>({});
|
|
39
|
-
const [selectedDataElements, setSelectedDataElements] = useState<
|
|
40
|
-
Record<string, boolean>
|
|
41
|
-
>({});
|
|
42
|
-
const [hasAlreadyConsented, setHasAlreadyConsented] = useState(false);
|
|
43
|
-
// When a ledger is configured, block the auto-submit effect until the ledger
|
|
44
|
-
// check-consent read settles, so an already-consented principal is not
|
|
45
|
-
// re-submitted. Starts true only when a ledger check will actually run
|
|
46
|
-
// (skipped for the magic-link specific_uuid flow); stays false otherwise so
|
|
47
|
-
// the legacy Python-409 path is unaffected.
|
|
48
|
-
const [isCheckingConsent, setIsCheckingConsent] = useState<boolean>(
|
|
49
|
-
Boolean(ledgerBaseUrl) && !applicationId
|
|
50
|
-
);
|
|
51
|
-
const [fetchError, setFetchError] = useState<Error | null>(null);
|
|
52
|
-
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
|
53
|
-
|
|
54
|
-
// Ref to track if we've already submitted consent to prevent duplicate submissions
|
|
55
|
-
const hasSubmittedRef = useRef(false);
|
|
56
|
-
|
|
57
|
-
// Inject spinner animation for loading indicator
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
injectSpinnerAnimation();
|
|
60
|
-
}, []);
|
|
61
|
-
|
|
62
|
-
// Add media query hooks
|
|
63
|
-
const isMobile = useMediaQuery("(max-width: 768px)");
|
|
64
|
-
|
|
65
|
-
// Responsive styles
|
|
66
|
-
const responsiveStyles = useMemo(
|
|
67
|
-
() => ({
|
|
68
|
-
optionTitle: {
|
|
69
|
-
fontSize: isMobile ? "14px" : "16px",
|
|
70
|
-
},
|
|
71
|
-
optionDescription: {
|
|
72
|
-
fontSize: isMobile ? "11px" : "12px",
|
|
73
|
-
},
|
|
74
|
-
dataElementText: {
|
|
75
|
-
fontSize: isMobile ? "12px" : "14px",
|
|
76
|
-
},
|
|
77
|
-
button: {
|
|
78
|
-
fontSize: isMobile ? "14px" : "16px",
|
|
79
|
-
padding: isMobile ? "10px 20px" : "9px 45px",
|
|
80
|
-
},
|
|
81
|
-
}),
|
|
82
|
-
[isMobile]
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
const areAllRequiredElementsChecked = useMemo(() => {
|
|
86
|
-
if (!content) return false;
|
|
87
|
-
|
|
88
|
-
return content.purposes.every((purpose) => {
|
|
89
|
-
const requiredElements = purpose.data_elements.filter(
|
|
90
|
-
(element) => element.required
|
|
91
|
-
);
|
|
92
|
-
return requiredElements.every(
|
|
93
|
-
(element) => selectedDataElements[`${purpose.uuid}-${element.uuid}`]
|
|
94
|
-
);
|
|
95
|
-
});
|
|
96
|
-
}, [content, selectedDataElements]);
|
|
97
|
-
|
|
98
|
-
// Notify parent component when validation state changes
|
|
99
|
-
useEffect(() => {
|
|
100
|
-
onValidationChange?.(areAllRequiredElementsChecked);
|
|
101
|
-
}, [areAllRequiredElementsChecked, onValidationChange]);
|
|
102
|
-
|
|
103
|
-
useEffect(() => {
|
|
104
|
-
if (hasAlreadyConsented) {
|
|
105
|
-
onAccept?.();
|
|
106
|
-
}
|
|
107
|
-
}, [hasAlreadyConsented, onAccept]);
|
|
108
|
-
|
|
109
|
-
const getTranslatedText = (
|
|
110
|
-
key: string,
|
|
111
|
-
defaultText: string,
|
|
112
|
-
itemId?: string
|
|
113
|
-
): string => {
|
|
114
|
-
if (!content) return defaultText;
|
|
115
|
-
|
|
116
|
-
if (selectedLanguage === "English" || selectedLanguage === "en" || selectedLanguage === "EN") {
|
|
117
|
-
if (
|
|
118
|
-
key === "privacy_policy_anchor_text" &&
|
|
119
|
-
content.privacy_policy_anchor_text
|
|
120
|
-
) {
|
|
121
|
-
return content.privacy_policy_anchor_text;
|
|
122
|
-
}
|
|
123
|
-
return defaultText;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (!content.supported_languages_and_translations) {
|
|
127
|
-
return defaultText;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const translationMap = content.supported_languages_and_translations[
|
|
131
|
-
selectedLanguage
|
|
132
|
-
] as TranslationObject | undefined;
|
|
133
|
-
|
|
134
|
-
if (!translationMap) {
|
|
135
|
-
return defaultText;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (itemId) {
|
|
139
|
-
if (key === "purposes.name" || key === "purposes.description") {
|
|
140
|
-
const purposeData = translationMap.purposes?.[itemId];
|
|
141
|
-
if (purposeData) {
|
|
142
|
-
if (typeof purposeData === "string") {
|
|
143
|
-
return key === "purposes.name" ? purposeData : defaultText;
|
|
144
|
-
}
|
|
145
|
-
return key === "purposes.name"
|
|
146
|
-
? purposeData.name || defaultText
|
|
147
|
-
: purposeData.description || defaultText;
|
|
148
|
-
}
|
|
149
|
-
return defaultText;
|
|
150
|
-
}
|
|
151
|
-
if (key.startsWith("data_elements.")) {
|
|
152
|
-
return translationMap.data_elements?.[itemId] || defaultText;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const value = translationMap[key];
|
|
157
|
-
if (typeof value === "string" && value) {
|
|
158
|
-
return value;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return defaultText;
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
const fetchNotice = async () => {
|
|
165
|
-
setIsLoading(true);
|
|
166
|
-
setFetchError(null);
|
|
167
|
-
try {
|
|
168
|
-
const consentContentData = await fetchConsentContent({
|
|
169
|
-
org_uuid,
|
|
170
|
-
workspace_uuid,
|
|
171
|
-
notice_uuid,
|
|
172
|
-
baseUrl,
|
|
173
|
-
language,
|
|
174
|
-
specific_uuid: applicationId,
|
|
175
|
-
});
|
|
176
|
-
const activeConfig = consentContentData.detail.active_config;
|
|
177
|
-
setContent(activeConfig);
|
|
178
|
-
if (activeConfig.default_language) {
|
|
179
|
-
setSelectedLanguage(activeConfig.default_language);
|
|
180
|
-
}
|
|
181
|
-
const initialCollapsedState = activeConfig.purposes.reduce(
|
|
182
|
-
(acc, purpose) => ({
|
|
183
|
-
...acc,
|
|
184
|
-
[purpose.uuid]: true,
|
|
185
|
-
}),
|
|
186
|
-
{}
|
|
187
|
-
);
|
|
188
|
-
setCollapsedPurposes(initialCollapsedState);
|
|
189
|
-
|
|
190
|
-
// Initialize selected states
|
|
191
|
-
// All elements start unchecked, but required elements cannot be unchecked once checked
|
|
192
|
-
const initialDataElementState: Record<string, boolean> =
|
|
193
|
-
activeConfig.purposes.reduce(
|
|
194
|
-
(acc: Record<string, boolean>, purpose) => {
|
|
195
|
-
purpose.data_elements.forEach((element) => {
|
|
196
|
-
const combinedId = `${purpose.uuid}-${element.uuid}`;
|
|
197
|
-
acc[combinedId] = false;
|
|
198
|
-
});
|
|
199
|
-
return acc;
|
|
200
|
-
},
|
|
201
|
-
{}
|
|
202
|
-
);
|
|
203
|
-
setSelectedDataElements(initialDataElementState);
|
|
204
|
-
|
|
205
|
-
// Initialize purpose states - all start unchecked
|
|
206
|
-
const initialPurposeState: Record<string, boolean> =
|
|
207
|
-
activeConfig.purposes.reduce(
|
|
208
|
-
(acc: Record<string, boolean>, purpose) => {
|
|
209
|
-
return {
|
|
210
|
-
...acc,
|
|
211
|
-
[purpose.uuid]: false,
|
|
212
|
-
};
|
|
213
|
-
},
|
|
214
|
-
{}
|
|
215
|
-
);
|
|
216
|
-
setSelectedPurposes(initialPurposeState);
|
|
217
|
-
} catch (err: unknown) {
|
|
218
|
-
const error = err as Error & { status?: number };
|
|
219
|
-
setFetchError(error);
|
|
220
|
-
if (error.status === 409) {
|
|
221
|
-
setHasAlreadyConsented(true);
|
|
222
|
-
} else {
|
|
223
|
-
onError?.(error);
|
|
224
|
-
}
|
|
225
|
-
} finally {
|
|
226
|
-
setIsLoading(false);
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
useEffect(() => {
|
|
231
|
-
fetchNotice();
|
|
232
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
233
|
-
}, [org_uuid, workspace_uuid, notice_uuid, language, applicationId]);
|
|
234
|
-
|
|
235
|
-
// Post-cutover, consent records live in the Go ledger, so Python's
|
|
236
|
-
// get-notice no longer returns 409 CONSENT_ALREADY_PROVIDED. When a ledger
|
|
237
|
-
// is configured, ask it directly whether this principal has already fully
|
|
238
|
-
// consented — the same check-consent read the banner uses. Skipped for the
|
|
239
|
-
// magic-link specific_uuid flow (which always re-submits against a specific
|
|
240
|
-
// application) and when no ledger is set (the legacy 409 path governs).
|
|
241
|
-
useEffect(() => {
|
|
242
|
-
if (!ledgerBaseUrl || applicationId) {
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
if (!accessToken || !content) {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
let active = true;
|
|
249
|
-
const controller = new AbortController();
|
|
250
|
-
const checkLedgerConsent = async () => {
|
|
251
|
-
try {
|
|
252
|
-
const ledgerStatus = await fetchNoticeConsentStatus({
|
|
253
|
-
accessToken,
|
|
254
|
-
ledgerBaseUrl,
|
|
255
|
-
noticeUuid: notice_uuid,
|
|
256
|
-
signal: controller.signal,
|
|
257
|
-
});
|
|
258
|
-
if (active && ledgerStatus && isNoticeFullyConsented(ledgerStatus)) {
|
|
259
|
-
setHasAlreadyConsented(true);
|
|
260
|
-
}
|
|
261
|
-
} finally {
|
|
262
|
-
if (active) {
|
|
263
|
-
setIsCheckingConsent(false);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
checkLedgerConsent();
|
|
268
|
-
return () => {
|
|
269
|
-
active = false;
|
|
270
|
-
controller.abort();
|
|
271
|
-
};
|
|
272
|
-
}, [ledgerBaseUrl, applicationId, accessToken, content, notice_uuid]);
|
|
273
|
-
|
|
274
|
-
const togglePurposeCollapse = (purposeUuid: string) => {
|
|
275
|
-
setCollapsedPurposes((prev) => ({
|
|
276
|
-
...prev,
|
|
277
|
-
[purposeUuid]: !prev[purposeUuid],
|
|
278
|
-
}));
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
const handlePurposeCheckboxChange = (purposeUuid: string) => {
|
|
282
|
-
if (content) {
|
|
283
|
-
const purpose = content.purposes.find((p) => p.uuid === purposeUuid);
|
|
284
|
-
if (purpose) {
|
|
285
|
-
const newPurposeState = !selectedPurposes[purposeUuid];
|
|
286
|
-
|
|
287
|
-
// Update purpose state
|
|
288
|
-
setSelectedPurposes((prev) => ({
|
|
289
|
-
...prev,
|
|
290
|
-
[purposeUuid]: newPurposeState,
|
|
291
|
-
}));
|
|
292
|
-
|
|
293
|
-
// Update ALL data elements (including required) when purpose checkbox is toggled
|
|
294
|
-
setSelectedDataElements((prev) => {
|
|
295
|
-
const updated = { ...prev };
|
|
296
|
-
purpose.data_elements.forEach((el) => {
|
|
297
|
-
const combinedId = `${purposeUuid}-${el.uuid}`;
|
|
298
|
-
updated[combinedId] = newPurposeState;
|
|
299
|
-
});
|
|
300
|
-
return updated;
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
const handleDataElementCheckboxChange = (
|
|
307
|
-
elementUuid: string,
|
|
308
|
-
purposeUuid: string
|
|
309
|
-
) => {
|
|
310
|
-
if (!content) return;
|
|
311
|
-
|
|
312
|
-
const purpose = content.purposes.find((p) => p.uuid === purposeUuid);
|
|
313
|
-
if (!purpose) return;
|
|
314
|
-
|
|
315
|
-
const dataElement = purpose.data_elements.find(
|
|
316
|
-
(el) => el.uuid === elementUuid
|
|
317
|
-
);
|
|
318
|
-
if (!dataElement) return;
|
|
319
|
-
|
|
320
|
-
const combinedId = `${purposeUuid}-${elementUuid}`;
|
|
321
|
-
const currentState = selectedDataElements[combinedId] || false;
|
|
322
|
-
const newElementState = !currentState;
|
|
323
|
-
|
|
324
|
-
// Update data element state
|
|
325
|
-
setSelectedDataElements((prev) => {
|
|
326
|
-
const newState = {
|
|
327
|
-
...prev,
|
|
328
|
-
[combinedId]: newElementState,
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
// Check if all required elements are checked
|
|
332
|
-
const requiredElements = purpose.data_elements.filter(
|
|
333
|
-
(el) => el.required
|
|
334
|
-
);
|
|
335
|
-
|
|
336
|
-
let shouldCheckPurpose: boolean;
|
|
337
|
-
|
|
338
|
-
if (requiredElements.length > 0) {
|
|
339
|
-
// Has required elements: check purpose when all required are selected
|
|
340
|
-
shouldCheckPurpose = requiredElements.every(
|
|
341
|
-
(el) => newState[`${purposeUuid}-${el.uuid}`]
|
|
342
|
-
);
|
|
343
|
-
} else {
|
|
344
|
-
// No required elements: check purpose when ANY element is selected
|
|
345
|
-
shouldCheckPurpose = purpose.data_elements.some(
|
|
346
|
-
(el) => newState[`${purposeUuid}-${el.uuid}`]
|
|
347
|
-
);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
setSelectedPurposes((prevPurposes) => ({
|
|
351
|
-
...prevPurposes,
|
|
352
|
-
[purposeUuid]: shouldCheckPurpose,
|
|
353
|
-
}));
|
|
354
|
-
|
|
355
|
-
return newState;
|
|
356
|
-
});
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
const handleAcceptWithToken = useCallback(
|
|
360
|
-
async (tokenToUse: string) => {
|
|
361
|
-
if (!tokenToUse || !content) {
|
|
362
|
-
setErrorMessage("Unable to submit consent. Please try again.");
|
|
363
|
-
throw new Error("Access token or content not available");
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
try {
|
|
367
|
-
setIsSubmitting(true);
|
|
368
|
-
setErrorMessage(null);
|
|
369
|
-
|
|
370
|
-
await submitConsentEvent({
|
|
371
|
-
org_uuid,
|
|
372
|
-
workspace_uuid,
|
|
373
|
-
accessToken: tokenToUse,
|
|
374
|
-
baseUrl,
|
|
375
|
-
ledgerBaseUrl,
|
|
376
|
-
noticeUuid: content.notice_uuid,
|
|
377
|
-
purposes: content.purposes.map((purpose) => {
|
|
378
|
-
// Check if any required data element is selected
|
|
379
|
-
const hasSelectedRequiredElement = purpose.data_elements.some(
|
|
380
|
-
(element) =>
|
|
381
|
-
element.required &&
|
|
382
|
-
(selectedDataElements[`${purpose.uuid}-${element.uuid}`] ||
|
|
383
|
-
false)
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
// Check if any data element is selected
|
|
387
|
-
const hasSelectedDataElement = purpose.data_elements.some(
|
|
388
|
-
(element) =>
|
|
389
|
-
selectedDataElements[`${purpose.uuid}-${element.uuid}`] || false
|
|
390
|
-
);
|
|
391
|
-
|
|
392
|
-
// Purpose is selected if: purpose checkbox is checked OR any required element is selected OR any data element is selected
|
|
393
|
-
const purposeSelected =
|
|
394
|
-
selectedPurposes[purpose.uuid] ||
|
|
395
|
-
hasSelectedRequiredElement ||
|
|
396
|
-
hasSelectedDataElement;
|
|
397
|
-
|
|
398
|
-
return {
|
|
399
|
-
...purpose,
|
|
400
|
-
selected: purposeSelected,
|
|
401
|
-
data_elements: purpose.data_elements.map((element) => ({
|
|
402
|
-
...element,
|
|
403
|
-
selected:
|
|
404
|
-
selectedDataElements[`${purpose.uuid}-${element.uuid}`] ||
|
|
405
|
-
false,
|
|
406
|
-
})),
|
|
407
|
-
};
|
|
408
|
-
}),
|
|
409
|
-
declined: false,
|
|
410
|
-
meta_data: applicationId
|
|
411
|
-
? { specific_uuid: applicationId }
|
|
412
|
-
: undefined,
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
onAccept?.();
|
|
416
|
-
// Reset ref on success to allow re-submission if needed
|
|
417
|
-
hasSubmittedRef.current = false;
|
|
418
|
-
} catch (error) {
|
|
419
|
-
const err = error as Error;
|
|
420
|
-
// The SDK is a passthrough: server-owned message wins. Only the
|
|
421
|
-
// bare-Error fallback is used when no message is present (e.g. a
|
|
422
|
-
// network failure that never produced a Response).
|
|
423
|
-
const message =
|
|
424
|
-
err.message || "Failed to submit consent. Please try again.";
|
|
425
|
-
setErrorMessage(message);
|
|
426
|
-
// Reset ref on error to allow retry
|
|
427
|
-
hasSubmittedRef.current = false;
|
|
428
|
-
throw error;
|
|
429
|
-
} finally {
|
|
430
|
-
setIsSubmitting(false);
|
|
431
|
-
}
|
|
432
|
-
},
|
|
433
|
-
[
|
|
434
|
-
content,
|
|
435
|
-
org_uuid,
|
|
436
|
-
workspace_uuid,
|
|
437
|
-
baseUrl,
|
|
438
|
-
ledgerBaseUrl,
|
|
439
|
-
selectedDataElements,
|
|
440
|
-
selectedPurposes,
|
|
441
|
-
applicationId,
|
|
442
|
-
onAccept,
|
|
443
|
-
]
|
|
444
|
-
);
|
|
445
|
-
|
|
446
|
-
// Auto-submit consent when all conditions are met. Waits for the ledger
|
|
447
|
-
// check-consent read to settle (isCheckingConsent) and never fires for an
|
|
448
|
-
// already-consented principal, so the cutover cannot trigger a duplicate
|
|
449
|
-
// submission.
|
|
450
|
-
useEffect(() => {
|
|
451
|
-
if (
|
|
452
|
-
accessToken &&
|
|
453
|
-
content &&
|
|
454
|
-
areAllRequiredElementsChecked &&
|
|
455
|
-
!isSubmitting &&
|
|
456
|
-
!isCheckingConsent &&
|
|
457
|
-
!hasAlreadyConsented &&
|
|
458
|
-
!hasSubmittedRef.current
|
|
459
|
-
) {
|
|
460
|
-
hasSubmittedRef.current = true;
|
|
461
|
-
const autoSubmit = async () => {
|
|
462
|
-
try {
|
|
463
|
-
await handleAcceptWithToken(accessToken);
|
|
464
|
-
} catch (err) {
|
|
465
|
-
hasSubmittedRef.current = false;
|
|
466
|
-
onError?.(err as Error);
|
|
467
|
-
}
|
|
468
|
-
};
|
|
469
|
-
autoSubmit();
|
|
470
|
-
}
|
|
471
|
-
}, [
|
|
472
|
-
accessToken,
|
|
473
|
-
content,
|
|
474
|
-
areAllRequiredElementsChecked,
|
|
475
|
-
isSubmitting,
|
|
476
|
-
isCheckingConsent,
|
|
477
|
-
hasAlreadyConsented,
|
|
478
|
-
handleAcceptWithToken,
|
|
479
|
-
]);
|
|
480
|
-
|
|
481
|
-
// Reset submission ref when accessToken changes (allows re-submission with new token)
|
|
482
|
-
useEffect(() => {
|
|
483
|
-
if (!accessToken) {
|
|
484
|
-
hasSubmittedRef.current = false;
|
|
485
|
-
}
|
|
486
|
-
}, [accessToken]);
|
|
487
|
-
|
|
488
|
-
const headingStyle = {
|
|
489
|
-
color: settings?.headingColor || "#101828",
|
|
490
|
-
};
|
|
491
|
-
|
|
492
|
-
const textStyle = {
|
|
493
|
-
color: settings?.textColor || "#344054",
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
if (hasAlreadyConsented || fetchError) {
|
|
497
|
-
return null;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
if (isLoading) {
|
|
501
|
-
return (
|
|
502
|
-
<div style={styles.loadingContainer}>
|
|
503
|
-
<div style={styles.loadingSpinner}></div>
|
|
504
|
-
<p style={{ ...styles.privacyText, ...textStyle }}>Loading...</p>
|
|
505
|
-
</div>
|
|
506
|
-
);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (!content) {
|
|
510
|
-
return null;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
return (
|
|
514
|
-
<div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
|
|
515
|
-
{errorMessage && (
|
|
516
|
-
<div
|
|
517
|
-
role="alert"
|
|
518
|
-
style={{
|
|
519
|
-
backgroundColor: "#FEE2E2",
|
|
520
|
-
color: "#DC2626",
|
|
521
|
-
padding: "12px",
|
|
522
|
-
borderRadius: "6px",
|
|
523
|
-
fontSize: "14px",
|
|
524
|
-
border: "1px solid #FCA5A5",
|
|
525
|
-
}}
|
|
526
|
-
>
|
|
527
|
-
{errorMessage}
|
|
528
|
-
</div>
|
|
529
|
-
)}
|
|
530
|
-
|
|
531
|
-
{content?.purposes?.map((purpose) => (
|
|
532
|
-
<div key={purpose.uuid}>
|
|
533
|
-
<div style={styles.optionItem}>
|
|
534
|
-
<div
|
|
535
|
-
style={styles.optionLeft}
|
|
536
|
-
onClick={() => togglePurposeCollapse(purpose.uuid)}
|
|
537
|
-
role="button"
|
|
538
|
-
tabIndex={0}
|
|
539
|
-
aria-expanded={!collapsedPurposes[purpose.uuid]}
|
|
540
|
-
aria-controls={`purpose-${purpose.uuid}`}
|
|
541
|
-
aria-label={`${collapsedPurposes[purpose.uuid] ? "Expand" : "Collapse"} ${getTranslatedText(
|
|
542
|
-
`purposes.name`,
|
|
543
|
-
purpose.name,
|
|
544
|
-
purpose.uuid
|
|
545
|
-
)} details`}
|
|
546
|
-
onKeyDown={(e) => {
|
|
547
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
548
|
-
e.preventDefault();
|
|
549
|
-
togglePurposeCollapse(purpose.uuid);
|
|
550
|
-
}
|
|
551
|
-
}}
|
|
552
|
-
>
|
|
553
|
-
<div
|
|
554
|
-
style={{
|
|
555
|
-
display: "flex",
|
|
556
|
-
alignItems: "center",
|
|
557
|
-
justifyContent: "center",
|
|
558
|
-
marginLeft: "5px",
|
|
559
|
-
}}
|
|
560
|
-
>
|
|
561
|
-
<svg
|
|
562
|
-
width="7"
|
|
563
|
-
height="12"
|
|
564
|
-
viewBox="0 0 7 12"
|
|
565
|
-
fill="none"
|
|
566
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
567
|
-
stroke={settings?.headingColor || "#323B4B"}
|
|
568
|
-
strokeWidth="2"
|
|
569
|
-
strokeLinecap="round"
|
|
570
|
-
strokeLinejoin="round"
|
|
571
|
-
style={{
|
|
572
|
-
transform: !collapsedPurposes[purpose.uuid]
|
|
573
|
-
? "rotate(90deg)"
|
|
574
|
-
: "rotate(0deg)",
|
|
575
|
-
transition: "transform 0.3s ease",
|
|
576
|
-
}}
|
|
577
|
-
aria-hidden="true"
|
|
578
|
-
>
|
|
579
|
-
<path d="M1 1L6 6L1 11" />
|
|
580
|
-
</svg>
|
|
581
|
-
</div>
|
|
582
|
-
<div style={styles.optionTextContainer}>
|
|
583
|
-
<h2
|
|
584
|
-
style={{
|
|
585
|
-
...styles.optionTitle,
|
|
586
|
-
...responsiveStyles.optionTitle,
|
|
587
|
-
...headingStyle,
|
|
588
|
-
}}
|
|
589
|
-
>
|
|
590
|
-
{getTranslatedText(
|
|
591
|
-
`purposes.name`,
|
|
592
|
-
purpose.name,
|
|
593
|
-
purpose.uuid
|
|
594
|
-
)}
|
|
595
|
-
</h2>
|
|
596
|
-
<h3
|
|
597
|
-
style={{
|
|
598
|
-
...styles.optionDescription,
|
|
599
|
-
...responsiveStyles.optionDescription,
|
|
600
|
-
...textStyle,
|
|
601
|
-
}}
|
|
602
|
-
>
|
|
603
|
-
{getTranslatedText(
|
|
604
|
-
`purposes.description`,
|
|
605
|
-
purpose.description,
|
|
606
|
-
purpose.uuid
|
|
607
|
-
)}
|
|
608
|
-
</h3>
|
|
609
|
-
</div>
|
|
610
|
-
</div>
|
|
611
|
-
<input
|
|
612
|
-
type="checkbox"
|
|
613
|
-
checked={selectedPurposes[purpose.uuid] || false}
|
|
614
|
-
onChange={() => handlePurposeCheckboxChange(purpose.uuid)}
|
|
615
|
-
aria-label={`Select all data elements for ${getTranslatedText(
|
|
616
|
-
`purposes.name`,
|
|
617
|
-
purpose.name,
|
|
618
|
-
purpose.uuid
|
|
619
|
-
)}`}
|
|
620
|
-
/>
|
|
621
|
-
</div>
|
|
622
|
-
{!collapsedPurposes[purpose.uuid] &&
|
|
623
|
-
purpose.data_elements &&
|
|
624
|
-
purpose.data_elements.length > 0 && (
|
|
625
|
-
<div
|
|
626
|
-
id={`purpose-${purpose.uuid}`}
|
|
627
|
-
style={styles.dataElementsContainer}
|
|
628
|
-
>
|
|
629
|
-
{purpose.data_elements.map((dataElement) => (
|
|
630
|
-
<div key={dataElement.uuid} style={styles.dataElementItem}>
|
|
631
|
-
<span
|
|
632
|
-
style={{
|
|
633
|
-
...styles.dataElementText,
|
|
634
|
-
...responsiveStyles.dataElementText,
|
|
635
|
-
...textStyle,
|
|
636
|
-
}}
|
|
637
|
-
>
|
|
638
|
-
{getTranslatedText(
|
|
639
|
-
`data_elements.name`,
|
|
640
|
-
dataElement.name,
|
|
641
|
-
dataElement.uuid
|
|
642
|
-
)}
|
|
643
|
-
{dataElement.required && (
|
|
644
|
-
<span
|
|
645
|
-
style={{
|
|
646
|
-
color: "red",
|
|
647
|
-
marginLeft: "4px",
|
|
648
|
-
}}
|
|
649
|
-
aria-label="required"
|
|
650
|
-
>
|
|
651
|
-
*
|
|
652
|
-
</span>
|
|
653
|
-
)}
|
|
654
|
-
</span>
|
|
655
|
-
<input
|
|
656
|
-
type="checkbox"
|
|
657
|
-
checked={
|
|
658
|
-
selectedDataElements[
|
|
659
|
-
`${purpose.uuid}-${dataElement.uuid}`
|
|
660
|
-
] || false
|
|
661
|
-
}
|
|
662
|
-
onChange={() =>
|
|
663
|
-
handleDataElementCheckboxChange(
|
|
664
|
-
dataElement.uuid,
|
|
665
|
-
purpose.uuid
|
|
666
|
-
)
|
|
667
|
-
}
|
|
668
|
-
aria-label={`Select ${getTranslatedText(
|
|
669
|
-
`data_elements.name`,
|
|
670
|
-
dataElement.name,
|
|
671
|
-
dataElement.uuid
|
|
672
|
-
)}${dataElement.required ? " (required)" : ""}`}
|
|
673
|
-
/>
|
|
674
|
-
</div>
|
|
675
|
-
))}
|
|
676
|
-
</div>
|
|
677
|
-
)}
|
|
678
|
-
</div>
|
|
679
|
-
))}
|
|
680
|
-
</div>
|
|
681
|
-
);
|
|
682
|
-
};
|
|
683
|
-
|
|
684
|
-
RedactoConsentInlineComponent.displayName = "RedactoConsentInline";
|
|
685
|
-
|
|
686
|
-
// Memoize the component to prevent unnecessary re-renders when props haven't changed
|
|
687
|
-
export const RedactoConsentInline = memo(RedactoConsentInlineComponent);
|