diff --git a/package.json b/package.json index 1275fd58c..c3a062fbf 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "quill-html-edit-button": "^2.2.12", "react": "18.2.0", "react-chartjs-2": "^5.2.0", + "react-cookie-consent": "^8.0.1", "react-dom": "18.2.0", "react-gtm-module": "2.0.11", "react-i18next": "^11.17.1", diff --git a/public/locales/bg/common.json b/public/locales/bg/common.json index 835c32a12..0075be69d 100644 --- a/public/locales/bg/common.json +++ b/public/locales/bg/common.json @@ -102,5 +102,8 @@ "read-more": "Прочетете още", "see-profile": "Вижте профил", "question": "Имате въпрос?" - } + }, + "cookieConsent": "Подкрепи.бг не използва бисквитки, освен тези от трети страни, нужни за аналитичните компоненти Google Analytics и HotJar. Приемането на бисквитките ще ни помогне да подобрим вашето потребителско преживяване", + "cookieConsentButton": "Приемам", + "cookieRejectButton": "Отхвърлям" } diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 76cd634eb..8faba94b3 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -99,5 +99,8 @@ "read-more": "Read more", "see-profile": "See profile", "question": "Have a question?" - } + }, + "cookieConsent": "Podkrepi.bg doesn't use cookies, except the third-party cookies required for the analytics components Google Analytics and HotJar. Accepting the cookies will help us improve your user experience.", + "cookieConsentButton": "Accept", + "cookieRejectButton": "Reject" } diff --git a/src/components/common/CookieConsentPopup.tsx b/src/components/common/CookieConsentPopup.tsx new file mode 100644 index 000000000..3e489b7b9 --- /dev/null +++ b/src/components/common/CookieConsentPopup.tsx @@ -0,0 +1,32 @@ +import CookieConsent from 'react-cookie-consent' +import { useTranslation } from 'react-i18next' + +type CookieConsentPopupProps = { + handleAcceptCookie: () => void + handleDeclineCookie: () => void +} + +const CookieConsentPopup = ({ + handleAcceptCookie, + handleDeclineCookie, +}: CookieConsentPopupProps) => { + const { t } = useTranslation() + + return ( + + {t('cookieConsent')} + + ) +} + +export default CookieConsentPopup diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 9a3e914ad..9dd1dc2a3 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,3 +1,4 @@ +import { useEffect, useState } from 'react' import { EmotionCache } from '@emotion/cache' import { CacheProvider } from '@emotion/react' import { CssBaseline } from '@mui/material' @@ -7,7 +8,7 @@ import { appWithTranslation, useTranslation } from 'next-i18next' import { AppProps } from 'next/app' import Head from 'next/head' import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' +import { getCookieConsentValue, Cookies } from 'react-cookie-consent' import createEmotionCache from 'common/createEmotionCache' import theme from 'common/theme' @@ -24,6 +25,7 @@ import { globalSnackbarProps, globalSnackbarContentProps, } from 'components/client/layout/NotificationSnackBar/props/global' +import CookieConsentPopup from 'components/common/CookieConsentPopup' // Client-side cache, shared for the whole session of the user in the browser. const clientSideEmotionCache = createEmotionCache() @@ -46,11 +48,24 @@ function CustomApp({ const { i18n } = useTranslation() const { initialize, trackEvent } = useGTM() - useEffect(() => { - // Init GTM + const handleAcceptCookie = () => { initialize({ events: { user_lang: i18n.language }, }) + } + + const handleDeclineCookie = () => { + Cookies.remove('_ga') + Cookies.remove('_gat') + Cookies.remove('_gid') + } + + useEffect(() => { + const isConsent = getCookieConsentValue() + // Init GTM + if (isConsent === 'true') { + handleAcceptCookie() + } }, []) // Register route change complete event handlers @@ -108,6 +123,10 @@ function CustomApp({ + ) } diff --git a/src/styles/global.scss b/src/styles/global.scss index cca0d355e..0e68a668d 100644 --- a/src/styles/global.scss +++ b/src/styles/global.scss @@ -66,3 +66,36 @@ ul { .ql-bubble .ql-video { margin-inline: auto; } + +.consent_container { + border: 1px solid black; + background-color: white !important; +} + +.consent_content { + display: flex; + align-items: center; + justify-content: center; + color: black; +} + +.consent_button-wrapper { + width: 100%; + display: flex; + justify-content: space-between; + padding: 0px 30px 0px 30px; +} + +.consent_button-accept { + background-color: white !important; + color: #32a9fe !important; + border: 1px solid #32a9fe !important; + border-radius: 5px !important; +} + +.consent_button-decline { + background-color: white !important; + color: #32a9fe !important; + border: 1px solid #32a9fe !important; + border-radius: 5px !important; +} diff --git a/yarn.lock b/yarn.lock index aa8bab762..42ac3d7f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8960,6 +8960,13 @@ __metadata: languageName: node linkType: hard +"js-cookie@npm:^2.2.1": + version: 2.2.1 + resolution: "js-cookie@npm:2.2.1" + checksum: 9b1fb980a1c5e624fd4b28ea4867bb30c71e04c4484bb3a42766344c533faa684de9498e443425479ec68609e96e27b60614bfe354877c449c631529b6d932f2 + languageName: node + linkType: hard + "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -11370,6 +11377,7 @@ __metadata: quill-html-edit-button: ^2.2.12 react: 18.2.0 react-chartjs-2: ^5.2.0 + react-cookie-consent: ^8.0.1 react-dom: 18.2.0 react-gtm-module: 2.0.11 react-i18next: ^11.17.1 @@ -11823,6 +11831,17 @@ __metadata: languageName: node linkType: hard +"react-cookie-consent@npm:^8.0.1": + version: 8.0.1 + resolution: "react-cookie-consent@npm:8.0.1" + dependencies: + js-cookie: ^2.2.1 + peerDependencies: + react: ">=16" + checksum: c99f3e40e3091c439956498158b5b8906cce170763836d6fade98a06ce667eca25aaf3bc407e10a6fb72fc44e5178a2ebf14cbbe4e1b5684a74b7d7f484bd359 + languageName: node + linkType: hard + "react-devtools-inline@npm:4.4.0": version: 4.4.0 resolution: "react-devtools-inline@npm:4.4.0"