Skip to content
This repository has been archived by the owner on Apr 3, 2024. It is now read-only.

Custom Categories #60

Merged
merged 13 commits into from
Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/consent-manager-builder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Component } from 'react'
import { loadPreferences, savePreferences } from './preferences'
import fetchDestinations from './fetch-destinations'
import conditionallyLoadAnalytics from './analytics'
import { Destination, CategoryPreferences } from '../types'
import { Destination, CategoryPreferences, CustomCategories } from '../types'

function getNewDestinations(destinations: Destination[], preferences: CategoryPreferences) {
const newDestinations: Destination[] = []
Expand Down Expand Up @@ -53,6 +53,11 @@ interface Props {
preferences: CategoryPreferences
) => { destinationPreferences: CategoryPreferences; customPreferences: CategoryPreferences }

/**
* Allows for adding custom consent categories by mapping a custom category to Segment integrations
*/
customCategories?: CustomCategories

/**
* A callback for dealing with errors in the Consent Manager
*/
Expand All @@ -64,6 +69,7 @@ interface RenderProps {
newDestinations: Destination[]
preferences: CategoryPreferences
isConsentRequired: boolean
customCategories?: CustomCategories
setPreferences: (newPreferences: CategoryPreferences) => void
resetPreferences: () => void
saveConsent: (newPreferences?: CategoryPreferences | boolean, shouldReload?: boolean) => void
Expand Down Expand Up @@ -96,7 +102,7 @@ export default class ConsentManagerBuilder extends Component<Props, State> {
}

render() {
const { children } = this.props
const { children, customCategories } = this.props
const { isLoading, destinations, preferences, newDestinations, isConsentRequired } = this.state

if (isLoading) {
Expand All @@ -105,6 +111,7 @@ export default class ConsentManagerBuilder extends Component<Props, State> {

return children({
destinations,
customCategories,
newDestinations,
preferences,
isConsentRequired,
Expand Down
6 changes: 5 additions & 1 deletion src/consent-manager/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Banner from './banner'
import PreferenceDialog from './preference-dialog'
import CancelDialog from './cancel-dialog'
import { ADVERTISING_CATEGORIES, FUNCTIONAL_CATEGORIES } from './categories'
import { Destination, CategoryPreferences } from '../types'
import { Destination, CategoryPreferences, CustomCategories } from '../types'

const emitter = new EventEmitter()
export function openDialog() {
Expand All @@ -23,6 +23,7 @@ interface ContainerProps {
resetPreferences: () => void
closeBehavior?: CloseBehavior
destinations: Destination[]
customCategories?: CustomCategories | undefined

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't the ? take care of the undefined case here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I originally had it as just customCategories?: CustomCategories but it was failing validation - because sometimes we do pass in customCategories but the value is undefined.

newDestinations: Destination[]
preferences: CategoryPreferences
isConsentRequired: boolean
Expand Down Expand Up @@ -173,6 +174,9 @@ const Container: React.FC<ContainerProps> = props => {

{isDialogOpen && (
<PreferenceDialog
customCategories={props.customCategories}
destinations={props.destinations}
preferences={props.preferences}
innerRef={current => (preferenceDialog = { current })}
onCancel={handleCancel}
onSave={handleSave}
Expand Down
65 changes: 59 additions & 6 deletions src/consent-manager/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default class ConsentManager extends PureComponent<ConsentManagerProps, {
implyConsentOnInteraction: false,
onError: undefined,
cookieDomain: undefined,
customCategories: undefined,
bannerTextColor: '#fff',
bannerSubContent: 'You can change your preferences at any time.',
bannerBackgroundColor: '#1f4160',
Expand All @@ -41,7 +42,7 @@ export default class ConsentManager extends PureComponent<ConsentManagerProps, {
preferencesDialogContent,
cancelDialogTitle,
cancelDialogContent,
initialPreferences,
customCategories,
onError
} = this.props

Expand All @@ -52,11 +53,13 @@ export default class ConsentManager extends PureComponent<ConsentManagerProps, {
otherWriteKeys={otherWriteKeys}
shouldRequireConsent={shouldRequireConsent}
cookieDomain={cookieDomain}
initialPreferences={initialPreferences || zeroValuePreferences}
initialPreferences={this.getInitialPreferences()}
mapCustomPreferences={this.handleMapCustomPreferences}
customCategories={customCategories}
>
{({
destinations,
customCategories,
newDestinations,
preferences,
isConsentRequired,
Expand All @@ -65,6 +68,7 @@ export default class ConsentManager extends PureComponent<ConsentManagerProps, {
saveConsent
}) => {
return <Container
customCategories={customCategories}
destinations={destinations}
newDestinations={newDestinations}
preferences={preferences}
Expand All @@ -90,10 +94,53 @@ export default class ConsentManager extends PureComponent<ConsentManagerProps, {
)
}

getInitialPreferences = () => {
const { initialPreferences, customCategories } = this.props
if (initialPreferences) {
return initialPreferences
}

if (!customCategories) {
return zeroValuePreferences
}

const initialCustomPreferences = {}
Object.keys(customCategories).forEach(category => {
initialCustomPreferences[category] = null
})

return initialCustomPreferences
}

handleMapCustomPreferences = (destinations: Destination[], preferences: CategoryPreferences) => {
const { customCategories } = this.props
const destinationPreferences = {}
const customPreferences = {}

if (customCategories) {
for (const preferenceName of Object.keys(customCategories)) {
const value = preferences[preferenceName]
if (typeof value === 'boolean') {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could just do this here I think:

          customPreferences[preferenceName] = Boolean(value)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is saying "if explicitly set as true or false, set as true or false, if not set (i.e. value is null), set to true"

customPreferences[preferenceName] = value
} else {
customPreferences[preferenceName] = true
}
}

destinations.forEach(destination => {
// Mark custom categories
Object.entries(customCategories).forEach(([categoryName, { integrations }]) => {
const consentAlreadySetToFalse = destinationPreferences[destination.id] === false
const shouldSetConsent = integrations.includes(destination.name)
if (shouldSetConsent && !consentAlreadySetToFalse) {
destinationPreferences[destination.id] = customPreferences[categoryName]
}
})
})

return { destinationPreferences, customPreferences }
}

// Default unset preferences to true (for implicit consent)
for (const preferenceName of Object.keys(preferences)) {
const value = preferences[preferenceName]
Expand All @@ -107,12 +154,18 @@ export default class ConsentManager extends PureComponent<ConsentManagerProps, {
const customPrefs = customPreferences as CategoryPreferences

for (const destination of destinations) {
if (ADVERTISING_CATEGORIES.find(c => c === destination.category)) {
// Mark advertising destinations
if (ADVERTISING_CATEGORIES.find(c => c === destination.category) && destinationPreferences[destination.id] !== false) {
destinationPreferences[destination.id] = customPrefs.advertising
} else if (FUNCTIONAL_CATEGORIES.find(c => c === destination.category)) {
}

// Mark function destinations
if (FUNCTIONAL_CATEGORIES.find(c => c === destination.category) && destinationPreferences[destination.id] !== false) {
destinationPreferences[destination.id] = customPrefs.functional
} else {
// Fallback to marketing
}

// Fallback to marketing
if (!(destination.id in destinationPreferences)) {
destinationPreferences[destination.id] = customPrefs.marketingAndAnalytics
}
}
Expand Down
Loading