From dcd32e32a4128e2dcb8c16394531780d2f233d0a Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 22 Jul 2022 17:04:53 -0500 Subject: [PATCH] Add configurable GDPR alert --- app/soapbox/containers/soapbox.tsx | 2 + app/soapbox/hooks/index.ts | 1 + app/soapbox/hooks/useGdpr.ts | 47 +++++++++++++++++++ .../normalizers/soapbox/soapbox_config.ts | 1 + 4 files changed, 51 insertions(+) create mode 100644 app/soapbox/hooks/useGdpr.ts diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index 26bd02488..cbfb87d4a 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -34,6 +34,7 @@ import { useSettings, useSystemTheme, useLocale, + useGdpr, } from 'soapbox/hooks'; import MESSAGES from 'soapbox/locales/messages'; import { useCachedLocationHandler } from 'soapbox/utils/redirect'; @@ -77,6 +78,7 @@ const loadInitial = () => { /** Highest level node with the Redux store. */ const SoapboxMount = () => { + useGdpr(); useCachedLocationHandler(); const me = useAppSelector(state => state.me); const instance = useAppSelector(state => state.instance); diff --git a/app/soapbox/hooks/index.ts b/app/soapbox/hooks/index.ts index a2489d6ef..270f44c84 100644 --- a/app/soapbox/hooks/index.ts +++ b/app/soapbox/hooks/index.ts @@ -3,6 +3,7 @@ export { useAppDispatch } from './useAppDispatch'; export { useAppSelector } from './useAppSelector'; export { useDimensions } from './useDimensions'; export { useFeatures } from './useFeatures'; +export { useGdpr } from './useGdpr'; export { useLocale } from './useLocale'; export { useOnScreen } from './useOnScreen'; export { useOwnAccount } from './useOwnAccount'; diff --git a/app/soapbox/hooks/useGdpr.ts b/app/soapbox/hooks/useGdpr.ts new file mode 100644 index 000000000..ea0c5435f --- /dev/null +++ b/app/soapbox/hooks/useGdpr.ts @@ -0,0 +1,47 @@ +import { useEffect, useRef } from 'react'; +import { useIntl, defineMessages } from 'react-intl'; + +import snackbar from 'soapbox/actions/snackbar'; + +import { useAppDispatch } from './useAppDispatch'; +import { useAppSelector } from './useAppSelector'; +import { useSoapboxConfig } from './useSoapboxConfig'; + +const hasGdpr = !!localStorage.getItem('soapbox:gdpr'); + +const messages = defineMessages({ + accept: { id: 'gdpr.accept', defaultMessage: 'Accept' }, + body: { id: 'gdpr.message', defaultMessage: '{siteTitle} uses session cookies, which are essential to the website\'s functioning.' }, +}); + +/** Displays a GDPR popup unless it has already been accepted. */ +const useGdpr = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + /** Track whether the snackbar has already been displayed once. */ + const triggered = useRef(hasGdpr); + + const soapbox = useSoapboxConfig(); + const isLoggedIn = useAppSelector(state => !!state.me); + const siteTitle = useAppSelector(state => state.instance.title); + + const handleAccept = () => { + localStorage.setItem('soapbox:gdpr', 'true'); + triggered.current = true; + }; + + useEffect(() => { + if (soapbox.gdpr && !isLoggedIn && !triggered.current) { + const message = intl.formatMessage(messages.body, { siteTitle }); + + dispatch(snackbar.show('info', message, { + action: handleAccept, + actionLabel: intl.formatMessage(messages.accept), + dismissAfter: false, + })); + } + }, [soapbox.gdpr, isLoggedIn]); +}; + +export { useGdpr }; diff --git a/app/soapbox/normalizers/soapbox/soapbox_config.ts b/app/soapbox/normalizers/soapbox/soapbox_config.ts index efb3b0044..7ed814013 100644 --- a/app/soapbox/normalizers/soapbox/soapbox_config.ts +++ b/app/soapbox/normalizers/soapbox/soapbox_config.ts @@ -89,6 +89,7 @@ export const SoapboxConfigRecord = ImmutableRecord({ customCss: ImmutableList(), defaultSettings: ImmutableMap(), extensions: ImmutableMap(), + gdpr: false, greentext: false, promoPanel: PromoPanelRecord(), navlinks: ImmutableMap({