diff --git a/app/models/BannerTests.scala b/app/models/BannerTests.scala index 8c6fd177..63570c35 100644 --- a/app/models/BannerTests.scala +++ b/app/models/BannerTests.scala @@ -63,6 +63,7 @@ case class BannerTest( deviceType: Option[DeviceType] = None, campaignName: Option[String] = Some("NOT_IN_CAMPAIGN"), signedInStatus: Option[SignedInStatus] = Some(SignedInStatus.All), + consentStatus: Option[ConsentStatus] = Some(ConsentStatus.All), ) extends ChannelTest[BannerTest] { override def withChannel(channel: Channel): BannerTest = diff --git a/app/models/ConsentStatus.scala b/app/models/ConsentStatus.scala new file mode 100644 index 00000000..91e05262 --- /dev/null +++ b/app/models/ConsentStatus.scala @@ -0,0 +1,16 @@ +package models + +import io.circe.generic.extras.Configuration +import io.circe.generic.extras.semiauto.{ deriveEnumerationDecoder, deriveEnumerationEncoder } +import io.circe.{Decoder, Encoder} + +sealed trait ConsentStatus + +object ConsentStatus { + case object All extends ConsentStatus + case object HasConsented extends ConsentStatus + case object HasNotConsented extends ConsentStatus + implicit val customConfig: Configuration = Configuration.default.withDefaults + implicit val decoder: Decoder[ConsentStatus] = deriveEnumerationDecoder[ConsentStatus] + implicit val encoder: Encoder[ConsentStatus] = deriveEnumerationEncoder[ConsentStatus] +} diff --git a/app/models/EpicTest.scala b/app/models/EpicTest.scala index 292faa8b..0472e973 100644 --- a/app/models/EpicTest.scala +++ b/app/models/EpicTest.scala @@ -60,6 +60,7 @@ case class EpicTest( deviceType: Option[DeviceType] = None, campaignName: Option[String] = Some("NOT_IN_CAMPAIGN"), signedInStatus: Option[SignedInStatus] = Some(SignedInStatus.All), + consentStatus: Option[ConsentStatus] = Some(ConsentStatus.All), ) extends ChannelTest[EpicTest] { override def withChannel(channel: Channel): EpicTest = this.copy(channel = Some(channel)) diff --git a/app/models/HeaderTests.scala b/app/models/HeaderTests.scala index 622157c0..62087f04 100644 --- a/app/models/HeaderTests.scala +++ b/app/models/HeaderTests.scala @@ -32,6 +32,7 @@ case class HeaderTest( deviceType: Option[DeviceType] = None, campaignName: Option[String] = Some("NOT_IN_CAMPAIGN"), signedInStatus: Option[SignedInStatus] = Some(SignedInStatus.All), + consentStatus: Option[ConsentStatus] = Some(ConsentStatus.All), ) extends ChannelTest[HeaderTest] { override def withChannel(channel: Channel): HeaderTest = this.copy(channel = Some(channel)) diff --git a/public/src/components/channelManagement/bannerTests/bannerTestEditor.tsx b/public/src/components/channelManagement/bannerTests/bannerTestEditor.tsx index 9e304422..95c9d063 100644 --- a/public/src/components/channelManagement/bannerTests/bannerTestEditor.tsx +++ b/public/src/components/channelManagement/bannerTests/bannerTestEditor.tsx @@ -1,6 +1,12 @@ import React, { useEffect, useState } from 'react'; import { Region } from '../../../utils/models'; -import { ArticlesViewedSettings, DeviceType, SignedInStatus, UserCohort } from '../helpers/shared'; +import { + ArticlesViewedSettings, + ConsentStatus, + DeviceType, + SignedInStatus, + UserCohort, +} from '../helpers/shared'; import { ARTICLE_COUNT_TEMPLATE } from '../helpers/validation'; import { Typography } from '@mui/material'; import BannerTestVariantEditor from './bannerTestVariantEditor'; @@ -128,6 +134,10 @@ const BannerTestEditor: React.FC> = ({ onTestChange({ ...test, signedInStatus }); }; + const onConsentStatusChange = (consentStatus: ConsentStatus): void => { + onTestChange({ ...test, consentStatus }); + }; + const onArticlesViewedSettingsChange = ( updatedArticlesViewedSettings?: ArticlesViewedSettings, ): void => { @@ -263,6 +273,9 @@ const BannerTestEditor: React.FC> = ({ showDeviceTypeSelector={true} selectedSignedInStatus={test.signedInStatus} onSignedInStatusChange={onSignedInStatusChange} + selectedConsentStatus={test.consentStatus} + onConsentStatusChange={onConsentStatusChange} + showConsentStatusSelector={true} /> diff --git a/public/src/components/channelManagement/epicTests/epicTestEditor.tsx b/public/src/components/channelManagement/epicTests/epicTestEditor.tsx index c1ae6ffa..c2a60743 100644 --- a/public/src/components/channelManagement/epicTests/epicTestEditor.tsx +++ b/public/src/components/channelManagement/epicTests/epicTestEditor.tsx @@ -8,6 +8,7 @@ import { DeviceType, SignedInStatus, PageContextTargeting, + ConsentStatus, } from '../helpers/shared'; import { FormControlLabel, Switch, Typography } from '@mui/material'; import CampaignSelector from '../CampaignSelector'; @@ -158,6 +159,10 @@ export const getEpicTestEditor = ( onTestChange({ ...test, signedInStatus }); }; + const onConsentChange = (consentStatus: ConsentStatus): void => { + onTestChange({ ...test, consentStatus }); + }; + const onArticlesViewedSettingsChange = ( updatedArticlesViewedSettings?: ArticlesViewedSettings, ): void => { @@ -332,6 +337,9 @@ export const getEpicTestEditor = ( showDeviceTypeSelector={epicEditorConfig.allowDeviceTypeTargeting} selectedSignedInStatus={test.signedInStatus} onSignedInStatusChange={onSignedInStatusChange} + selectedConsentStatus={test.consentStatus} + onConsentStatusChange={onConsentChange} + showConsentStatusSelector={false} platform={epicEditorConfig.platform} /> diff --git a/public/src/components/channelManagement/headerTests/headerTestEditor.tsx b/public/src/components/channelManagement/headerTests/headerTestEditor.tsx index 8e32742f..e3d1c864 100644 --- a/public/src/components/channelManagement/headerTests/headerTestEditor.tsx +++ b/public/src/components/channelManagement/headerTests/headerTestEditor.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Region } from '../../../utils/models'; -import { DeviceType, SignedInStatus, UserCohort } from '../helpers/shared'; +import { ConsentStatus, DeviceType, SignedInStatus, UserCohort } from '../helpers/shared'; import { Typography } from '@mui/material'; import HeaderTestVariantEditor from './headerTestVariantEditor'; @@ -73,6 +73,10 @@ const HeaderTestEditor: React.FC> = ({ onTestChange({ ...test, signedInStatus }); }; + const onConsentChange = (consentStatus: ConsentStatus): void => { + onTestChange({ ...test, consentStatus }); + }; + const renderVariantEditor = (variant: HeaderVariant): React.ReactElement => ( > = ({ showDeviceTypeSelector={true} selectedSignedInStatus={test.signedInStatus} onSignedInStatusChange={onSignedInStatusChange} + selectedConsentStatus={test.consentStatus} + onConsentStatusChange={onConsentChange} + showConsentStatusSelector={false} /> diff --git a/public/src/components/channelManagement/helpers/shared.ts b/public/src/components/channelManagement/helpers/shared.ts index f632d8af..0616501c 100644 --- a/public/src/components/channelManagement/helpers/shared.ts +++ b/public/src/components/channelManagement/helpers/shared.ts @@ -27,6 +27,7 @@ export interface Test { userCohort?: string; channel?: string; signedInStatus?: SignedInStatus; + consentStatus?: ConsentStatus; } export interface EpicEditorConfig { @@ -253,6 +254,8 @@ export type ContributionFrequency = 'ONE_OFF' | 'MONTHLY' | 'ANNUAL'; export type DeviceType = 'Mobile' | 'Desktop' | 'All' | 'iOS' | 'Android'; +export type ConsentStatus = 'HasConsented' | 'HasNotConsented' | 'All'; + export interface Image { mainUrl: string; altText: string; diff --git a/public/src/components/channelManagement/testEditorTargetAudienceSelector.tsx b/public/src/components/channelManagement/testEditorTargetAudienceSelector.tsx index 9ce97bba..203b47bd 100644 --- a/public/src/components/channelManagement/testEditorTargetAudienceSelector.tsx +++ b/public/src/components/channelManagement/testEditorTargetAudienceSelector.tsx @@ -3,7 +3,13 @@ import React from 'react'; import { Theme, Typography } from '@mui/material'; import { makeStyles } from '@mui/styles'; import { Region } from '../../utils/models'; -import { DeviceType, SignedInStatus, UserCohort, TestPlatform } from './helpers/shared'; +import { + DeviceType, + SignedInStatus, + UserCohort, + TestPlatform, + ConsentStatus, +} from './helpers/shared'; import TestEditorTargetRegionsSelector from './testEditorTargetRegionsSelector'; import TypedRadioGroup from './TypedRadioGroup'; @@ -41,6 +47,9 @@ interface TestEditorTargetAudienceSelectorProps { showDeviceTypeSelector: boolean; selectedSignedInStatus?: SignedInStatus; onSignedInStatusChange: (signedInStatus: SignedInStatus) => void; + selectedConsentStatus?: ConsentStatus; + onConsentStatusChange: (consentStatus: ConsentStatus) => void; + showConsentStatusSelector: boolean; platform?: TestPlatform; } const TestEditorTargetAudienceSelector: React.FC = ({ @@ -56,6 +65,9 @@ const TestEditorTargetAudienceSelector: React.FC { const classes = useStyles(); @@ -120,6 +132,22 @@ const TestEditorTargetAudienceSelector: React.FC + + {showConsentStatusSelector && ( +
+ Consent Status + +
+ )} ); };