From 1562a5d58eb1ad775803a32693850ed8481038e8 Mon Sep 17 00:00:00 2001 From: Cassie Tarakajian Date: Tue, 3 Aug 2021 16:29:18 -0400 Subject: [PATCH 01/24] Add CookieConsent component --- client/constants.js | 2 + client/modules/App/App.jsx | 2 + client/modules/User/actions.js | 29 ++-- .../modules/User/components/CookieConsent.jsx | 140 ++++++++++++++++++ client/modules/User/reducers.js | 2 + package-lock.json | 30 ++-- package.json | 1 + server/controllers/user.controller.js | 3 +- server/models/user.js | 7 +- server/views/index.js | 18 ++- 10 files changed, 186 insertions(+), 48 deletions(-) create mode 100644 client/modules/User/components/CookieConsent.jsx diff --git a/client/constants.js b/client/constants.js index 13c74e0504..2678e6950b 100644 --- a/client/constants.js +++ b/client/constants.js @@ -145,3 +145,5 @@ export const STOP_LOADING = 'STOP_LOADING'; export const START_SAVING_PROJECT = 'START_SAVING_PROJECT'; export const END_SAVING_PROJECT = 'END_SAVING_PROJECT'; + +export const SET_COOKIE_CONSENT = 'SET_COOKIE_CONSENT'; diff --git a/client/modules/App/App.jsx b/client/modules/App/App.jsx index c6b7a581bb..7e602f272e 100644 --- a/client/modules/App/App.jsx +++ b/client/modules/App/App.jsx @@ -5,6 +5,7 @@ import getConfig from '../../utils/getConfig'; import DevTools from './components/DevTools'; import { setPreviousPath } from '../IDE/actions/ide'; import { setLanguage } from '../IDE/actions/preferences'; +import CookieConsent from '../User/components/CookieConsent'; class App extends React.Component { constructor(props, context) { @@ -41,6 +42,7 @@ class App extends React.Component { render() { return (
+ {this.state.isMounted && !window.devToolsExtension && getConfig('NODE_ENV') === 'development' && } diff --git a/client/modules/User/actions.js b/client/modules/User/actions.js index 5d04c73c8a..4ebfab7890 100644 --- a/client/modules/User/actions.js +++ b/client/modules/User/actions.js @@ -20,13 +20,6 @@ export function loginUser(formValues) { return apiClient.post('/login', formValues); } -export function loginUserSuccess(user) { - return { - type: ActionTypes.AUTH_USER, - user - }; -} - export function authenticateUser(user) { return { type: ActionTypes.AUTH_USER, @@ -55,7 +48,7 @@ export function validateAndLoginUser(formProps) { return new Promise((resolve) => { loginUser(formProps) .then((response) => { - dispatch(loginUserSuccess(response.data)); + dispatch(authenticateUser(response.data)); dispatch(setPreferences(response.data.preferences)); dispatch( setLanguage(response.data.preferences.language, { @@ -102,10 +95,7 @@ export function getUser() { apiClient .get('/session') .then((response) => { - dispatch({ - type: ActionTypes.AUTH_USER, - user: response.data - }); + dispatch(authenticateUser(response.data)); dispatch({ type: ActionTypes.SET_PREFERENCES, preferences: response.data.preferences @@ -259,7 +249,7 @@ export function updatePassword(formValues, token) { apiClient .post(`/reset-password/${token}`, formValues) .then((response) => { - dispatch(loginUserSuccess(response.data)); + dispatch(authenticateUser(response.data)); browserHistory.push('/'); resolve(); }) @@ -339,10 +329,7 @@ export function unlinkService(service) { apiClient .delete(`/auth/${service}`) .then((response) => { - dispatch({ - type: ActionTypes.AUTH_USER, - user: response.data - }); + dispatch(authenticateUser(response.data)); }) .catch((error) => { const { response } = error; @@ -351,3 +338,11 @@ export function unlinkService(service) { }); }; } + +export function setUserCookieConsent(cookieConsent) { + // maybe also send this to the server rn? + return { + type: ActionTypes.SET_COOKIE_CONSENT, + cookieConsent + }; +} diff --git a/client/modules/User/components/CookieConsent.jsx b/client/modules/User/components/CookieConsent.jsx new file mode 100644 index 0000000000..0144a8e48c --- /dev/null +++ b/client/modules/User/components/CookieConsent.jsx @@ -0,0 +1,140 @@ +import React, { useState, useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import Cookies from 'js-cookie'; +import styled from 'styled-components'; +import getConfig from '../../../utils/getConfig'; +import { setUserCookieConsent } from '../actions'; +import { remSize, prop } from '../../../theme'; +import Button from '../../../common/Button'; + +const CookieConsentContainer = styled.div` + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: 9999; +`; + +const CookieConsentDialog = styled.div` + width: 100%; + height: 100%; + background: ${prop('Modal.background')}; + border-top: 1px solid ${prop('Separator')}; + padding: ${remSize(40)} ${remSize(60)}; +`; + +const CookieConsentHeader = styled.h2` + margin-bottom: ${remSize(20)}; +`; + +const CookieConsentContent = styled.div` + display: flex; + justify-content: space-between; +`; + +const CookieConsentCopy = styled.p``; + +const CookieConsentButtons = styled.div` + display: flex; + align-items: center; + margin-left: ${remSize(60)}; + & button:not(:last-child) { + margin-right: ${remSize(20)}; + } +`; + +function CookieConsent() { + const user = useSelector((state) => state.user); + const [cookieConsent, setBrowserCookieConsent] = useState('none'); + const dispatch = useDispatch(); + + function initializeCookieConsent() { + if (user.authenticated) { + setBrowserCookieConsent(user.cookieConsent); + Cookies.set('p5-cookie-consent', user.cookieConsent, { expires: 365 }); + return; + } + setBrowserCookieConsent('none'); + Cookies.set('p5-cookie-consent', 'none', { expires: 365 }); + } + + function acceptAllCookies() { + if (user.authenticated) { + dispatch(setUserCookieConsent('all')); + return; + } + setBrowserCookieConsent('all'); + Cookies.set('p5-cookie-consent', 'all', { expires: 365 }); + } + + function acceptEssentialCookies() { + if (user.authenticated) { + dispatch(setUserCookieConsent('essential')); + return; + } + setBrowserCookieConsent('essential'); + Cookies.set('p5-cookie-consent', 'essential', { expires: 365 }); + } + + function mergeCookieConsent() { + if (user.authenticated) { + if (user.cookieConsent === 'none' && cookieConsent !== 'none') { + dispatch(setUserCookieConsent(cookieConsent)); + } else if (user.cookieConsent !== 'none') { + setBrowserCookieConsent(user.cookieConsent); + Cookies.set('p5-cookie-consent', user.cookieConsent, { expires: 365 }); + } + } + } + + useEffect(() => { + const p5CookieConsent = Cookies.get('p5-cookie-consent'); + if (p5CookieConsent) { + setBrowserCookieConsent(p5CookieConsent); + } else { + initializeCookieConsent(); + } + }, []); + + useEffect(() => { + mergeCookieConsent(); + }, [user.authenticated]); + + // Turn off Google Analytics + useEffect(() => { + if (cookieConsent === 'essential' || user.cookieConsent === 'essential') { + window[`ga-disable-${getConfig('GA_MEASUREMENT_ID')}`] = true; + } + }, [cookieConsent, user.cookieConsent]); + + const showCookieConsent = + (user.authenticated && user.cookieConsent === 'none') || + (!user.authenticated && cookieConsent === 'none'); + + if (!showCookieConsent) return null; + + return ( + + + {/* */} + Cookies + + + The p5.js Editor uses cookies. Some are essential to the website + functionality and allow you to manage an account and preferences. + Others are used for analytics allow us to gather information and + make improvements. You can decide which cookies you would like to + allow. + + + + + + + + + ); +} +// TODO need to merge browser cookie with user when u login + +export default CookieConsent; diff --git a/client/modules/User/reducers.js b/client/modules/User/reducers.js index 87953d7810..2832190b28 100644 --- a/client/modules/User/reducers.js +++ b/client/modules/User/reducers.js @@ -41,6 +41,8 @@ const user = (state = { authenticated: false }, action) => { return { ...state, ...action.user }; case ActionTypes.API_KEY_CREATED: return { ...state, ...action.user }; + case ActionTypes.SET_COOKIE_CONSENT: + return { ...state, cookieConsent: action.cookieConsent }; default: return state; } diff --git a/package-lock.json b/package-lock.json index 007c2f504b..baa4161113 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26613,6 +26613,11 @@ } } }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", @@ -33772,27 +33777,10 @@ } }, "prismjs": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz", - "integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==", - "dev": true, - "requires": { - "clipboard": "^2.0.0" - }, - "dependencies": { - "clipboard": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz", - "integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==", - "dev": true, - "optional": true, - "requires": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - } - } + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.24.1.tgz", + "integrity": "sha512-mNPsedLuk90RVJioIky8ANZEwYm5w9LcvCXrxHlwf4fNVSn8jEipMybMkWUyyF0JhnC+C4VcOVSBuHRKs1L5Ow==", + "dev": true }, "private": { "version": "0.1.8", diff --git a/package.json b/package.json index 210164bd6c..b72f5c4016 100644 --- a/package.json +++ b/package.json @@ -179,6 +179,7 @@ "i18next-http-backend": "^1.0.21", "is-url": "^1.2.4", "jest-express": "^1.11.0", + "js-cookie": "^2.2.1", "jsdom": "^9.8.3", "jshint": "^2.11.0", "lodash": "^4.17.21", diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js index 19d5b6a823..9310876d9d 100644 --- a/server/controllers/user.controller.js +++ b/server/controllers/user.controller.js @@ -17,7 +17,8 @@ export function userResponse(user) { id: user._id, totalSize: user.totalSize, github: user.github, - google: user.google + google: user.google, + cookieConsent: user.cookieConsent }; } diff --git a/server/models/user.js b/server/models/user.js index 1ff4132b60..0ffe79c6c5 100644 --- a/server/models/user.js +++ b/server/models/user.js @@ -76,7 +76,12 @@ const userSchema = new Schema( language: { type: String, default: 'en-US' }, autocloseBracketsQuotes: { type: Boolean, default: true } }, - totalSize: { type: Number, default: 0 } + totalSize: { type: Number, default: 0 }, + cookieConsent: { + type: String, + enum: ['none', 'essential', 'all'], + default: 'none' + } }, { timestamps: true, usePushEach: true } ); diff --git a/server/views/index.js b/server/views/index.js index f7e5b4b229..29cc25771e 100644 --- a/server/views/index.js +++ b/server/views/index.js @@ -35,6 +35,7 @@ export function renderIndex() { window.process.env.MOBILE_ENABLED = ${process.env.MOBILE_ENABLED ? `${process.env.MOBILE_ENABLED}` : undefined}; window.process.env.TRANSLATIONS_ENABLED = ${process.env.TRANSLATIONS_ENABLED === 'true' ? true : false}; window.process.env.PREVIEW_URL = '${process.env.PREVIEW_URL}'; + window.process.env.GA_MEASUREMENT_ID='${process.env.GA_MEASUREMENT_ID}'; @@ -42,14 +43,15 @@ export function renderIndex() {
From 0b81d4f7a80f6d65bc55136c5f23910abfb6924a Mon Sep 17 00:00:00 2001 From: Cassie Tarakajian Date: Tue, 3 Aug 2021 18:38:56 -0400 Subject: [PATCH 02/24] Update Button component to have primary and secondary styles --- client/common/Button.jsx | 94 ++++++--- client/common/Button.stories.jsx | 4 +- client/components/mobile/IconButton.jsx | 2 +- .../modules/User/components/CookieConsent.jsx | 4 +- client/theme.js | 180 ++++++++++++------ package-lock.json | 107 +++++------ 6 files changed, 240 insertions(+), 151 deletions(-) diff --git a/client/common/Button.jsx b/client/common/Button.jsx index 3009ab338b..852ed86068 100644 --- a/client/common/Button.jsx +++ b/client/common/Button.jsx @@ -6,8 +6,12 @@ import { Link } from 'react-router'; import { remSize, prop } from '../theme'; const kinds = { + primary: 'primary', + secondary: 'secondary' +}; + +const displays = { block: 'block', - icon: 'icon', inline: 'inline' }; @@ -23,45 +27,49 @@ const StyledButton = styled.button` width: max-content; text-decoration: none; - color: ${prop('Button.default.foreground')}; - background-color: ${prop('Button.default.background')}; + color: ${({ kind }) => prop(`Button.${kind}.default.foreground`)}; + background-color: ${({ kind }) => + prop(`Button.${kind}.default.background`)}; cursor: pointer; - border: 2px solid ${prop('Button.default.border')}; + border: 2px solid ${({ kind }) => prop(`Button.${kind}.default.border`)}; border-radius: 2px; padding: ${remSize(8)} ${remSize(25)}; line-height: 1; svg * { - fill: ${prop('Button.default.foreground')}; + fill: ${({ kind }) => prop(`Button.${kind}.default.foreground`)}; } &:hover:not(:disabled) { - color: ${prop('Button.hover.foreground')}; - background-color: ${prop('Button.hover.background')}; - border-color: ${prop('Button.hover.border')}; + color: ${({ kind }) => prop(`Button.${kind}.hover.foreground`)}; + background-color: ${({ kind }) => + prop(`Button.${kind}.hover.background`)}; + border-color: ${({ kind }) => prop(`Button.${kind}.hover.border`)}; svg * { - fill: ${prop('Button.hover.foreground')}; + fill: ${({ kind }) => prop(`Button.${kind}.hover.foreground`)}; } } &:active:not(:disabled) { - color: ${prop('Button.active.foreground')}; - background-color: ${prop('Button.active.background')}; + color: ${({ kind }) => prop(`Button.${kind}.active.foreground`)}; + background-color: ${({ kind }) => + prop(`Button.${kind}.active.background`)}; svg * { - fill: ${prop('Button.active.foreground')}; + fill: ${({ kind }) => prop(`Button.${kind}.active.foreground`)}; } } &:disabled { - color: ${prop('Button.disabled.foreground')}; - background-color: ${prop('Button.disabled.background')}; - border-color: ${prop('Button.disabled.border')}; + color: ${({ kind }) => prop(`Button.${kind}.disabled.foreground`)}; + background-color: ${({ kind }) => + prop(`Button.${kind}.disabled.background`)}; + border-color: ${({ kind }) => prop(`Button.${kind}.disabled.border`)}; cursor: not-allowed; svg * { - fill: ${prop('Button.disabled.foreground')}; + fill: ${({ kind }) => prop(`Button.${kind}.disabled.foreground`)}; } } @@ -108,8 +116,8 @@ const StyledIconButton = styled.button` height: ${remSize(32)}px; text-decoration: none; - color: ${prop('Button.default.foreground')}; - background-color: ${prop('Button.hover.background')}; + color: ${({ kind }) => prop(`Button.${kind}.default.foreground`)}; + background-color: ${({ kind }) => prop(`Button.${kind}.hover.background`)}; cursor: pointer; border: 1px solid transparent; border-radius: 50%; @@ -117,26 +125,29 @@ const StyledIconButton = styled.button` line-height: 1; &:hover:not(:disabled) { - color: ${prop('Button.hover.foreground')}; - background-color: ${prop('Button.hover.background')}; + color: ${({ kind }) => prop(`Button.${kind}.hover.foreground`)}; + background-color: ${({ kind }) => + prop(`Button.${kind}.hover.background`)}; svg * { - fill: ${prop('Button.hover.foreground')}; + fill: ${({ kind }) => prop(`Button.${kind}.hover.foreground`)}; } } &:active:not(:disabled) { - color: ${prop('Button.active.foreground')}; - background-color: ${prop('Button.active.background')}; + color: ${({ kind }) => prop(`Button.${kind}.active.foreground`)}; + background-color: ${({ kind }) => + prop(`Button.${kind}.active.background`)}; svg * { - fill: ${prop('Button.active.foreground')}; + fill: ${({ kind }) => prop(`Button.${kind}.active.foreground`)}; } } &:disabled { - color: ${prop('Button.disabled.foreground')}; - background-color: ${prop('Button.disabled.background')}; + color: ${({ kind }) => prop(`Button.${kind}.disabled.foreground`)}; + background-color: ${({ kind }) => + prop(`Button.${kind}.disabled.background`)}; cursor: not-allowed; } @@ -151,10 +162,12 @@ const StyledIconButton = styled.button` */ const Button = ({ children, + display, href, kind, iconBefore, iconAfter, + iconOnly, 'aria-label': ariaLabel, to, type, @@ -170,9 +183,11 @@ const Button = ({ ); let StyledComponent = StyledButton; - if (kind === kinds.inline) { + if (display === displays.inline) { StyledComponent = StyledInlineButton; - } else if (kind === kinds.icon) { + } + + if (iconOnly) { StyledComponent = StyledIconButton; } @@ -180,6 +195,7 @@ const Button = ({ return ( + {content} ); @@ -214,9 +237,11 @@ const Button = ({ Button.defaultProps = { children: null, disabled: false, + display: displays.block, iconAfter: null, iconBefore: null, - kind: kinds.block, + iconOnly: false, + kind: kinds.primary, href: null, 'aria-label': null, to: null, @@ -224,6 +249,7 @@ Button.defaultProps = { }; Button.kinds = kinds; +Button.displays = displays; Button.propTypes = { /** @@ -235,6 +261,10 @@ Button.propTypes = { If the button can be activated or not */ disabled: PropTypes.bool, + /** + * The display type of the button—inline or block + */ + display: PropTypes.string, /** * SVG icon to place after child content */ @@ -243,6 +273,10 @@ Button.propTypes = { * SVG icon to place before child content */ iconBefore: PropTypes.element, + /** + * If the button content is only an SVG icon + */ + iconOnly: PropTypes.bool, /** * The kind of button - determines how it appears visually */ diff --git a/client/common/Button.stories.jsx b/client/common/Button.stories.jsx index a583d8b46d..6ad1ddddb5 100644 --- a/client/common/Button.stories.jsx +++ b/client/common/Button.stories.jsx @@ -59,7 +59,7 @@ export const ButtonWithIconAfter = () => ( ); export const InlineButtonWithIconAfter = () => ( - ); @@ -68,6 +68,6 @@ export const InlineIconOnlyButton = () => ( + diff --git a/client/theme.js b/client/theme.js index f22f13adb4..f388ab7307 100644 --- a/client/theme.js +++ b/client/theme.js @@ -66,25 +66,49 @@ export default { backgroundColor: grays.lighter, Button: { - default: { - foreground: colors.black, - background: grays.light, - border: grays.middleLight + primary: { + default: { + foreground: colors.black, + background: grays.light, + border: grays.middleLight + }, + hover: { + foreground: grays.lightest, + background: colors.p5jsPink, + border: colors.p5jsPink + }, + active: { + foreground: grays.lightest, + background: colors.p5jsActivePink, + border: colors.p5jsActivePink + }, + disabled: { + foreground: colors.black, + background: grays.light, + border: grays.middleLight + } }, - hover: { - foreground: grays.lightest, - background: colors.p5jsPink, - border: colors.p5jsPink - }, - active: { - foreground: grays.lightest, - background: colors.p5jsActivePink, - border: colors.p5jsActivePink - }, - disabled: { - foreground: colors.black, - background: grays.light, - border: grays.middleLight + secondary: { + default: { + foreground: grays.lightest, + background: colors.p5jsPink, + border: colors.p5jsPink + }, + hover: { + foreground: grays.lightest, + background: colors.p5jsPink, + border: colors.p5jsPink + }, + active: { + foreground: grays.lightest, + background: colors.p5jsActivePink, + border: colors.p5jsActivePink + }, + disabled: { + foreground: colors.black, + background: grays.light, + border: grays.middleLight + } } }, Icon: { @@ -119,25 +143,49 @@ export default { backgroundColor: grays.darker, Button: { - default: { - foreground: grays.light, - background: grays.dark, - border: grays.middleDark - }, - hover: { - foreground: grays.lightest, - background: colors.p5jsPink, - border: colors.p5jsPink + primary: { + default: { + foreground: grays.light, + background: grays.dark, + border: grays.middleDark + }, + hover: { + foreground: grays.lightest, + background: colors.p5jsPink, + border: colors.p5jsPink + }, + active: { + foreground: grays.lightest, + background: colors.p5jsActivePink, + border: colors.p5jsActivePink + }, + disabled: { + foreground: grays.light, + background: grays.dark, + border: grays.middleDark + } }, - active: { - foreground: grays.lightest, - background: colors.p5jsActivePink, - border: colors.p5jsActivePink - }, - disabled: { - foreground: grays.light, - background: grays.dark, - border: grays.middleDark + secondary: { + default: { + foreground: grays.lightest, + background: colors.p5jsPink, + border: colors.p5jsPink + }, + hover: { + foreground: grays.lightest, + background: colors.p5jsPink, + border: colors.p5jsPink + }, + active: { + foreground: grays.lightest, + background: colors.p5jsActivePink, + border: colors.p5jsActivePink + }, + disabled: { + foreground: grays.light, + background: grays.dark, + border: grays.middleDark + } } }, Icon: { @@ -172,25 +220,49 @@ export default { backgroundColor: grays.darker, Button: { - default: { - foreground: grays.light, - background: grays.dark, - border: grays.middleDark - }, - hover: { - foreground: grays.dark, - background: colors.yellow, - border: colors.yellow - }, - active: { - foreground: grays.dark, - background: colors.p5jsActivePink, - border: colors.p5jsActivePink + primary: { + default: { + foreground: grays.light, + background: grays.dark, + border: grays.middleDark + }, + hover: { + foreground: grays.dark, + background: colors.yellow, + border: colors.yellow + }, + active: { + foreground: grays.dark, + background: colors.p5jsActivePink, + border: colors.p5jsActivePink + }, + disabled: { + foreground: grays.light, + background: grays.dark, + border: grays.middleDark + } }, - disabled: { - foreground: grays.light, - background: grays.dark, - border: grays.middleDark + secondary: { + default: { + foreground: grays.dark, + background: colors.yellow, + border: colors.yellow + }, + hover: { + foreground: grays.dark, + background: colors.yellow, + border: colors.yellow + }, + active: { + foreground: grays.dark, + background: colors.p5jsActivePink, + border: colors.p5jsActivePink + }, + disabled: { + foreground: grays.light, + background: grays.dark, + border: grays.middleDark + } } }, Icon: { diff --git a/package-lock.json b/package-lock.json index baa4161113..8a49904862 100644 --- a/package-lock.json +++ b/package-lock.json @@ -136,14 +136,6 @@ "electron-to-chromium": "^1.3.723", "escalade": "^3.1.1", "node-releases": "^1.1.71" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001236", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz", - "integrity": "sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ==", - "dev": true - } } }, "colorette": { @@ -507,14 +499,6 @@ "electron-to-chromium": "^1.3.723", "escalade": "^3.1.1", "node-releases": "^1.1.71" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001236", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz", - "integrity": "sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ==", - "dev": true - } } }, "colorette": { @@ -3136,14 +3120,6 @@ "electron-to-chromium": "^1.3.723", "escalade": "^3.1.1", "node-releases": "^1.1.71" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001236", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz", - "integrity": "sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ==", - "dev": true - } } }, "colorette": { @@ -6799,14 +6775,6 @@ "electron-to-chromium": "^1.3.723", "escalade": "^3.1.1", "node-releases": "^1.1.71" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001236", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz", - "integrity": "sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ==", - "dev": true - } } }, "cacache": { @@ -7566,7 +7534,8 @@ }, "ssri": { "version": "7.1.0", - "resolved": "", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", + "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", "dev": true, "requires": { "figgy-pudding": "^3.5.1", @@ -9694,7 +9663,8 @@ }, "browserslist": { "version": "4.16.1", - "resolved": "", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz", + "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==", "dev": true, "requires": { "caniuse-lite": "^1.0.30001173", @@ -12863,7 +12833,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "" + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -13235,12 +13206,6 @@ "node-releases": "^1.1.71" }, "dependencies": { - "caniuse-lite": { - "version": "1.0.30001236", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz", - "integrity": "sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ==", - "dev": true - }, "colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", @@ -13522,9 +13487,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001180", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001180.tgz", - "integrity": "sha512-n8JVqXuZMVSPKiPiypjFtDTXc4jWIdjxull0f92WLo7e1MSi3uJ3NvveakSh/aCl1QKFAvIz3vIj0v+0K+FrXw==", + "version": "1.0.30001248", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001248.tgz", + "integrity": "sha512-NwlQbJkxUFJ8nMErnGtT0QTM2TJ33xgz4KXJSMIrjXIbDVdaYueGyjOrLKRtJC+rTiWfi6j5cnZN1NBiSBJGNw==", "dev": true }, "capture-exit": { @@ -14617,14 +14582,6 @@ "electron-to-chromium": "^1.3.723", "escalade": "^3.1.1", "node-releases": "^1.1.71" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001236", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz", - "integrity": "sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ==", - "dev": true - } } }, "colorette": { @@ -19578,7 +19535,8 @@ }, "ini": { "version": "1.3.5", - "resolved": "", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, "is-fullwidth-code-point": { @@ -27282,6 +27240,12 @@ "package-json": "^6.3.0" } }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + }, "lazy-universal-dotenv": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz", @@ -28491,7 +28455,8 @@ }, "merge-deep": { "version": "3.0.2", - "resolved": "", + "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz", + "integrity": "sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA==", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -28508,6 +28473,7 @@ "for-own": "^0.1.3", "is-plain-object": "^2.0.1", "kind-of": "^3.0.2", + "lazy-cache": "^1.0.3", "shallow-clone": "^0.1.2" } }, @@ -28519,7 +28485,8 @@ "requires": { "is-extendable": "^0.1.1", "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3" + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" }, "dependencies": { "kind-of": { @@ -28863,6 +28830,24 @@ } } }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true + } + } + }, "mjml": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/mjml/-/mjml-3.3.5.tgz", @@ -33327,12 +33312,6 @@ "node-releases": "^1.1.71" }, "dependencies": { - "caniuse-lite": { - "version": "1.0.30001236", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz", - "integrity": "sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ==", - "dev": true - }, "colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", @@ -37632,7 +37611,8 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "" + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -42202,7 +42182,8 @@ }, "ws": { "version": "7.3.0", - "resolved": "", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", + "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==", "dev": true }, "xdg-basedir": { From 0590562d629b55b7a7943bf8f65aed18de736abf Mon Sep 17 00:00:00 2001 From: Cassie Tarakajian Date: Mon, 9 Aug 2021 18:35:58 -0400 Subject: [PATCH 03/24] Handle Google analytics --- .../modules/User/components/CookieConsent.jsx | 28 ++++++-- package-lock.json | 72 ++++++------------- package.json | 1 + server/views/index.js | 11 --- 4 files changed, 44 insertions(+), 68 deletions(-) diff --git a/client/modules/User/components/CookieConsent.jsx b/client/modules/User/components/CookieConsent.jsx index a89ac0ea0c..f9aec08116 100644 --- a/client/modules/User/components/CookieConsent.jsx +++ b/client/modules/User/components/CookieConsent.jsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import Cookies from 'js-cookie'; import styled from 'styled-components'; +import ReactGA from 'react-ga'; import getConfig from '../../../utils/getConfig'; import { setUserCookieConsent } from '../actions'; import { remSize, prop } from '../../../theme'; @@ -61,7 +62,6 @@ function CookieConsent() { function acceptAllCookies() { if (user.authenticated) { dispatch(setUserCookieConsent('all')); - return; } setBrowserCookieConsent('all'); Cookies.set('p5-cookie-consent', 'all', { expires: 365 }); @@ -70,10 +70,12 @@ function CookieConsent() { function acceptEssentialCookies() { if (user.authenticated) { dispatch(setUserCookieConsent('essential')); - return; } setBrowserCookieConsent('essential'); Cookies.set('p5-cookie-consent', 'essential', { expires: 365 }); + Cookies.remove('_ga'); + Cookies.remove('_gat'); + Cookies.remove('_gid'); } function mergeCookieConsent() { @@ -94,6 +96,17 @@ function CookieConsent() { } else { initializeCookieConsent(); } + + if (p5CookieConsent === 'essential') { + ReactGA.initialize(getConfig('GA_MEASUREMENT_ID'), { + gaOptions: { + storage: 'none' + } + }); + } else { + ReactGA.initialize(getConfig('GA_MEASUREMENT_ID')); + } + ReactGA.pageview(window.location.pathname + window.location.search); }, []); useEffect(() => { @@ -101,11 +114,12 @@ function CookieConsent() { }, [user.authenticated]); // Turn off Google Analytics - useEffect(() => { - if (cookieConsent === 'essential' || user.cookieConsent === 'essential') { - window[`ga-disable-${getConfig('GA_MEASUREMENT_ID')}`] = true; - } - }, [cookieConsent, user.cookieConsent]); + // useEffect(() => { + // if (cookieConsent === 'all' || user.cookieConsent === 'all') { + // ReactGA.initialize(getConfig('GA_MEASUREMENT_ID')); + // ReactGA.pageview(window.location.pathname + window.location.search); + // } + // }, [cookieConsent, user.cookieConsent]); const showCookieConsent = (user.authenticated && user.cookieConsent === 'none') || diff --git a/package-lock.json b/package-lock.json index 8a49904862..029f4b56ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7534,8 +7534,7 @@ }, "ssri": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", - "integrity": "sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g==", + "resolved": "", "dev": true, "requires": { "figgy-pudding": "^3.5.1", @@ -9663,8 +9662,7 @@ }, "browserslist": { "version": "4.16.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz", - "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==", + "resolved": "", "dev": true, "requires": { "caniuse-lite": "^1.0.30001173", @@ -12833,8 +12831,7 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "resolved": "" } } }, @@ -14529,9 +14526,9 @@ } }, "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.6.tgz", + "integrity": "sha512-oaWyu5dQbHaYcyZCTfyPpC+VmI62/OM2RTUYavTk1MDr1cwW5Boi3baeYQKiZbY2uSQJGr+iMOzb/JFxLrft+g==", "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -19535,8 +19532,7 @@ }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "resolved": "", "optional": true }, "is-fullwidth-code-point": { @@ -27240,12 +27236,6 @@ "package-json": "^6.3.0" } }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true - }, "lazy-universal-dotenv": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz", @@ -28455,8 +28445,7 @@ }, "merge-deep": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz", - "integrity": "sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA==", + "resolved": "", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -28473,7 +28462,6 @@ "for-own": "^0.1.3", "is-plain-object": "^2.0.1", "kind-of": "^3.0.2", - "lazy-cache": "^1.0.3", "shallow-clone": "^0.1.2" } }, @@ -28485,8 +28473,7 @@ "requires": { "is-extendable": "^0.1.1", "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3", - "mixin-object": "^2.0.1" + "lazy-cache": "^0.2.3" }, "dependencies": { "kind-of": { @@ -28830,24 +28817,6 @@ } } }, - "mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", - "dev": true, - "requires": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "dependencies": { - "for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", - "dev": true - } - } - }, "mjml": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/mjml/-/mjml-3.3.5.tgz", @@ -34675,6 +34644,11 @@ "use-sidecar": "^1.0.1" } }, + "react-ga": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/react-ga/-/react-ga-3.3.0.tgz", + "integrity": "sha512-o8RScHj6Lb8cwy3GMrVH6NJvL+y0zpJvKtc0+wmH7Bt23rszJmnqEQxRbyrqUzk9DTJIHoP42bfO5rswC9SWBQ==" + }, "react-helmet": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-5.2.1.tgz", @@ -37611,8 +37585,7 @@ }, "kind-of": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "resolved": "" } } }, @@ -38800,9 +38773,9 @@ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.6.tgz", + "integrity": "sha512-oaWyu5dQbHaYcyZCTfyPpC+VmI62/OM2RTUYavTk1MDr1cwW5Boi3baeYQKiZbY2uSQJGr+iMOzb/JFxLrft+g==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -39246,9 +39219,9 @@ } }, "tar": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", - "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.6.tgz", + "integrity": "sha512-oaWyu5dQbHaYcyZCTfyPpC+VmI62/OM2RTUYavTk1MDr1cwW5Boi3baeYQKiZbY2uSQJGr+iMOzb/JFxLrft+g==", "dev": true, "requires": { "chownr": "^2.0.0", @@ -42182,8 +42155,7 @@ }, "ws": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", - "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==", + "resolved": "", "dev": true }, "xdg-basedir": { diff --git a/package.json b/package.json index b72f5c4016..8ec49f2e9d 100644 --- a/package.json +++ b/package.json @@ -206,6 +206,7 @@ "react": "^16.12.0", "react-dom": "^16.12.0", "react-final-form": "^6.5.2", + "react-ga": "^3.3.0", "react-helmet": "^5.1.3", "react-hot-loader": "^4.12.19", "react-i18next": "^11.5.0", diff --git a/server/views/index.js b/server/views/index.js index 29cc25771e..2957f9d62b 100644 --- a/server/views/index.js +++ b/server/views/index.js @@ -42,17 +42,6 @@ export function renderIndex() {
- `; From 388a3afd851c311e5ce7c840ab9f8ddd6566ec83 Mon Sep 17 00:00:00 2001 From: Cassie Tarakajian Date: Wed, 11 Aug 2021 17:37:57 -0400 Subject: [PATCH 04/24] Save cookieConsent server-side, add animation --- client/modules/User/actions.js | 17 +- .../modules/User/components/CookieConsent.jsx | 82 ++++---- package-lock.json | 179 +++++++++--------- package.json | 3 +- server/controllers/user.controller.js | 17 ++ server/routes/user.routes.js | 6 + 6 files changed, 174 insertions(+), 130 deletions(-) diff --git a/client/modules/User/actions.js b/client/modules/User/actions.js index 4ebfab7890..c329713309 100644 --- a/client/modules/User/actions.js +++ b/client/modules/User/actions.js @@ -341,8 +341,19 @@ export function unlinkService(service) { export function setUserCookieConsent(cookieConsent) { // maybe also send this to the server rn? - return { - type: ActionTypes.SET_COOKIE_CONSENT, - cookieConsent + return (dispatch) => { + apiClient + .put('/cookie-consent', { cookieConsent }) + .then(() => { + dispatch({ + type: ActionTypes.SET_COOKIE_CONSENT, + cookieConsent + }); + }) + .catch((error) => { + const { response } = error; + const message = response.message || response.data.error; + dispatch(authError(message)); + }); }; } diff --git a/client/modules/User/components/CookieConsent.jsx b/client/modules/User/components/CookieConsent.jsx index f9aec08116..42b15d4cd1 100644 --- a/client/modules/User/components/CookieConsent.jsx +++ b/client/modules/User/components/CookieConsent.jsx @@ -3,6 +3,7 @@ import { useSelector, useDispatch } from 'react-redux'; import Cookies from 'js-cookie'; import styled from 'styled-components'; import ReactGA from 'react-ga'; +import { Transition } from 'react-transition-group'; import getConfig from '../../../utils/getConfig'; import { setUserCookieConsent } from '../actions'; import { remSize, prop } from '../../../theme'; @@ -10,7 +11,13 @@ import Button from '../../../common/Button'; const CookieConsentContainer = styled.div` position: fixed; - bottom: 0; + transition: 1.6s cubic-bezier(0.165, 0.84, 0.44, 1); + bottom: ${({ state }) => { + if (state === 'entered') { + return '0'; + } + return remSize(-200); + }}; left: 0; right: 0; z-index: 9999; @@ -47,6 +54,7 @@ const CookieConsentButtons = styled.div` function CookieConsent() { const user = useSelector((state) => state.user); const [cookieConsent, setBrowserCookieConsent] = useState('none'); + const [inProp, setInProp] = useState(false); const dispatch = useDispatch(); function initializeCookieConsent() { @@ -73,6 +81,7 @@ function CookieConsent() { } setBrowserCookieConsent('essential'); Cookies.set('p5-cookie-consent', 'essential', { expires: 365 }); + // Remove Google Analytics Cookies Cookies.remove('_ga'); Cookies.remove('_gat'); Cookies.remove('_gid'); @@ -113,42 +122,45 @@ function CookieConsent() { mergeCookieConsent(); }, [user.authenticated]); - // Turn off Google Analytics - // useEffect(() => { - // if (cookieConsent === 'all' || user.cookieConsent === 'all') { - // ReactGA.initialize(getConfig('GA_MEASUREMENT_ID')); - // ReactGA.pageview(window.location.pathname + window.location.search); - // } - // }, [cookieConsent, user.cookieConsent]); - - const showCookieConsent = - (user.authenticated && user.cookieConsent === 'none') || - (!user.authenticated && cookieConsent === 'none'); - - if (!showCookieConsent) return null; + useEffect(() => { + if (cookieConsent !== 'none') { + setInProp(false); + } else { + setInProp(true); + } + }, [cookieConsent]); return ( - - - {/* */} - Cookies - - - The p5.js Editor uses cookies. Some are essential to the website - functionality and allow you to manage an account and preferences. - Others are used for analytics allow us to gather information and - make improvements. You can decide which cookies you would like to - allow. - - - - - - - - + + {(state) => ( + + + {/* */} + Cookies + + + The p5.js Editor uses cookies. Some are essential to the website + functionality and allow you to manage an account and + preferences. Others are used for analytics allow us to gather + information and make improvements. You can decide which cookies + you would like to allow. + + + + + + + + + )} + ); } // TODO need to merge browser cookie with user when u login diff --git a/package-lock.json b/package-lock.json index 029f4b56ed..e1210cec0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13923,7 +13923,8 @@ "colors": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz", - "integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ==" + "integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ==", + "dev": true }, "combined-stream": { "version": "1.0.8", @@ -16150,29 +16151,31 @@ } }, "dom-helpers": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.4.tgz", - "integrity": "sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==", - "dev": true, + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", "requires": { "@babel/runtime": "^7.8.7", - "csstype": "^2.6.7" + "csstype": "^3.0.2" }, "dependencies": { "@babel/runtime": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz", - "integrity": "sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==", - "dev": true, + "version": "7.14.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz", + "integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==", "requires": { "regenerator-runtime": "^0.13.4" } }, + "csstype": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" + }, "regenerator-runtime": { - "version": "0.13.5", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", - "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==", - "dev": true + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" } } }, @@ -20822,45 +20825,64 @@ } }, "htmlhint": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/htmlhint/-/htmlhint-0.10.3.tgz", - "integrity": "sha512-LZZrDZRl1u6aYacpEl10K0wGKSQMboCNBWMgsV2eR4sxYD8jbG+FVBZqp3eo7tTwxZOdc9Cmjh3nQ4Nf4G37gQ==", - "requires": { - "async": "2.6.1", - "colors": "1.3.2", - "commander": "2.17.1", - "csslint": "^1.0.5", - "glob": "7.1.3", - "jshint": "^2.9.6", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/htmlhint/-/htmlhint-0.15.1.tgz", + "integrity": "sha512-uNbgqqBiD2ko4QQOYAHTPwDMluc9X81NwzlrJN7yExCoM6dHNgRFjVI+4TEdRrF/EqUzl1dpMUn7GYbu/qCKmA==", + "requires": { + "async": "3.2.0", + "chalk": "4.1.0", + "commander": "5.1.0", + "glob": "7.1.6", "parse-glob": "3.0.4", - "path-parse": "1.0.6", - "request": "2.88.0", - "strip-json-comments": "2.0.1", + "request": "2.88.2", + "strip-json-comments": "3.1.0", "xml": "1.0.1" }, "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "requires": { - "lodash": "^4.17.10" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "csslint": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/csslint/-/csslint-1.0.5.tgz", - "integrity": "sha1-Gcw+2jIhYP0/cjKvHLKjYOiYouk=", - "optional": true, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { - "clone": "~2.1.0", - "parserlib": "~1.1.1" + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -20870,48 +20892,23 @@ "path-is-absolute": "^1.0.0" } }, - "parserlib": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parserlib/-/parserlib-1.1.1.tgz", - "integrity": "sha1-pkz6ckBiQ0/fw1HJpOwtkrlMBvQ=", - "optional": true + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "strip-json-comments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", + "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==" }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" } } }, @@ -31711,9 +31708,9 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-proxy": { "version": "1.0.0", @@ -35008,10 +35005,9 @@ } }, "react-transition-group": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", - "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", - "dev": true, + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", "requires": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -38315,7 +38311,8 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true }, "style-loader": { "version": "2.0.0", @@ -40106,9 +40103,9 @@ } }, "url-parse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", - "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", + "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", "dev": true, "requires": { "querystringify": "^2.1.1", diff --git a/package.json b/package.json index 8ec49f2e9d..f877b6f49f 100644 --- a/package.json +++ b/package.json @@ -174,7 +174,7 @@ "express-session": "^1.17.0", "final-form": "^4.20.1", "friendly-words": "^1.1.10", - "htmlhint": "^0.10.1", + "htmlhint": "^0.15.1", "i18next": "^19.4.5", "i18next-http-backend": "^1.0.21", "is-url": "^1.2.4", @@ -215,6 +215,7 @@ "react-router": "^3.2.5", "react-split-pane": "^0.1.89", "react-tabs": "^2.3.1", + "react-transition-group": "^4.4.2", "redux": "^3.7.2", "redux-auth-wrapper": "^2.1.0", "redux-devtools": "^3.4.2", diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js index 9310876d9d..bc3e179662 100644 --- a/server/controllers/user.controller.js +++ b/server/controllers/user.controller.js @@ -413,3 +413,20 @@ export function unlinkGoogle(req, res) { message: 'You must be logged in to complete this action.' }); } + +export function updateCookieConsent(req, res) { + User.findById(req.user.id, (err, user) => { + if (err) { + res.status(500).json({ error: err }); + return; + } + if (!user) { + res.status(404).json({ error: 'Document not found' }); + return; + } + + const { cookieConsent } = req.body; + user.cookieConsent = cookieConsent; + saveUser(res, user); + }); +} diff --git a/server/routes/user.routes.js b/server/routes/user.routes.js index a52facf963..a507c328bd 100644 --- a/server/routes/user.routes.js +++ b/server/routes/user.routes.js @@ -18,6 +18,12 @@ router.post('/reset-password/:token', UserController.updatePassword); router.put('/account', isAuthenticated, UserController.updateSettings); +router.put( + '/cookie-consent', + isAuthenticated, + UserController.updateCookieConsent +); + router.post('/account/api-keys', isAuthenticated, UserController.createApiKey); router.delete( From 9cbe79d6818ad5689507cddc5140335e21a0b5c3 Mon Sep 17 00:00:00 2001 From: Cassie Tarakajian Date: Thu, 19 Aug 2021 18:24:15 -0400 Subject: [PATCH 05/24] Add Privacy Policy page --- client/modules/IDE/pages/PrivacyPolicy.jsx | 62 ++ client/modules/IDE/pages/TermsOfUse.jsx | 0 client/routes.jsx | 2 + package-lock.json | 861 ++++++++++++++++++++- package.json | 2 + server/routes/server.routes.js | 4 + server/server.js | 1 + server/views/index.js | 2 +- 8 files changed, 903 insertions(+), 31 deletions(-) create mode 100644 client/modules/IDE/pages/PrivacyPolicy.jsx create mode 100644 client/modules/IDE/pages/TermsOfUse.jsx diff --git a/client/modules/IDE/pages/PrivacyPolicy.jsx b/client/modules/IDE/pages/PrivacyPolicy.jsx new file mode 100644 index 0000000000..341df2cefe --- /dev/null +++ b/client/modules/IDE/pages/PrivacyPolicy.jsx @@ -0,0 +1,62 @@ +import React, { useEffect, useState } from 'react'; +import Helmet from 'react-helmet'; +import ReactMarkdown from 'react-markdown'; +import remarkSlug from 'remark-slug'; +import styled from 'styled-components'; +import axios from 'axios'; +import Nav from '../../../components/Nav'; +import { remSize } from '../../../theme'; + +const PrivacyPolicyContainer = styled.main` + max-width: ${remSize(700)}; + margin: 0 auto; + padding: ${remSize(10)}; + & p { + margin-bottom: ${remSize(10)}; + } + font-size: ${remSize(16)}; + & h1 { + font-size: 2em; + } + & h2 { + font-size: 1.5em; + margin-block-start: 0.83em; + margin-block-end: 0.83em; + } + & h3 { + font-size: 1.17em; + margin-block-start: 1em; + margin-block-end: 1em; + font-weight: bold; + } + & ul { + list-style: initial; + padding-inline-start: 40px; + margin-block-start: 1em; + margin-block-end: 1em; + } +`; + +function PrivacyPolicy() { + const [privacyPolicy, setPrivacyPolicy] = useState(''); + useEffect(() => { + axios.get('privacy-policy.md').then((response) => { + setPrivacyPolicy(response.data); + }); + }, []); + return ( + <> + + Privacy Policy + +