diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 0000000..3247f89 --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,76 @@ +import { ColorModeProvider } from '@/components/ui/color-mode' +import { ChakraProvider } from '@chakra-ui/react' +import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { RouterProvider, createRouter } from '@tanstack/react-router' +import { PostHogProvider } from 'posthog-js/react' +import { useState } from 'react' +import { OpenAPI } from './client' +import { ApiError } from './client' +import { AuthProvider } from './hooks/useAuthContext' +import { routeTree } from './routeTree.gen' +import { system } from './theme' +import CookieConsent from './components/commonUI/CookieConsentBanner' + +OpenAPI.BASE = import.meta.env.VITE_API_URL +OpenAPI.TOKEN = async () => { + return localStorage.getItem('access_token') || '' +} + + +const posthogApiKey = import.meta.env.VITE_POSTHOG_API_KEY +const posthogConfig = { + enabled: import.meta.env.PROD && !!posthogApiKey, + options: import.meta.env.VITE_POSTHOG_HOST ? { api_host: import.meta.env.VITE_POSTHOG_HOST } : {}, +} + +const handleApiError = (error: Error) => { + if (error instanceof ApiError && [401, 403].includes(error.status)) { + localStorage.removeItem('access_token') + window.location.href = '/login' + } + } + + +const queryClient = new QueryClient({ + queryCache: new QueryCache({ + onError: handleApiError, + }), + mutationCache: new MutationCache({ + onError: handleApiError, + }), +}) + +const router = createRouter({ routeTree }) + +declare module '@tanstack/react-router' { + interface Register { + router: typeof router + } +} + +const App = () => { + const [isPosthogEnabled, setIsPosthogEnabled] = useState(false); + const onConsent=(status:boolean)=>{ + setIsPosthogEnabled(status) + } + return ( + + + + + + {isPosthogEnabled && posthogConfig.enabled ? ( + + + + ) : ( + + )} + + + + + ); +}; + +export default App; \ No newline at end of file diff --git a/frontend/src/components/commonUI/CookieConsentBanner.tsx b/frontend/src/components/commonUI/CookieConsentBanner.tsx new file mode 100644 index 0000000..5697c34 --- /dev/null +++ b/frontend/src/components/commonUI/CookieConsentBanner.tsx @@ -0,0 +1,129 @@ +import React, { useState, useEffect } from "react"; +import { + Box, + Button, + Flex, + Text, + Link, + VStack, + IconButton, +} from "@chakra-ui/react"; + +import { FaTimes as CloseIcon } from "react-icons/fa"; + +interface CookieConsentProps{ + consented:boolean + onConsent:(status:boolean)=>void +} + +const CookieConsent:React.FC = ({consented,onConsent}) => { + const [isVisible, setIsVisible] = useState(false); + useEffect(() => { + const consent = localStorage.getItem("cookie-consent"); + if (consent==="all") { + onConsent(true); + } else { + const timer = setTimeout(() => { + onConsent(false) + setIsVisible(true); + }, 300); + return () => clearTimeout(timer); + } + }, []); + + const handleAcceptAll = () => { + localStorage.setItem("cookie-consent", "all"); + setIsVisible(false); + setTimeout(() => onConsent(true), 300); + }; + + const handleAcceptNecessary = () => { + localStorage.setItem("cookie-consent", "deny"); + setIsVisible(false); + setTimeout(() => onConsent(false), 300); + }; + + const handleClose = () => { + setIsVisible(false); + }; + + if (consented) return null; + return ( + + + + We use cookies 🍪 + + To enhance your experience on FlashNotes. By continuing, you agree to our use of cookies as outlined in our + + Privacy Policy + . + + + + + + + + + + + + + ); +}; + +export default CookieConsent; diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 8e60b5f..e8d1c0c 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,69 +1,14 @@ import './i18n' -import { ColorModeProvider } from '@/components/ui/color-mode' -import { ChakraProvider } from '@chakra-ui/react' -import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { RouterProvider, createRouter } from '@tanstack/react-router' -import { PostHogProvider } from 'posthog-js/react' import { StrictMode } from 'react' import ReactDOM from 'react-dom/client' -import { ApiError, OpenAPI } from './client' -import { AuthProvider } from './hooks/useAuthContext' -import { routeTree } from './routeTree.gen' -import { system } from './theme' - -OpenAPI.BASE = import.meta.env.VITE_API_URL -OpenAPI.TOKEN = async () => { - return localStorage.getItem('access_token') || '' -} - -const handleApiError = (error: Error) => { - if (error instanceof ApiError && [401, 403].includes(error.status)) { - localStorage.removeItem('access_token') - window.location.href = '/login' - } -} -const queryClient = new QueryClient({ - queryCache: new QueryCache({ - onError: handleApiError, - }), - mutationCache: new MutationCache({ - onError: handleApiError, - }), -}) - -const router = createRouter({ routeTree }) -declare module '@tanstack/react-router' { - interface Register { - router: typeof router - } -} - -const posthogApiKey = import.meta.env.VITE_POSTHOG_API_KEY -const posthogConfig = { - enabled: import.meta.env.PROD && !!posthogApiKey, - options: import.meta.env.VITE_POSTHOG_HOST ? { api_host: import.meta.env.VITE_POSTHOG_HOST } : {}, -} +import App from './App' const rootElement = document.getElementById('root') if (rootElement && !rootElement.innerHTML) { const root = ReactDOM.createRoot(rootElement) root.render( - - - - - {posthogConfig.enabled ? ( - - - - ) : ( - - )} - - - - + , ) }