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

Commit

Permalink
Initial Preferences override (#49)
Browse files Browse the repository at this point in the history
* Document props

* Add option to provide custom initial consent

* Change signature

* Harden type

* Swap write keys

* Add CookieView to every story

* Fix logic

* Do not generate sourceMap

* Bump size limit
  • Loading branch information
nettofarah authored Oct 10, 2019
1 parent cb2c4a6 commit 71c9bb7
Show file tree
Hide file tree
Showing 20 changed files with 213 additions and 105 deletions.
1 change: 1 addition & 0 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const pkg = require('../package.json')

module.exports = {
mode: 'development',
devtool: 'source-map',
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ The initial value of the preferences. By default it should be an object map of `
Type: `function`<br>
Default: `undefined`

Callback function allows you to use a custom preferences format (e.g: categories) instead of the default destination based one. The function gets called during the consent saving process and gets passed `{destinations, preferences}`. The function should return `{destinationPreferences, customPreferences}` where `destinationPreferences` is your custom preferences mapped to the destinations format (`{destiantionId: true|false}`) and `customPreferences` is your custom preferences if you changed them in the callback (optional).
Callback function allows you to use a custom preferences format (e.g: categories) instead of the default destination based one. The function gets called during the consent saving process and gets passed `(destinations, preferences)`. The function should return `{destinationPreferences, customPreferences}` where `destinationPreferences` is your custom preferences mapped to the destinations format (`{destiantionId: true|false}`) and `customPreferences` is your custom preferences if you changed them in the callback (optional).

##### cookieDomain

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
"size-limit": [
{
"path": "esm/index.js",
"limit": "48 KB"
"limit": "50 KB"
},
{
"path": "standalone/consent-manager.js",
Expand Down
2 changes: 1 addition & 1 deletion src/consent-manager-builder/fetch-destinations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ async function fetchDestinationForWriteKey(writeKey: string): Promise<Destinatio
}

export default async function fetchDestinations(writeKeys: string[]): Promise<Destination[]> {
const destinationsRequests: any[] = []
const destinationsRequests: Promise<Destination[]>[] = []
for (const writeKey of writeKeys) {
destinationsRequests.push(fetchDestinationForWriteKey(writeKey))
}
Expand Down
67 changes: 49 additions & 18 deletions src/consent-manager-builder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,41 @@ function getNewDestinations(destinations: Destination[], preferences: CategoryPr
}

interface Props {
onError?: (err: Error) => void | Promise<void>
/** Your Segment Write key for your website */
writeKey: string

/** A list of other write keys you may want to provide */
otherWriteKeys?: string[]
shouldRequireConsent?: () => Promise<boolean> | boolean
initialPreferences?: CategoryPreferences

cookieDomain?: string

/**
* An initial selection of Preferences
*/
initialPreferences?: CategoryPreferences

/**
* Provide a function to define whether or not consent should be required
*/
shouldRequireConsent?: () => Promise<boolean> | boolean

/**
* Render props for the Consent Manager builder
*/
children: (props: RenderProps) => React.ReactElement

mapCustomPreferences?: (args: {
destinations: Destination[]
/**
* Allows for customizing how to show different categories of consent.
*/
mapCustomPreferences?: (
destinations: Destination[],
preferences: CategoryPreferences
}) => { destinationPreferences: CategoryPreferences; customPreferences: CategoryPreferences }
) => { destinationPreferences: CategoryPreferences; customPreferences: CategoryPreferences }

/**
* A callback for dealing with errors in the Consent Manager
*/
onError?: (err: Error) => void | Promise<void>
}

interface RenderProps {
Expand Down Expand Up @@ -113,7 +136,7 @@ export default class ConsentManagerBuilder extends Component<Props, State> {
mapCustomPreferences
} = this.props
// TODO: add option to run mapCustomPreferences on load so that the destination preferences automatically get updated
const { destinationPreferences = {}, customPreferences } = loadPreferences()
let { destinationPreferences = {}, customPreferences } = loadPreferences()

const [isConsentRequired, destinations] = await Promise.all([
shouldRequireConsent(),
Expand All @@ -122,20 +145,31 @@ export default class ConsentManagerBuilder extends Component<Props, State> {

const newDestinations = getNewDestinations(destinations, destinationPreferences)

let preferences: CategoryPreferences | undefined
if (mapCustomPreferences) {
preferences = customPreferences || initialPreferences || {}

const hasInitialPreferenceToTrue = Object.values(initialPreferences || {}).some(Boolean)
const emptyCustomPreferecences = Object.values(customPreferences || {}).every(
v => v === null || v === undefined
)

if (hasInitialPreferenceToTrue && emptyCustomPreferecences) {
const mapped = mapCustomPreferences(destinations, preferences)
destinationPreferences = mapped.destinationPreferences
customPreferences = mapped.customPreferences
}
} else {
preferences = destinationPreferences || initialPreferences
}

conditionallyLoadAnalytics({
writeKey,
destinations,
destinationPreferences,
isConsentRequired
})

let preferences: CategoryPreferences | undefined
if (mapCustomPreferences) {
preferences = customPreferences || initialPreferences
} else {
preferences = destinationPreferences || initialPreferences
}

this.setState({
isLoading: false,
destinations,
Expand Down Expand Up @@ -187,10 +221,7 @@ export default class ConsentManagerBuilder extends Component<Props, State> {
let customPreferences: CategoryPreferences | undefined

if (mapCustomPreferences) {
const custom = mapCustomPreferences({
destinations,
preferences
})
const custom = mapCustomPreferences(destinations, preferences)
destinationPreferences = custom.destinationPreferences
customPreferences = custom.customPreferences

Expand Down
13 changes: 4 additions & 9 deletions src/consent-manager/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Container from './container'
import { ADVERTISING_CATEGORIES, FUNCTIONAL_CATEGORIES } from './categories'
import { CategoryPreferences, Destination, ConsentManagerProps } from '../types'

const initialPreferences: CategoryPreferences = {
const zeroValuePreferences: CategoryPreferences = {
marketingAndAnalytics: null,
advertising: null,
functional: null
Expand Down Expand Up @@ -41,6 +41,7 @@ export default class ConsentManager extends PureComponent<ConsentManagerProps, {
preferencesDialogContent,
cancelDialogTitle,
cancelDialogContent,
initialPreferences,
onError
} = this.props

Expand All @@ -51,7 +52,7 @@ export default class ConsentManager extends PureComponent<ConsentManagerProps, {
otherWriteKeys={otherWriteKeys}
shouldRequireConsent={shouldRequireConsent}
cookieDomain={cookieDomain}
initialPreferences={initialPreferences}
initialPreferences={initialPreferences || zeroValuePreferences}
mapCustomPreferences={this.handleMapCustomPreferences}
>
{({
Expand Down Expand Up @@ -89,13 +90,7 @@ export default class ConsentManager extends PureComponent<ConsentManagerProps, {
)
}

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

Expand Down
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type WindowWithConsentManagerConfig = Window &
typeof globalThis & {
consentManagerConfig?: (
args: StandaloneConsentManagerParams
) => Partial<ConsentManagerInput> | Partial<ConsentManagerInput>
) => ConsentManagerInput | ConsentManagerInput
}

export type ConsentManagerInput = ConsentManagerProps & {
Expand Down Expand Up @@ -65,4 +65,5 @@ export interface ConsentManagerProps {
cancelDialogTitle?: React.ReactNode
cancelDialogContent: React.ReactNode
closeBehavior?: CloseBehavior
initialPreferences?: CategoryPreferences
}
4 changes: 3 additions & 1 deletion stories/0-consent-manager.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { CloseBehavior } from '../src/consent-manager/container'
import { docco } from 'react-syntax-highlighter/dist/esm/styles/hljs'
import SyntaxHighlighter from 'react-syntax-highlighter'
import { Preferences } from '../src/types'
import CookieView from './components/CookieView'

const bannerContent = (
<span>
Expand Down Expand Up @@ -79,7 +80,7 @@ const ConsentManagerExample = (props: { closeBehavior: CloseBehavior }) => {
return (
<Pane>
<ConsentManager
writeKey="mA3XTMcavCUOQo5DL56VIHWcJMsyhAI7"
writeKey="tYQQPcY78Hc3T1hXUYk0n4xcbEHnN7r0"
otherWriteKeys={['vMRS7xbsjH97Bb2PeKbEKvYDvgMm5T3l']}
bannerContent={bannerContent}
bannerSubContent={bannerSubContent}
Expand Down Expand Up @@ -128,6 +129,7 @@ const ConsentManagerExample = (props: { closeBehavior: CloseBehavior }) => {
</Button>
</p>
</Pane>
<CookieView />
</Pane>
)
}
Expand Down
5 changes: 4 additions & 1 deletion stories/0.1-consent-manager-close-interaction.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Pane, Heading, Button } from 'evergreen-ui'
import { ConsentManager, openConsentManager } from '../src'
import { storiesOf } from '@storybook/react'
import { ImplyConsentOnInteraction } from './ImplyConsentOnInteraction'
import CookieView from './components/CookieView'

const bannerContent = (
<span>
Expand Down Expand Up @@ -64,7 +65,7 @@ const ConsentManagerExample = () => {
return (
<Pane>
<ConsentManager
writeKey="mA3XTMcavCUOQo5DL56VIHWcJMsyhAI7"
writeKey="tYQQPcY78Hc3T1hXUYk0n4xcbEHnN7r0"
otherWriteKeys={['vMRS7xbsjH97Bb2PeKbEKvYDvgMm5T3l']}
bannerContent={bannerContent}
bannerSubContent={bannerSubContent}
Expand Down Expand Up @@ -108,6 +109,8 @@ const ConsentManagerExample = () => {
</Button>
</p>
</Pane>

<CookieView />
</Pane>
)
}
Expand Down
33 changes: 18 additions & 15 deletions stories/1-standalone.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,27 @@ import { docco } from 'react-syntax-highlighter/dist/esm/styles/hljs'

// @ts-ignore
import contents from 'raw-loader!./standalone.html'
import CookieView from './components/CookieView'

const StandaloneConsentManagerExample = () => {
return (
<Pane display="flex" height="calc(100vh - 10px)">
<iframe
frameBorder="0"
style={{ overflow: 'hidden', height: '100%', width: '100%' }}
height="100%"
width="100%"
srcDoc={contents}
></iframe>
<SyntaxHighlighter language="html" style={docco}>
{contents}
</SyntaxHighlighter>
</Pane>
<>
<Pane display="flex" height="calc(100vh - 10px)">
<iframe
frameBorder="0"
style={{ overflow: 'hidden', height: '100%', width: '550px', flex: 1 }}
height="100%"
width="550"
srcDoc={contents}
></iframe>
<SyntaxHighlighter language="html" style={docco} customStyle={{ flex: 1 }}>
{contents}
</SyntaxHighlighter>
</Pane>

<CookieView />
</>
)
}

storiesOf('Script Tag', module).add(`Standalone Script Tag`, () => (
<StandaloneConsentManagerExample />
))
storiesOf('Standalone / Tag', module).add(`Basic`, () => <StandaloneConsentManagerExample />)
30 changes: 17 additions & 13 deletions stories/1.1-standalone-custom.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,28 @@ import { docco } from 'react-syntax-highlighter/dist/esm/styles/hljs'

// @ts-ignore
import contents from 'raw-loader!./standalone-custom.html'
import CookieView from './components/CookieView'

const StandaloneConsentManagerExample = () => {
return (
<Pane display="flex" height="calc(100vh - 10px)">
<iframe
frameBorder="0"
style={{ overflow: 'hidden', height: '100%', width: '100%' }}
height="100%"
width="100%"
srcDoc={contents}
></iframe>
<SyntaxHighlighter language="html" style={docco}>
{contents}
</SyntaxHighlighter>
</Pane>
<>
<Pane display="flex" height="calc(100vh - 10px)">
<iframe
frameBorder="0"
style={{ overflow: 'hidden', height: '100%', width: '550px', flex: 1 }}
height="100%"
width="550"
srcDoc={contents}
></iframe>
<SyntaxHighlighter language="html" style={docco} customStyle={{ flex: 1 }}>
{contents}
</SyntaxHighlighter>
</Pane>
<CookieView />
</>
)
}

storiesOf('Script Tag', module).add(`Standalone Script Tag with Customization`, () => (
storiesOf('Standalone / Javascript', module).add(`with Customization`, () => (
<StandaloneConsentManagerExample />
))
7 changes: 5 additions & 2 deletions stories/2-category-based.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import React from 'react'
import { groupBy } from 'lodash'
import { Pane, Heading, SubHeading, Ul, Code, Button } from 'evergreen-ui'
import { ConsentManagerBuilder } from '../src'
import DestinationTile from './destination-tile'
import DestinationTile from './components/destination-tile'
import { storiesOf } from '@storybook/react'
import CookieView from './components/CookieView'

function Section(props) {
return <Pane is="section" marginBottom={24} {...props} />
Expand All @@ -18,7 +19,7 @@ const CategoryBased = () => {
<Pane maxWidth={1000} margin={30}>
<ConsentManagerBuilder
onError={e => console.error('Error Handling', e)}
writeKey="mA3XTMcavCUOQo5DL56VIHWcJMsyhAI7"
writeKey="tYQQPcY78Hc3T1hXUYk0n4xcbEHnN7r0"
otherWriteKeys={['vMRS7xbsjH97Bb2PeKbEKvYDvgMm5T3l']}
>
{({ destinations, preferences, setPreferences, saveConsent }) => {
Expand Down Expand Up @@ -74,6 +75,8 @@ const CategoryBased = () => {
)
}}
</ConsentManagerBuilder>

<CookieView />
</Pane>
)
}
Expand Down
7 changes: 5 additions & 2 deletions stories/3-tool-based.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react'
import { Pane, Heading, SubHeading, Ul, Code, Button } from 'evergreen-ui'
import { ConsentManagerBuilder } from '../src'
import DestinationTile from './destination-tile'
import DestinationTile from './components/destination-tile'
import { storiesOf } from '@storybook/react'
import CookieView from './components/CookieView'

function Section(props) {
return <Pane is="section" marginBottom={24} {...props} />
Expand All @@ -12,7 +13,7 @@ const ToolBased = () => {
return (
<Pane maxWidth={1000} margin={30}>
<ConsentManagerBuilder
writeKey="mA3XTMcavCUOQo5DL56VIHWcJMsyhAI7"
writeKey="tYQQPcY78Hc3T1hXUYk0n4xcbEHnN7r0"
otherWriteKeys={['vMRS7xbsjH97Bb2PeKbEKvYDvgMm5T3l']}
>
{({ destinations, preferences, setPreferences, saveConsent }) => {
Expand Down Expand Up @@ -57,6 +58,8 @@ const ToolBased = () => {
)
}}
</ConsentManagerBuilder>

<CookieView />
</Pane>
)
}
Expand Down
Loading

0 comments on commit 71c9bb7

Please sign in to comment.