Skip to content
This repository has been archived by the owner on Nov 10, 2023. It is now read-only.

feat: Cookies and privacy policy #3517

Merged
merged 5 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from 4 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: 8 additions & 3 deletions src/components/AppLayout/Sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { wrapInSuspense } from 'src/utils/wrapInSuspense'
import ListIcon from 'src/components/List/ListIcon'
import { openCookieBanner } from 'src/logic/cookies/store/actions/openCookieBanner'
import { loadFromCookie } from 'src/logic/cookies/utils'
import { COOKIES_KEY, BannerCookiesType } from 'src/logic/cookies/model/cookie'
import { COOKIES_KEY, BannerCookiesType, COOKIE_IDS } from 'src/logic/cookies/model/cookie'

const StyledDivider = styled(Divider)`
margin: 16px -8px 0;
Expand Down Expand Up @@ -88,8 +88,13 @@ const Sidebar = ({
dispatch(openCookieBanner({ cookieBannerOpen: true }))
return
}
if (!cookiesState.acceptedIntercom) {
dispatch(openCookieBanner({ cookieBannerOpen: true, intercomAlertDisplayed: true }))
if (!cookiesState.acceptedAnalytics) {
dispatch(
openCookieBanner({
cookieBannerOpen: true,
key: COOKIE_IDS.BEAMER,
}),
)
}
}

Expand Down
49 changes: 26 additions & 23 deletions src/components/CookiesBanner/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { ReactElement, useEffect, useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import Button from 'src/components/layout/Button'
import Link from 'src/components/layout/Link'
import { COOKIES_KEY, BannerCookiesType } from 'src/logic/cookies/model/cookie'
import { openCookieBanner } from 'src/logic/cookies/store/actions/openCookieBanner'
import { cookieBannerOpen } from 'src/logic/cookies/store/selectors'
import { COOKIES_KEY, BannerCookiesType, COOKIE_IDS, COOKIE_ALERTS } from 'src/logic/cookies/model/cookie'
import { closeCookieBanner, openCookieBanner } from 'src/logic/cookies/store/actions/openCookieBanner'
import { cookieBannerState } from 'src/logic/cookies/store/selectors'
import { loadFromCookie, saveCookie } from 'src/logic/cookies/utils'
import { mainFontFamily, md, primary, screenSm } from 'src/theme/variables'
import { loadGoogleAnalytics, removeCookies } from 'src/utils/googleAnalytics'
Expand Down Expand Up @@ -93,13 +93,9 @@ const useStyles = makeStyles({
},
} as any)

interface CookiesBannerFormProps {
alertMessage: boolean
}

const CookiesBanner = (): ReactElement => {
const classes = useStyles()
const dispatch = useRef(useDispatch())
const dispatch = useDispatch()
const intercomLoaded = isIntercomLoaded()

const [showAnalytics, setShowAnalytics] = useState(false)
Expand All @@ -110,14 +106,13 @@ const CookiesBanner = (): ReactElement => {
const { getAppUrl } = useSafeAppUrl()
const beamerScriptRef = useRef<HTMLScriptElement>()

const showBanner = useSelector(cookieBannerOpen)
const { key, cookieBannerOpen } = useSelector(cookieBannerState)
const newAppUrl = getAppUrl()
const isSafeAppView = newAppUrl !== null

useEffect(() => {
if (showIntercom && !isSafeAppView) {
loadIntercom()
loadBeamer(beamerScriptRef)
}
}, [showIntercom, isSafeAppView])

Expand All @@ -131,7 +126,7 @@ const CookiesBanner = (): ReactElement => {
async function fetchCookiesFromStorage() {
const cookiesState = await loadFromCookie<BannerCookiesType>(COOKIES_KEY)
if (!cookiesState) {
dispatch.current(openCookieBanner({ cookieBannerOpen: true }))
dispatch(openCookieBanner({ cookieBannerOpen: true }))
} else {
const { acceptedIntercom, acceptedAnalytics, acceptedNecessary } = cookiesState
if (acceptedIntercom === undefined) {
Expand All @@ -155,11 +150,15 @@ const CookiesBanner = (): ReactElement => {

if (acceptedAnalytics && !isDesktop) {
loadGoogleAnalytics()

// For use in non-webapps (Mobile and Desktop)
// https://www.getbeamer.com/help/how-to-install-beamer-using-our-api
loadBeamer(beamerScriptRef)
iamacook marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
fetchCookiesFromStorage()
}, [showAnalytics, showIntercom])
}, [dispatch, showAnalytics, showIntercom])

const acceptCookiesHandler = async () => {
const newState = {
Expand All @@ -173,7 +172,7 @@ const CookiesBanner = (): ReactElement => {
await saveCookie<BannerCookiesType>(COOKIES_KEY, newState, cookieConfig)
setShowAnalytics(!isDesktop)
setShowIntercom(true)
dispatch.current(openCookieBanner({ cookieBannerOpen: false }))
dispatch(closeCookieBanner())
}

const closeCookiesBannerHandler = async () => {
Expand All @@ -191,24 +190,23 @@ const CookiesBanner = (): ReactElement => {

if (!localAnalytics) {
removeCookies()
closeBeamer(beamerScriptRef)
}

if (!localIntercom && isIntercomLoaded()) {
closeIntercom()
closeBeamer(beamerScriptRef)
}
dispatch.current(openCookieBanner({ cookieBannerOpen: false }))
dispatch(closeCookieBanner())
}

const CookiesBannerForm = (props: CookiesBannerFormProps) => {
const { alertMessage } = props
const CookiesBannerForm = () => {
return (
<div data-testid="cookies-banner-form" className={classes.container}>
<div className={classes.content}>
{alertMessage && (
{key && (
<div className={classes.intercomAlert}>
<img src={AlertRedIcon} />
You attempted to open the customer support chat. Please accept the customer support cookie.
{COOKIE_ALERTS[key]}
</div>
)}
<p className={classes.text}>
Expand Down Expand Up @@ -284,12 +282,17 @@ const CookiesBanner = (): ReactElement => {
<img
className={classes.intercomImage}
src={IntercomIcon}
onClick={() => dispatch.current(openCookieBanner({ cookieBannerOpen: true, intercomAlertDisplayed: true }))}
onClick={() =>
dispatch(
openCookieBanner({
cookieBannerOpen: true,
key: COOKIE_IDS.INTERCOM,
}),
)
}
/>
)}
{!isDesktop && showBanner?.cookieBannerOpen && (
<CookiesBannerForm alertMessage={showBanner?.intercomAlertDisplayed} />
)}
{!isDesktop && cookieBannerOpen && <CookiesBannerForm />}
</>
)
}
Expand Down
15 changes: 13 additions & 2 deletions src/logic/cookies/model/cookie.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
export const COOKIES_KEY = 'COOKIES'
export const COOKIES_KEY_INTERCOM = `${COOKIES_KEY}_INTERCOM`

export enum COOKIE_IDS {
INTERCOM = 'INTERCOM',
BEAMER = 'BEAMER',
}

export const COOKIE_ALERTS: Record<COOKIE_IDS, string> = {
INTERCOM: 'You attempted to open the customer support chat. Please accept the customer support cookie',
BEAMER: "You attempted to open the What's New section. Please accept the analytics cookies.",
}

export type BannerCookiesType = {
acceptedNecessary: boolean
acceptedIntercom: boolean
Expand All @@ -6,5 +19,3 @@ export type BannerCookiesType = {
export type IntercomCookieType = {
userId: string
}
export const COOKIES_KEY = 'COOKIES'
export const COOKIES_KEY_INTERCOM = `${COOKIES_KEY}_INTERCOM`
8 changes: 6 additions & 2 deletions src/logic/cookies/store/actions/openCookieBanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { createAction } from 'redux-actions'

import { OpenCookieBannerPayload } from 'src/logic/cookies/store/reducer/cookies'

export const OPEN_COOKIE_BANNER = 'OPEN_COOKIE_BANNER'
export enum COOKIE_ACTIONS {
OPEN_BANNER = 'cookies/openCookieBanner',
CLOSE_BANNER = 'cookies/closeCookieBanner',
}

export const openCookieBanner = createAction<OpenCookieBannerPayload>(OPEN_COOKIE_BANNER)
export const openCookieBanner = createAction<OpenCookieBannerPayload>(COOKIE_ACTIONS.OPEN_BANNER)
export const closeCookieBanner = createAction(COOKIE_ACTIONS.CLOSE_BANNER)
27 changes: 19 additions & 8 deletions src/logic/cookies/store/reducer/cookies.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
import { Map } from 'immutable'
import { handleActions } from 'redux-actions'
import { OPEN_COOKIE_BANNER } from 'src/logic/cookies/store/actions/openCookieBanner'

import { COOKIE_IDS } from 'src/logic/cookies/model/cookie'
import { COOKIE_ACTIONS } from 'src/logic/cookies/store/actions/openCookieBanner'

export const COOKIES_REDUCER_ID = 'cookies'

type CookieState = Map<string, any>
export type CookieState = {
cookieBannerOpen: boolean
key?: COOKIE_IDS
}

const initialState: CookieState = {
cookieBannerOpen: false,
key: undefined,
}

export type OpenCookieBannerPayload = { cookieBannerOpen: boolean; intercomAlertDisplayed?: boolean }
export type OpenCookieBannerPayload = CookieState

const cookiesReducer = handleActions<CookieState, OpenCookieBannerPayload>(
{
[OPEN_COOKIE_BANNER]: (state, action) => {
const { intercomAlertDisplayed = false, cookieBannerOpen } = action.payload
return state.set('cookieBannerOpen', { intercomAlertDisplayed, cookieBannerOpen })
[COOKIE_ACTIONS.OPEN_BANNER]: (_, action) => {
return action.payload
},
[COOKIE_ACTIONS.CLOSE_BANNER]: () => {
return initialState
},
},
Map(),
initialState,
)

export default cookiesReducer
5 changes: 3 additions & 2 deletions src/logic/cookies/store/selectors/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { COOKIES_REDUCER_ID } from 'src/logic/cookies/store/reducer/cookies'
import { CookieState, COOKIES_REDUCER_ID } from 'src/logic/cookies/store/reducer/cookies'
import { AppReduxState } from 'src/store'

export const cookieBannerOpen = (state) => state[COOKIES_REDUCER_ID].get('cookieBannerOpen')
export const cookieBannerState = (state: AppReduxState): CookieState => state[COOKIES_REDUCER_ID]
4 changes: 2 additions & 2 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
nftAssetReducer,
nftTokensReducer,
} from 'src/logic/collectibles/store/reducer/collectibles'
import cookiesReducer, { COOKIES_REDUCER_ID } from 'src/logic/cookies/store/reducer/cookies'
import cookiesReducer, { CookieState, COOKIES_REDUCER_ID } from 'src/logic/cookies/store/reducer/cookies'
import currentSessionReducer, {
CurrentSessionState,
CURRENT_SESSION_REDUCER_ID,
Expand Down Expand Up @@ -112,7 +112,7 @@ export type AppReduxState = CombinedState<{
[PENDING_TRANSACTIONS_ID]: PendingTransactionsState
[NOTIFICATIONS_REDUCER_ID]: Map<string, Notification>
[CURRENCY_REDUCER_ID]: CurrencyValuesState
[COOKIES_REDUCER_ID]: Map<string, any>
[COOKIES_REDUCER_ID]: CookieState
[ADDRESS_BOOK_REDUCER_ID]: AddressBookState
[CURRENT_SESSION_REDUCER_ID]: CurrentSessionState
[CONFIG_REDUCER_ID]: ConfigState
Expand Down