Skip to content

Commit e6a7b95

Browse files
review: cookie consent banner (#65)
* feat: add analytics consent banner * fix: move analytics consent key to shared const file and remove unsused state --------- Co-authored-by: muhammedsirajudeen <[email protected]>
1 parent bd0b460 commit e6a7b95

File tree

7 files changed

+168
-14
lines changed

7 files changed

+168
-14
lines changed

frontend/public/locales/en/translation.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
"guestModeNotice": {
6666
"message": "You are currently offline.",
6767
"messageWithAction": "You are offline. Data may be lost. Log in to save your progress."
68+
},
69+
"analyticsConsent": {
70+
"title": "We use cookies",
71+
"description": "We use cookies to improve your experience and analyze site usage. Please accept or decline cookies to continue using FlashNotes.",
72+
"accept": "Accept",
73+
"decline": "Decline"
6874
}
6975
},
7076
"general": {

frontend/public/locales/es/translation.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
"guestModeNotice": {
6666
"message": "Actualmente estás sin conexión.",
6767
"messageWithAction": "Estás sin conexión. Los datos pueden perderse. Inicia sesión para guardar tu progreso."
68+
},
69+
"analyticsConsent": {
70+
"title": "Usamos cookies",
71+
"description": "Usamos cookies para mejorar tu experiencia y analizar el uso del sitio. Por favor, acepta o rechaza las cookies para continuar usando FlashNotes.",
72+
"accept": "Aceptar",
73+
"decline": "Rechazar"
6874
}
6975
},
7076
"general": {

frontend/public/locales/nl/translation.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
"guestModeNotice": {
6666
"message": "Je bent momenteel offline.",
6767
"messageWithAction": "Je bent offline. Gegevens kunnen verloren gaan. Log in om je voortgang op te slaan."
68+
},
69+
"analyticsConsent": {
70+
"title": "Wij gebruiken cookies",
71+
"description": "We gebruiken cookies om je ervaring te verbeteren en het gebruik van de site te analyseren. Accepteer of weiger cookies om FlashNotes te blijven gebruiken.",
72+
"accept": "Accepteren",
73+
"decline": "Weigeren"
6874
}
6975
},
7076
"general": {
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { CONSENT_KEY } from '@/lib/const/analytics'
2+
import { Box, Button, Flex, IconButton, Text } from '@chakra-ui/react'
3+
import posthog from 'posthog-js'
4+
import type { FC } from 'react'
5+
import { useEffect, useState } from 'react'
6+
import { useTranslation } from 'react-i18next'
7+
import { FaTimes as CloseIcon } from 'react-icons/fa'
8+
9+
const AnalyticsConsent: FC = () => {
10+
const [showConsent, setShowConsent] = useState<boolean>(false)
11+
const { t } = useTranslation()
12+
13+
useEffect(() => {
14+
const storedConsent = localStorage.getItem(CONSENT_KEY)
15+
if (storedConsent === 'true') {
16+
setShowConsent(false)
17+
initializeAnalytics()
18+
} else if (storedConsent === 'false') {
19+
setShowConsent(false)
20+
} else {
21+
setShowConsent(true)
22+
}
23+
}, [])
24+
25+
const initializeAnalytics = () => {
26+
if (
27+
import.meta.env.PROD &&
28+
import.meta.env.VITE_POSTHOG_API_KEY &&
29+
import.meta.env.VITE_POSTHOG_HOST
30+
) {
31+
posthog.init(import.meta.env.VITE_POSTHOG_API_KEY, {
32+
api_host: import.meta.env.VITE_POSTHOG_HOST,
33+
})
34+
}
35+
}
36+
37+
const handleAccept = () => {
38+
localStorage.setItem(CONSENT_KEY, 'true')
39+
setShowConsent(false)
40+
initializeAnalytics()
41+
}
42+
43+
const handleDecline = () => {
44+
localStorage.setItem(CONSENT_KEY, 'false')
45+
setShowConsent(false)
46+
}
47+
48+
const handleClose = () => {
49+
setShowConsent(false)
50+
}
51+
52+
if (!showConsent) {
53+
return null
54+
}
55+
56+
return (
57+
<Box
58+
position="fixed"
59+
top={0}
60+
left={0}
61+
width="100dvw"
62+
height="100dvh"
63+
bg="blackAlpha.400"
64+
zIndex="overlay"
65+
display="flex"
66+
flexDirection="column"
67+
justifyContent="flex-end"
68+
alignItems="flex-end"
69+
pointerEvents="auto"
70+
>
71+
<Box
72+
maxW="sm"
73+
width="100%"
74+
bg="bg.100"
75+
color="fg.primary"
76+
p={6}
77+
borderRadius="lg"
78+
borderWidth="1px"
79+
borderColor="bg.100"
80+
display="flex"
81+
flexDirection="column"
82+
gap={3}
83+
position="relative"
84+
pointerEvents="auto"
85+
mb={{ base: 4, md: 8 }}
86+
mr={{ base: 4, md: 8 }}
87+
>
88+
<IconButton
89+
aria-label={t('general.actions.close')}
90+
size="sm"
91+
variant="ghost"
92+
color="fg.muted"
93+
position="absolute"
94+
top={2}
95+
right={2}
96+
onClick={handleClose}
97+
_hover={{ bg: 'bg.50' }}
98+
>
99+
<CloseIcon />
100+
</IconButton>
101+
<Text fontWeight="bold" fontSize="lg" mb={1} display="flex" alignItems="center">
102+
{t('components.analyticsConsent.title')}{' '}
103+
<Box as="span" ml={1}>
104+
🍪
105+
</Box>
106+
</Text>
107+
<Text fontSize="sm" color="fg.muted" mb={2}>
108+
{t('components.analyticsConsent.description')}
109+
</Text>
110+
<Flex gap={2} direction={{ base: 'column', md: 'row' }} justify="flex-end">
111+
<Button
112+
size="sm"
113+
variant="outline"
114+
color="fg.primary"
115+
borderColor="bg.200"
116+
borderRadius="md"
117+
onClick={handleDecline}
118+
_hover={{ bg: 'bg.50', borderColor: 'bg.200' }}
119+
>
120+
{t('components.analyticsConsent.decline')}
121+
</Button>
122+
<Button
123+
size="sm"
124+
minW={28}
125+
bg="accent.purple.light"
126+
color="gray.800"
127+
borderRadius="md"
128+
onClick={handleAccept}
129+
_hover={{ bg: 'accent.purple.dark' }}
130+
fontWeight="semibold"
131+
>
132+
{t('components.analyticsConsent.accept')}
133+
</Button>
134+
</Flex>
135+
</Box>
136+
</Box>
137+
)
138+
}
139+
140+
export default AnalyticsConsent
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const CONSENT_KEY = 'analytics_consent'

frontend/src/main.tsx

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import { ColorModeProvider } from '@/components/ui/color-mode'
33
import { ChakraProvider } from '@chakra-ui/react'
44
import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query'
55
import { RouterProvider, createRouter } from '@tanstack/react-router'
6-
import { PostHogProvider } from 'posthog-js/react'
76
import { StrictMode } from 'react'
87
import ReactDOM from 'react-dom/client'
98
import { ApiError, OpenAPI } from './client'
9+
import AnalyticsConsent from './components/commonUI/AnalyticsConsent'
1010
import { AuthProvider } from './hooks/useAuthContext'
1111
import { routeTree } from './routeTree.gen'
1212
import { system } from './theme'
@@ -38,12 +38,6 @@ declare module '@tanstack/react-router' {
3838
}
3939
}
4040

