(Feature) Implement GDPR requirements (#490)

* (fix) format script command

* (add) "Accept preferences" link

* (add) footer

* (fix) mobile accept preferences link

* (fix) linting

* (fix) script typo
This commit is contained in:
Gabriel Rodríguez Alsina 2020-01-31 11:06:22 -03:00 committed by GitHub
parent ef79515972
commit 84926fde82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 130 additions and 84 deletions

View File

@ -23,7 +23,7 @@
"start": "node scripts/start.js", "start": "node scripts/start.js",
"start-mainnet": "REACT_APP_NETWORK=mainnet yarn start", "start-mainnet": "REACT_APP_NETWORK=mainnet yarn start",
"test": "NODE_ENV=test && node scripts/test.js --env=jsdom", "test": "NODE_ENV=test && node scripts/test.js --env=jsdom",
"format": "prettier-eslint \"src/**/*.js\" --write" "format": "prettier-eslint $PWD'/src/**/*.{js,jsx}' --write"
}, },
"pre-commit": [ "pre-commit": [
"precommit" "precommit"

View File

@ -1,14 +1,15 @@
// @flow // @flow
import Checkbox from '@material-ui/core/Checkbox' import Checkbox from '@material-ui/core/Checkbox'
import Close from '@material-ui/icons/Close'
import FormControlLabel from '@material-ui/core/FormControlLabel' import FormControlLabel from '@material-ui/core/FormControlLabel'
import IconButton from '@material-ui/core/IconButton'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { makeStyles } from '@material-ui/core/styles' import { makeStyles } from '@material-ui/core/styles'
import { useDispatch, useSelector } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import cn from 'classnames'
import Link from '~/components/layout/Link' import Link from '~/components/layout/Link'
import Button from '~/components/layout/Button' import Button from '~/components/layout/Button'
import { primary, mainFontFamily, md } from '~/theme/variables' import {
primary, mainFontFamily, md, screenSm,
} from '~/theme/variables'
import type { CookiesProps } from '~/logic/cookies/model/cookie' import type { CookiesProps } from '~/logic/cookies/model/cookie'
import { COOKIES_KEY } from '~/logic/cookies/model/cookie' import { COOKIES_KEY } from '~/logic/cookies/model/cookie'
import { loadFromCookie, saveCookie } from '~/logic/cookies/utils' import { loadFromCookie, saveCookie } from '~/logic/cookies/utils'
@ -48,9 +49,12 @@ const useStyles = makeStyles({
columnGap: '10px', columnGap: '10px',
display: 'grid', display: 'grid',
gridTemplateColumns: '1fr', gridTemplateColumns: '1fr',
paddingBottom: '30px',
rowGap: '10px', rowGap: '10px',
'@media (min-width: 960px)': {
[`@media (min-width: ${screenSm}px)`]: {
gridTemplateColumns: '1fr 1fr 1fr', gridTemplateColumns: '1fr 1fr 1fr',
paddingBottom: '0',
}, },
}, },
formItem: { formItem: {
@ -64,10 +68,20 @@ const useStyles = makeStyles({
textDecoration: 'none', textDecoration: 'none',
}, },
}, },
close: { acceptPreferences: {
bottom: '-20px',
cursor: 'pointer',
position: 'absolute', position: 'absolute',
right: '12px', right: '20px',
top: '12px', textDecoration: 'underline',
[`@media (min-width: ${screenSm}px)`]: {
bottom: '-10px',
},
'&:hover': {
textDecoration: 'none',
},
}, },
}) })
@ -120,12 +134,16 @@ const CookiesBanner = () => {
const cookieBannerContent = ( const cookieBannerContent = (
<div className={classes.container}> <div className={classes.container}>
<IconButton onClick={() => closeCookiesBannerHandler()} className={classes.close}><Close /></IconButton> <span role="button" tabIndex="0" onClick={closeCookiesBannerHandler} onKeyDown={closeCookiesBannerHandler} className={cn(classes.acceptPreferences, classes.text)}>
Accept preferences &gt;
</span>
<div className={classes.content}> <div className={classes.content}>
<p className={classes.text}> <p className={classes.text}>
We use cookies to give you the best experience and to help improve our website. Please read our We use cookies to give you the best experience and to help improve our website. Please read our
{' '} {' '}
<Link className={classes.link} to="https://safe.gnosis.io/cookie">Cookie Policy</Link> <Link className={classes.link} to="https://safe.gnosis.io/cookie">
Cookie Policy
</Link>
{' '} {' '}
for more information. By clicking &quot;Accept all&quot;, you agree to the storing of cookies on your device for more information. By clicking &quot;Accept all&quot;, you agree to the storing of cookies on your device
to enhance site navigation, analyze site usage and provide customer support. to enhance site navigation, analyze site usage and provide customer support.
@ -139,9 +157,7 @@ const CookiesBanner = () => {
name="Necessary" name="Necessary"
onChange={() => setLocalNecessary((prev) => !prev)} onChange={() => setLocalNecessary((prev) => !prev)}
value={localNecessary} value={localNecessary}
control={( control={<Checkbox disabled />}
<Checkbox disabled />
)}
/> />
</div> </div>
<div className={classes.formItem}> <div className={classes.formItem}>
@ -150,9 +166,7 @@ const CookiesBanner = () => {
name="Analytics" name="Analytics"
onChange={() => setLocalAnalytics((prev) => !prev)} onChange={() => setLocalAnalytics((prev) => !prev)}
value={localAnalytics} value={localAnalytics}
control={( control={<Checkbox checked={localAnalytics} />}
<Checkbox checked={localAnalytics} />
)}
/> />
</div> </div>
<div className={classes.formItem}> <div className={classes.formItem}>

View File

@ -0,0 +1,95 @@
// @flow
import * as React from 'react'
import { makeStyles } from '@material-ui/core/styles'
import { useDispatch } from 'react-redux'
import cn from 'classnames'
import Link from '~/components/layout/Link'
import { secondary, screenSm, sm } from '~/theme/variables'
import { openCookieBanner } from '~/logic/cookies/store/actions/openCookieBanner'
import GnoButtonLink from '~/components/layout/ButtonLink'
const useStyles = makeStyles({
footer: {
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'center',
margin: '0 auto',
maxWidth: '100%',
padding: `40px ${sm} 20px`,
width: `${screenSm}px`,
},
item: {
color: 'rgba(0, 0, 0, 0.54)',
fontSize: '13px',
},
link: {
color: secondary,
textDecoration: 'none',
'&:hover': {
textDecoration: 'underline',
},
},
sep: {
color: 'rgba(0, 0, 0, 0.54)',
margin: '0 10px',
},
buttonLink: {
padding: '0',
},
})
const appVersion = process.env.REACT_APP_APP_VERSION ? `v${process.env.REACT_APP_APP_VERSION} ` : 'Versions'
const Footer = () => {
const date = new Date()
const classes = useStyles()
const dispatch = useDispatch()
const openCookiesHandler = () => {
dispatch(openCookieBanner(true))
}
return (
<footer className={classes.footer}>
<span className={classes.item}>
©
{' '}
{date.getFullYear()}
{' '}
Gnosis
</span>
<span className={classes.sep}>|</span>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/terms" target="_blank">
Terms
</Link>
<span className={classes.sep}>|</span>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/privacy" target="_blank">
Privacy
</Link>
<span className={classes.sep}>|</span>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/licenses" target="_blank">
Licenses
</Link>
<span className={classes.sep}>|</span>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/imprint" target="_blank">
Imprint
</Link>
<span className={classes.sep}>|</span>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/cookie" target="_blank">
Cookie Policy
</Link>
<span className={classes.sep}>-</span>
<GnoButtonLink className={cn(classes.item, classes.link, classes.buttonLink)} onClick={openCookiesHandler}>
Preferences
</GnoButtonLink>
<span className={classes.sep}>|</span>
<Link className={cn(classes.item, classes.link)} to="https://github.com/gnosis/safe-react/releases" target="_blank">
{appVersion}
</Link>
</footer>
)
}
export default Footer

View File

@ -1,63 +0,0 @@
// @flow
import React from 'react'
import { makeStyles } from '@material-ui/core/styles'
import { useDispatch } from 'react-redux'
import Block from '~/components/layout/Block'
import Link from '~/components/layout/Link'
import { sm, primary } from '~/theme/variables'
import { openCookieBanner } from '~/logic/cookies/store/actions/openCookieBanner'
import GnoButtonLink from '~/components/layout/ButtonLink'
const useStyles = makeStyles({
container: {
padding: `${sm} 0`,
},
link: {
color: primary,
},
buttonLink: {
textDecoration: 'none',
color: primary,
},
})
type Props = {
toggleSidebar: Function,
}
const appVersion = process.env.REACT_APP_APP_VERSION ? `v${process.env.REACT_APP_APP_VERSION}` : 'Versions'
const LegalLinks = (props: Props) => {
const classes = useStyles()
const dispatch = useDispatch()
const openCookiesHandler = () => {
dispatch(openCookieBanner(true))
props.toggleSidebar()
}
return (
<Block className={classes.container} justify="space-around">
<Link className={classes.link} to="https://safe.gnosis.io/terms" target="_blank">
Terms
</Link>
<Link className={classes.link} to="https://safe.gnosis.io/privacy" target="_blank">
Privacy
</Link>
<Link className={classes.link} to="https://safe.gnosis.io/licenses" target="_blank">
Licenses
</Link>
<Link className={classes.link} to="https://safe.gnosis.io/imprint" target="_blank">
Imprint
</Link>
<GnoButtonLink className={classes.buttonLink} onClick={openCookiesHandler}>
Cookies
</GnoButtonLink>
<Link className={classes.link} to="https://github.com/gnosis/safe-react/releases" target="_blank">
{appVersion}
</Link>
</Block>
)
}
export default LegalLinks

View File

@ -21,7 +21,6 @@ import {
import setDefaultSafe from '~/routes/safe/store/actions/setDefaultSafe' import setDefaultSafe from '~/routes/safe/store/actions/setDefaultSafe'
import { sortedSafeListSelector } from './selectors' import { sortedSafeListSelector } from './selectors'
import SafeList from './SafeList' import SafeList from './SafeList'
import LegalLinks from './LegalLinks'
import useSidebarStyles from './style' import useSidebarStyles from './style'
const { useState, useEffect, useMemo } = React const { useState, useEffect, useMemo } = React
@ -46,8 +45,8 @@ type SidebarProps = {
const filterBy = (filter: string, safes: List<Safe>): List<Safe> => safes.filter( const filterBy = (filter: string, safes: List<Safe>): List<Safe> => safes.filter(
(safe: Safe) => !filter (safe: Safe) => !filter
|| safe.address.toLowerCase().includes(filter.toLowerCase()) || safe.address.toLowerCase().includes(filter.toLowerCase())
|| safe.name.toLowerCase().includes(filter.toLowerCase()), || safe.name.toLowerCase().includes(filter.toLowerCase()),
) )
const Sidebar = ({ const Sidebar = ({
@ -137,7 +136,6 @@ const Sidebar = ({
defaultSafe={defaultSafe} defaultSafe={defaultSafe}
currentSafe={currentSafe} currentSafe={currentSafe}
/> />
<LegalLinks toggleSidebar={toggleSidebar} />
</Drawer> </Drawer>
</ClickAwayListener> </ClickAwayListener>
{children} {children}

View File

@ -6,6 +6,7 @@ import { withStyles } from '@material-ui/core/styles'
import Backdrop from '~/components/layout/Backdrop' import Backdrop from '~/components/layout/Backdrop'
import CookiesBanner from '~/components/CookiesBanner' import CookiesBanner from '~/components/CookiesBanner'
import Header from '~/components/Header' import Header from '~/components/Header'
import Footer from '~/components/Footer'
import Img from '~/components/layout/Img' import Img from '~/components/layout/Img'
import Notifier from '~/components/Notifier' import Notifier from '~/components/Notifier'
import SidebarProvider from '~/components/Sidebar' import SidebarProvider from '~/components/Sidebar'
@ -67,6 +68,7 @@ const PageFrame = ({ children, classes, currentNetwork }: Props) => {
<SidebarProvider> <SidebarProvider>
<Header /> <Header />
{children} {children}
<Footer />
</SidebarProvider> </SidebarProvider>
</SnackbarProvider> </SnackbarProvider>
<CookiesBanner /> <CookiesBanner />