diff --git a/package.json b/package.json
index efd4c0d..f3d33f5 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"url": "https://github.com/transcend-io/consent-manager-ui.git"
},
"homepage": "https://github.com/transcend-io/consent-manager-ui",
- "version": "4.21.2",
+ "version": "4.22.0",
"license": "MIT",
"main": "build/ui",
"files": [
diff --git a/src/components/CompleteOptionsInverted.tsx b/src/components/CompleteOptionsInverted.tsx
index 6610c43..15a7bd9 100644
--- a/src/components/CompleteOptionsInverted.tsx
+++ b/src/components/CompleteOptionsInverted.tsx
@@ -1,7 +1,7 @@
import { h, JSX } from 'preact';
import { useState } from 'preact/hooks';
import { useIntl } from 'react-intl';
-import { useAirgap, useGetPurposeMessageKeys } from '../hooks';
+import { useAirgap, useGetInvertedPurposeMessageKeys } from '../hooks';
import {
messages,
completeOptionsMessages,
@@ -36,7 +36,7 @@ export function CompleteOptionsInverted({
// Get the tracking purposes from Airgap for display
const initialConsentSelections = getConsentSelections(airgap);
- const purposeToMessageKey = useGetPurposeMessageKeys({
+ const purposeToMessageKey = useGetInvertedPurposeMessageKeys({
consentSelection: initialConsentSelections,
defaultPurposeToMessageKey: DEFAULT_PURPOSE_TO_INVERTED_MESSAGE_KEY,
});
diff --git a/src/components/CompleteOptionsToggles.tsx b/src/components/CompleteOptionsToggles.tsx
index 531056a..a939bdf 100644
--- a/src/components/CompleteOptionsToggles.tsx
+++ b/src/components/CompleteOptionsToggles.tsx
@@ -4,11 +4,19 @@ import { useMemo, useState } from 'preact/hooks';
import { useIntl } from 'react-intl';
import { getConsentSelections } from '../consent-selections';
import { CONSENT_OPTIONS } from '../constants';
-import { useAirgap, useGetPurposeMessageKeys } from '../hooks';
+import {
+ useAirgap,
+ useGetPurposeDescriptionKeys,
+ useGetPurposeMessageKeys,
+} from '../hooks';
import { messages } from '../messages';
import type { HandleSetViewState } from '../types';
import { CloseButton } from './CloseButton';
-import { DEFAULT_PURPOSE_TO_MESSAGE_KEY, ORDER_OF_PURPOSES } from './constants';
+import {
+ DEFAULT_PURPOSE_TO_DESCRIPTION_KEY,
+ DEFAULT_PURPOSE_TO_MESSAGE_KEY,
+ ORDER_OF_PURPOSES,
+} from './constants';
import { Switch } from './Switch';
/**
@@ -37,7 +45,11 @@ export function CompleteOptionsToggles({
defaultPurposeToMessageKey: DEFAULT_PURPOSE_TO_MESSAGE_KEY,
});
const purposeToDescription = useMemo(() => airgap.getPurposeTypes(), []);
-
+ const purposeToDescriptionKey = useGetPurposeDescriptionKeys({
+ consentSelection: initialConsentSelections,
+ defaultPurposeToDescriptionKey: DEFAULT_PURPOSE_TO_DESCRIPTION_KEY,
+ airgapPurposes: purposeToDescription,
+ });
// Set state on the currently selected toggles
const [consentSelections, setConsentSelections] = useState(
initialConsentSelections,
@@ -140,7 +152,10 @@ export function CompleteOptionsToggles({
}
/>
- {purposeToDescription.Essential?.description}
+ {formatMessage(
+ purposeToDescriptionKey.Essential,
+ globalUiVariables,
+ )}
{orderedSelections.map(([purpose, isChecked], idx) => (
@@ -166,7 +181,10 @@ export function CompleteOptionsToggles({
{...(idx === 0 ? { initialFocus: true } : {})}
/>
- {purposeToDescription[purpose]?.description}
+ {formatMessage(
+ purposeToDescriptionKey[purpose],
+ globalUiVariables,
+ )}
))}
diff --git a/src/components/constants.ts b/src/components/constants.ts
index 83dab18..dee21c2 100644
--- a/src/components/constants.ts
+++ b/src/components/constants.ts
@@ -1,23 +1,31 @@
import { DefinedMessage } from '@transcend-io/internationalization';
-import {
- completeOptionsMessages,
- completeOptionsInvertedMessages,
-} from '../messages';
+import { completeOptionsInvertedMessages, purposeMessages } from '../messages';
// Mapping of purposes to the message translation key
export const DEFAULT_PURPOSE_TO_MESSAGE_KEY: Record = {
- Essential: completeOptionsMessages.essentialLabel,
- Functional: completeOptionsMessages.functionalLabel,
- Analytics: completeOptionsMessages.analyticsLabel,
- Advertising: completeOptionsMessages.advertisingLabel,
- SaleOfInfo: completeOptionsMessages.saleOfInfoLabel,
+ Essential: purposeMessages['Essential.title'],
+ Functional: purposeMessages['Functional.title'],
+ Analytics: purposeMessages['Analytics.title'],
+ Advertising: purposeMessages['Advertising.title'],
+ SaleOfInfo: purposeMessages['SaleOfInfo.title'],
+};
+
+export const DEFAULT_PURPOSE_TO_DESCRIPTION_KEY: Record<
+ string,
+ DefinedMessage
+> = {
+ Essential: purposeMessages['Essential.description'],
+ Functional: purposeMessages['Functional.description'],
+ Analytics: purposeMessages['Analytics.description'],
+ Advertising: purposeMessages['Advertising.description'],
+ SaleOfInfo: purposeMessages['SaleOfInfo.description'],
};
export const DEFAULT_PURPOSE_TO_INVERTED_MESSAGE_KEY: Record<
string,
DefinedMessage
> = {
- Essential: completeOptionsMessages.essentialLabel,
+ Essential: purposeMessages['Essential.title'],
Functional: completeOptionsInvertedMessages.functionalLabel,
Analytics: completeOptionsInvertedMessages.analyticsLabel,
Advertising: completeOptionsInvertedMessages.advertisingLabel,
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index fcf6bf7..249de7a 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -2,4 +2,6 @@ export * from './useLanguage';
export * from './useStickyState';
export * from './useViewState';
export * from './useAirgap';
+export * from './useGetInvertedPurposeMessageKeys';
+export * from './useGetPurposeDescriptionKeys';
export * from './useGetPurposeMessageKeys';
diff --git a/src/hooks/useGetInvertedPurposeMessageKeys.ts b/src/hooks/useGetInvertedPurposeMessageKeys.ts
new file mode 100644
index 0000000..3d566ea
--- /dev/null
+++ b/src/hooks/useGetInvertedPurposeMessageKeys.ts
@@ -0,0 +1,43 @@
+import { ConsentSelection } from '../types';
+
+import { useMemo } from 'preact/hooks';
+
+import { DefinedMessage } from '@transcend-io/internationalization';
+
+const PURPOSE_MESSAGE_PREFIX = 'purpose.trackingType';
+
+export const useGetInvertedPurposeMessageKeys = ({
+ consentSelection,
+ defaultPurposeToMessageKey,
+}: {
+ /** The configured airgap purpose types */
+ consentSelection: ConsentSelection;
+ /** The lookup of messages for default purpose types */
+ defaultPurposeToMessageKey: Record;
+}): Record => {
+ const purposeToMessageKey: Record = useMemo(
+ () =>
+ // the purpose type is unique for the bundle
+ [...Object.keys(consentSelection ?? {}), 'Essential'].reduce(
+ (allMessages, purposeType) => {
+ if (allMessages[purposeType]) {
+ return allMessages;
+ }
+ const purposeMessageLabel = `${PURPOSE_MESSAGE_PREFIX}.${purposeType}.title`;
+ return {
+ ...allMessages,
+ [purposeType]: {
+ id: purposeMessageLabel,
+ defaultMessage: defaultPurposeToMessageKey[purposeType]?.defaultMessage
+ || purposeType,
+ description: `Translatable name for purpose '${purposeType}'`,
+ } as DefinedMessage,
+ };
+ },
+ defaultPurposeToMessageKey as Record,
+ ),
+ [consentSelection, defaultPurposeToMessageKey],
+ );
+
+ return purposeToMessageKey;
+};
diff --git a/src/hooks/useGetPurposeDescriptionKeys.ts b/src/hooks/useGetPurposeDescriptionKeys.ts
new file mode 100644
index 0000000..1eb521d
--- /dev/null
+++ b/src/hooks/useGetPurposeDescriptionKeys.ts
@@ -0,0 +1,48 @@
+import type {
+ TrackingPurposesTypes,
+} from '@transcend-io/airgap.js-types';
+
+import { ConsentSelection } from '../types';
+
+import { useMemo } from 'preact/hooks';
+
+import { DefinedMessage } from '@transcend-io/internationalization';
+
+const PURPOSE_MESSAGE_PREFIX = 'purpose.trackingType';
+
+export const useGetPurposeDescriptionKeys = ({
+ consentSelection,
+ defaultPurposeToDescriptionKey,
+ airgapPurposes,
+}: {
+ /** The configured airgap purpose types */
+ consentSelection: ConsentSelection;
+ /** The lookup of messages for default purpose types */
+ defaultPurposeToDescriptionKey: Record;
+ /** Airgap purposes data */
+ airgapPurposes: TrackingPurposesTypes;
+}): Record => {
+ const purposeToDescriptionKey: Record = useMemo(
+ () =>
+ // hard-coding Essential since it's not provided by consentSelection
+ [...Object.keys(consentSelection ?? {}), 'Essential'].reduce((allMessages, purposeType) => {
+ // making sure default message for Essential is not overwritten
+ // by missing Essential message from airgap
+ if (airgapPurposes[purposeType]?.description) {
+ const purposeMessageDescriptionId = `${PURPOSE_MESSAGE_PREFIX}.${purposeType}.description`;
+ return {
+ ...allMessages,
+ [purposeType]: {
+ id: purposeMessageDescriptionId,
+ defaultMessage: airgapPurposes[purposeType]?.description,
+ description: `Translatable description for purpose '${purposeType}'`,
+ } as DefinedMessage,
+ };
+ }
+ return {...allMessages};
+ }, defaultPurposeToDescriptionKey as Record),
+ [consentSelection, defaultPurposeToDescriptionKey],
+ );
+
+ return purposeToDescriptionKey;
+};
diff --git a/src/hooks/useGetPurposeMessageKeys.ts b/src/hooks/useGetPurposeMessageKeys.ts
index 348df3b..892b33b 100644
--- a/src/hooks/useGetPurposeMessageKeys.ts
+++ b/src/hooks/useGetPurposeMessageKeys.ts
@@ -4,7 +4,7 @@ import { useMemo } from 'preact/hooks';
import { DefinedMessage } from '@transcend-io/internationalization';
-const CUSTOM_PURPOSE_MESSAGE_PREFIX = 'cm-ui.purpose';
+const PURPOSE_MESSAGE_PREFIX = 'purpose.trackingType';
export const useGetPurposeMessageKeys = ({
consentSelection,
@@ -18,20 +18,20 @@ export const useGetPurposeMessageKeys = ({
const purposeToMessageKey: Record = useMemo(
() =>
// the purpose type is unique for the bundle
- Object.keys(consentSelection ?? {}).reduce((allMessages, purposeType) => {
- if (allMessages[purposeType]) {
- return allMessages;
- }
- const customPurposeMessageLabel = `${CUSTOM_PURPOSE_MESSAGE_PREFIX}.${purposeType}`;
- return {
- ...allMessages,
- [purposeType]: {
- id: customPurposeMessageLabel,
- defaultMessage: purposeType,
- description: `Translatable name for custom purpose '${purposeType}'`,
- } as DefinedMessage,
- };
- }, defaultPurposeToMessageKey as Record),
+ [...Object.keys(consentSelection ?? {}), 'Essential'].reduce(
+ (allMessages, purposeType) => {
+ const purposeMessageLabel = `${PURPOSE_MESSAGE_PREFIX}.${purposeType}.title`;
+ return {
+ ...allMessages,
+ [purposeType]: {
+ id: purposeMessageLabel,
+ defaultMessage: purposeType,
+ description: `Translatable name for purpose '${purposeType}'`,
+ } as DefinedMessage,
+ };
+ },
+ defaultPurposeToMessageKey as Record,
+ ),
[consentSelection, defaultPurposeToMessageKey],
);
diff --git a/src/messages.ts b/src/messages.ts
index 388709d..a6af0fc 100644
--- a/src/messages.ts
+++ b/src/messages.ts
@@ -456,32 +456,60 @@ export const bottomMenuMessages = defineMessages('ui.src.bottomMenu', {
},
});
+export const purposeMessages = defineMessages('purpose.trackingType', {
+ 'Essential.title': {
+ defaultMessage: 'Essential',
+ description: 'Text for essential purposes in CompleteOptions view state.',
+ },
+ 'Essential.description': {
+ defaultMessage: 'No consent needed.',
+ description:
+ 'Text for essential purposes description in CompleteOptions view state.',
+ },
+ 'Functional.title': {
+ defaultMessage: 'Functional',
+ description:
+ 'Text for functional purposes in CompleteOptions view state.',
+ },
+ 'Functional.description': {
+ defaultMessage: 'Personalization, autofilled forms, etc.',
+ description:
+ 'Text for functional purposes description in CompleteOptions view state.',
+ },
+ 'Analytics.title': {
+ defaultMessage: 'Analytics',
+ description: 'Text for analytics purposes in CompleteOptions view state.',
+ },
+ 'Analytics.description': {
+ defaultMessage: 'Help us learn how our site is used and how it performs.',
+ description:
+ 'Text for analytics purposes description in CompleteOptions view state.',
+ },
+ 'Advertising.title': {
+ defaultMessage: 'Advertising',
+ description:
+ 'Text for advertising purposes in CompleteOptions view state.',
+ },
+ 'Advertising.description': {
+ defaultMessage: 'Helps us and others serve ads relevant to you.',
+ description:
+ 'Text for advertising purposes description in CompleteOptions view state.',
+ },
+ 'SaleOfInfo.title': {
+ defaultMessage: 'SaleOfInfo',
+ description:
+ 'Text for sale of information purposes in CompleteOptions view state.',
+ },
+ 'SaleOfInfo.description': {
+ defaultMessage: 'Sale of personal information.',
+ description:
+ 'Text for advertising purposes description in CompleteOptions view state.',
+ },
+});
+
export const completeOptionsMessages = defineMessages(
'ui.src.completeOptions',
{
- essentialLabel: {
- defaultMessage: 'Essential purposes',
- description: 'Text for essential purposes in CompleteOptions view state.',
- },
- functionalLabel: {
- defaultMessage: 'Functionality',
- description:
- 'Text for functional purposes in CompleteOptions view state.',
- },
- analyticsLabel: {
- defaultMessage: 'Analytics',
- description: 'Text for analytics purposes in CompleteOptions view state.',
- },
- advertisingLabel: {
- defaultMessage: 'Advertising',
- description:
- 'Text for advertising purposes in CompleteOptions view state.',
- },
- saleOfInfoLabel: {
- defaultMessage: 'Sale of personal information',
- description:
- 'Text for sale of information purposes in CompleteOptions view state.',
- },
saveButtonPrimary: {
defaultMessage: 'Confirm',
description: 'Confirm button text in CompleteOptions view state.',