41-
const posthogApiKey = import.meta.env.VITE_POSTHOG_API_KEY
42-
const posthogConfig = {
43-
enabled: import.meta.env.PROD && !!posthogApiKey,
44-
options: import.meta.env.VITE_POSTHOG_HOST ? { api_host: import.meta.env.VITE_POSTHOG_HOST } : {},
45-
}
46-
4741
const rootElement = document.getElementById('root')
4842
if (rootElement && !rootElement.innerHTML) {
4943
const root = ReactDOM.createRoot(rootElement)
@@ -52,14 +46,9 @@ if (rootElement && !rootElement.innerHTML) {
5246
<AuthProvider>
5347
<ChakraProvider value={system}>
5448
<ColorModeProvider>
49+
<AnalyticsConsent />
5550
<QueryClientProvider client={queryClient}>
56-
{posthogConfig.enabled ? (
57-
<PostHogProvider apiKey={posthogApiKey} options={posthogConfig.options}>
58-
<RouterProvider router={router} />
59-
</PostHogProvider>
60-
) : (
61-
<RouterProvider router={router} />
62-
)}
51+
<RouterProvider router={router} />
6352
</QueryClientProvider>
6453
</ColorModeProvider>
6554
</ChakraProvider>

frontend/src/theme.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ const config = defineConfig({
7575
'green.dark': {
7676
value: '#2E493F',
7777
},
78+
'purple.light': {
79+
value: '#D8B4FC',
80+
},
81+
'purple.dark': {
82+
value: '#D1A6F7',
83+
},
7884
},
7985
stat: {
8086
positive: {

0 commit comments

Comments
 (0)