From e6031a70b22e6ac285ab43655fa2b937b441bc97 Mon Sep 17 00:00:00 2001 From: behcetilhan Date: Tue, 9 Apr 2024 22:42:22 +0200 Subject: [PATCH 01/12] added mui --- .eslintrc.cjs | 1 + bun.lockb | Bin 167836 -> 187688 bytes index.html | 2 +- package.json | 5 ++ src/App.tsx | 39 +++++++++ src/components/auth/LoginComponent.tsx | 81 ++++++++++-------- src/main.tsx | 60 +++---------- src/routes/__root.tsx | 9 +- src/theme.ts | 15 ++++ src/utils/{AuthContext.tsx => AppContext.tsx} | 10 +-- src/utils/hooks/useAuth.ts | 4 +- 11 files changed, 131 insertions(+), 95 deletions(-) create mode 100644 src/App.tsx create mode 100644 src/theme.ts rename src/utils/{AuthContext.tsx => AppContext.tsx} (63%) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index f5c4de7..e49b61c 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -22,6 +22,7 @@ module.exports = { '@typescript-eslint/no-unsafe-argument': 'off', '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-return':'off', 'react-refresh/only-export-components': [ 'warn', {allowConstantExport: true}, diff --git a/bun.lockb b/bun.lockb index 5e5956e6303404ce1f175312eb9459ae57d17ebd..b0eacd875afc454f9f451e0d48cb2ee705f00647 100755 GIT binary patch delta 40466 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 bm3g{sGf@4PCZ@*i=bM?rxu&!9GtB@18~*L^ delta 27489 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 diff --git a/index.html b/index.html index 990e82d..7a0ee2c 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ Vite + React + TS -
+
diff --git a/package.json b/package.json index 67fb3f4..4a6cca0 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,11 @@ "preview": "vite preview" }, "dependencies": { + "@emotion/react": "^11.11.4", + "@emotion/styled": "^11.11.5", + "@fontsource/roboto": "^5.0.12", + "@mui/icons-material": "^5.15.15", + "@mui/material": "^5.15.15", "@tanstack/react-query": "^5.28.14", "@tanstack/react-router": "^1.26.7", "axios": "^1.6.8", diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..d173c87 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,39 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { + createRouter, + ErrorComponent, + RouterProvider +} from '@tanstack/react-router' +import { useAuth } from '@/utils/hooks/useAuth' +import { routeTree } from '@/routeTree.gen' + +const queryClient = new QueryClient() + +declare module '@tanstack/react-router' { + interface Register { + router: typeof router + } +} + +const router = createRouter({ + routeTree, + context: { + auth: undefined!, + queryClient + }, + defaultPreload: 'intent', + defaultPreloadStaleTime: 0, + defaultPendingComponent: () => ...loading..., + defaultErrorComponent: ({ error }) => , + defaultNotFoundComponent: () => is a 404 +}) + +export const App = () => { + const auth = useAuth() + + return ( + + + + ) +} diff --git a/src/components/auth/LoginComponent.tsx b/src/components/auth/LoginComponent.tsx index 5d29906..9c12d0e 100644 --- a/src/components/auth/LoginComponent.tsx +++ b/src/components/auth/LoginComponent.tsx @@ -1,42 +1,55 @@ -import { Field, Form, Formik } from 'formik' +import { useFormik } from 'formik' import { loginSchema } from '@/components/auth/loginSchema' import { toFormikValidationSchema } from 'zod-formik-adapter' -import { useMutation } from '@tanstack/react-query' -import { User } from '@/utils/AuthContext' -import axios from 'axios' +import { Button, Container, Stack, TextField } from '@mui/material' export const LoginComponent = () => { - const mutation = useMutation({ - mutationFn: ({ username, password }: User) => { - return axios.post( - 'https://localhost:3001/login', - { username, password }, - { withCredentials: true } - ) - }, - onSuccess: () => { - console.log('success') - }, - onError: (error) => console.log('error -->', error) - }) - - return ( - { - console.log('values -->', values) - mutation.mutate(values) - }} - validationSchema={toFormikValidationSchema(loginSchema)} - > -
- - - - -
+ }, + validationSchema: toFormikValidationSchema(loginSchema), + onSubmit: (values) => { + console.log(JSON.stringify(values, null, 2)) + } + }) + + return ( + +
+ + + + + +
+
) } diff --git a/src/main.tsx b/src/main.tsx index 6a074f3..7027c8c 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,61 +1,23 @@ import ReactDOM from 'react-dom/client' -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { - createRouter, - ErrorComponent, - RouterProvider -} from '@tanstack/react-router' -import { routeTree } from '@/routeTree.gen' -import { useAuth } from '@/utils/hooks/useAuth' -import { AuthProvider } from '@/utils/AuthContext' +import { AppProvider } from '@/utils/AppContext' import { StrictMode } from 'react' +import { CssBaseline, ThemeProvider } from '@mui/material' +import { theme } from '@/theme' +import { App } from '@/App' -const queryClient = new QueryClient() - -const router = createRouter({ - routeTree, - context: { - auth: undefined!, - queryClient - }, - defaultPreload: 'intent', - defaultPreloadStaleTime: 0, - defaultPendingComponent: () => ...loading..., - defaultErrorComponent: ({ error }) => , - defaultNotFoundComponent: () => is a 404 -}) - -declare module '@tanstack/react-router' { - interface Register { - router: typeof router - } -} - -function InnerApp() { - const auth = useAuth() - return ( - - - - ) -} - -function App() { - return ( - - - - ) -} - -const rootElement = document.getElementById('app')! +const rootElement = document.getElementById('appRoot')! if (!rootElement.innerHTML) { const root = ReactDOM.createRoot(rootElement) root.render( - + + + + + + ) } diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 44e8618..d5a4ae6 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -1,16 +1,17 @@ import { createRootRouteWithContext, Outlet } from '@tanstack/react-router' import { QueryClient } from '@tanstack/react-query' -import { AuthContextProps } from 'utils/AuthContext' +import { AppContextProps } from '@/utils/AppContext' +import { Typography } from '@mui/material' -interface RouterContextProps { - auth: AuthContextProps +export interface RouterContextProps { + auth: AppContextProps queryClient: QueryClient } export const Route = createRootRouteWithContext()({ component: () => (
- root itself + root component
diff --git a/src/theme.ts b/src/theme.ts new file mode 100644 index 0000000..550676b --- /dev/null +++ b/src/theme.ts @@ -0,0 +1,15 @@ +import { createTheme } from '@mui/material/styles' + +export const theme = createTheme({ + palette: { + primary: { + main: '#556cd6' + }, + secondary: { + main: '#19857b' + }, + error: { + main: '#ff0000' + } + } +}) diff --git a/src/utils/AuthContext.tsx b/src/utils/AppContext.tsx similarity index 63% rename from src/utils/AuthContext.tsx rename to src/utils/AppContext.tsx index 63e9129..7c245b5 100644 --- a/src/utils/AuthContext.tsx +++ b/src/utils/AppContext.tsx @@ -5,21 +5,21 @@ export interface User { password: string } -export interface AuthContextProps { +export interface AppContextProps { isAuthenticated: boolean setUser: (user: User | null) => void user: User | null } -const authInitials: AuthContextProps = { +const appInitials: AppContextProps = { isAuthenticated: false, setUser: () => {}, user: null } -export const AuthContext = createContext(authInitials) +export const AppContext = createContext(appInitials) -export const AuthProvider = (props: PropsWithChildren) => { +export const AppProvider = (props: PropsWithChildren) => { const [user, setUser] = useState(null) const isAuthenticated = !!user @@ -29,6 +29,6 @@ export const AuthProvider = (props: PropsWithChildren) => { ) return ( - {props.children} + {props.children} ) } diff --git a/src/utils/hooks/useAuth.ts b/src/utils/hooks/useAuth.ts index 0f1b5c1..2c84882 100644 --- a/src/utils/hooks/useAuth.ts +++ b/src/utils/hooks/useAuth.ts @@ -1,8 +1,8 @@ import { useContext } from 'react' -import { AuthContext } from '@/utils/AuthContext' +import { AppContext } from '@/utils/AppContext' export const useAuth = () => { - const context = useContext(AuthContext) + const context = useContext(AppContext) if (!context) { throw new Error('useAuth must be used inside AuthProvider') From 1dfda0b785ec60997b3dc34d9e9fffe1454c6b79 Mon Sep 17 00:00:00 2001 From: behcetilhan Date: Wed, 10 Apr 2024 22:48:07 +0200 Subject: [PATCH 02/12] added dark mode support --- src/components/themeToggler/ThemeToggler.tsx | 14 +++++ src/main.tsx | 8 +-- src/routes/__root.tsx | 5 +- src/theme.ts | 15 ------ src/utils/ThemeContext.tsx | 55 ++++++++++++++++++++ src/utils/hooks/useThemeContext.ts | 10 ++++ 6 files changed, 86 insertions(+), 21 deletions(-) create mode 100644 src/components/themeToggler/ThemeToggler.tsx delete mode 100644 src/theme.ts create mode 100644 src/utils/ThemeContext.tsx create mode 100644 src/utils/hooks/useThemeContext.ts diff --git a/src/components/themeToggler/ThemeToggler.tsx b/src/components/themeToggler/ThemeToggler.tsx new file mode 100644 index 0000000..1c305b1 --- /dev/null +++ b/src/components/themeToggler/ThemeToggler.tsx @@ -0,0 +1,14 @@ +import { useThemeContext } from '@/utils/hooks/useThemeContext' +import { IconButton } from '@mui/material' +import Brightness4Icon from '@mui/icons-material/Brightness4' +import Brightness7Icon from '@mui/icons-material/Brightness7' + +export const ThemeToggler = () => { + const { toggleTheme, isDarkMode } = useThemeContext() + + return ( + + {isDarkMode ? : } + + ) +} diff --git a/src/main.tsx b/src/main.tsx index 7027c8c..febfe9d 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,9 +1,9 @@ import ReactDOM from 'react-dom/client' import { AppProvider } from '@/utils/AppContext' import { StrictMode } from 'react' -import { CssBaseline, ThemeProvider } from '@mui/material' -import { theme } from '@/theme' +import { CssBaseline } from '@mui/material' import { App } from '@/App' +import { MultiThemeProvider } from '@/utils/ThemeContext' const rootElement = document.getElementById('appRoot')! @@ -12,12 +12,12 @@ if (!rootElement.innerHTML) { root.render( - + - + ) } diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index d5a4ae6..4da8b13 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -1,7 +1,7 @@ import { createRootRouteWithContext, Outlet } from '@tanstack/react-router' import { QueryClient } from '@tanstack/react-query' import { AppContextProps } from '@/utils/AppContext' -import { Typography } from '@mui/material' +import { ThemeToggler } from '@/components/themeToggler/ThemeToggler' export interface RouterContextProps { auth: AppContextProps @@ -11,7 +11,8 @@ export interface RouterContextProps { export const Route = createRootRouteWithContext()({ component: () => (
- root component + Toggle Theme +
diff --git a/src/theme.ts b/src/theme.ts deleted file mode 100644 index 550676b..0000000 --- a/src/theme.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { createTheme } from '@mui/material/styles' - -export const theme = createTheme({ - palette: { - primary: { - main: '#556cd6' - }, - secondary: { - main: '#19857b' - }, - error: { - main: '#ff0000' - } - } -}) diff --git a/src/utils/ThemeContext.tsx b/src/utils/ThemeContext.tsx new file mode 100644 index 0000000..2f92374 --- /dev/null +++ b/src/utils/ThemeContext.tsx @@ -0,0 +1,55 @@ +import { createContext, PropsWithChildren, useEffect, useState } from 'react' +import { createTheme } from '@mui/material/styles' +import { ThemeProvider, useMediaQuery } from '@mui/material' + +interface ThemeContextProps { + toggleTheme: () => void + isDarkMode: boolean +} + +const themeInitials: ThemeContextProps = { + toggleTheme: () => {}, + isDarkMode: false +} + +export const ThemeContext = createContext(themeInitials) + +export const MultiThemeProvider = (props: PropsWithChildren) => { + const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)') + const [isDarkMode, setIsDarkMode] = useState(() => { + const persistedPreference = localStorage.getItem('theme') + + if (persistedPreference) { + return persistedPreference === 'dark' + } + + return prefersDarkMode + }) + + useEffect(() => { + localStorage.setItem('theme', isDarkMode ? 'dark' : 'light') + }, [isDarkMode]) + + const toggleTheme = () => setIsDarkMode(!isDarkMode) + + const theme = createTheme({ + palette: { + mode: isDarkMode ? 'dark' : 'light', + primary: { + main: '#556cd6' + }, + secondary: { + main: '#19857b' + }, + error: { + main: '#ff0000' + } + } + }) + + return ( + + {props.children} + + ) +} diff --git a/src/utils/hooks/useThemeContext.ts b/src/utils/hooks/useThemeContext.ts new file mode 100644 index 0000000..6ba5c4f --- /dev/null +++ b/src/utils/hooks/useThemeContext.ts @@ -0,0 +1,10 @@ +import { useContext } from 'react' +import { ThemeContext } from '@/utils/ThemeContext' + +export const useThemeContext = () => { + const context = useContext(ThemeContext) + + if (!context) + throw new Error('useThemeContext must be used within a ThemeProvider') + return context +} From 21e33265704708f210fade4305e440de30454c0c Mon Sep 17 00:00:00 2001 From: behcetilhan Date: Fri, 12 Apr 2024 17:06:36 +0200 Subject: [PATCH 03/12] added i18next --- .eslintrc.cjs | 1 + bun.lockb | Bin 187688 -> 189636 bytes package.json | 3 +++ src/components/auth/LoginComponent.tsx | 8 +++--- .../languageToggler/LanguageToggler.tsx | 19 ++++++++++++++ src/i18n.ts | 18 +++++++++++++ src/locales/de.json | 11 ++++++++ src/locales/en.json | 11 ++++++++ src/main.tsx | 2 ++ src/routes/__root.tsx | 3 ++- src/utils/hooks/useLanguageSelect.ts | 24 ++++++++++++++++++ 11 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 src/components/languageToggler/LanguageToggler.tsx create mode 100644 src/i18n.ts create mode 100644 src/locales/de.json create mode 100644 src/locales/en.json create mode 100644 src/utils/hooks/useLanguageSelect.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index e49b61c..baa3492 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -23,6 +23,7 @@ module.exports = { '@typescript-eslint/no-unsafe-call': 'off', '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/no-unsafe-return':'off', + '@typescript-eslint/no-floating-promises':'off', 'react-refresh/only-export-components': [ 'warn', {allowConstantExport: true}, diff --git a/bun.lockb b/bun.lockb index b0eacd875afc454f9f451e0d48cb2ee705f00647..7d93d7b36f8676673f93cb66e355291d7d2d3959 100755 GIT binary patch delta 36298 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 K$ZD-9>i+==_xv&d delta 35310 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 bws}jmfhA;iXDv_We5HA9d$3mfEcX8ZI9&Do diff --git a/package.json b/package.json index 4a6cca0..8a66934 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,11 @@ "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-react": "^7.34.1", "formik": "^2.4.5", + "i18next": "^23.11.1", + "install": "^0.13.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-i18next": "^14.1.0", "zod": "^3.22.4", "zod-formik-adapter": "^1.3.0" }, diff --git a/src/components/auth/LoginComponent.tsx b/src/components/auth/LoginComponent.tsx index 9c12d0e..774c713 100644 --- a/src/components/auth/LoginComponent.tsx +++ b/src/components/auth/LoginComponent.tsx @@ -2,8 +2,10 @@ import { useFormik } from 'formik' import { loginSchema } from '@/components/auth/loginSchema' import { toFormikValidationSchema } from 'zod-formik-adapter' import { Button, Container, Stack, TextField } from '@mui/material' +import { useTranslation } from 'react-i18next' export const LoginComponent = () => { + const { t } = useTranslation() const { handleSubmit, values, handleChange, handleBlur, touched, errors } = useFormik({ initialValues: { @@ -25,7 +27,7 @@ export const LoginComponent = () => { fullWidth id='username' name='username' - label='Username' + label={t('auth.username')} value={values.username} onChange={handleChange} onBlur={handleBlur} @@ -37,7 +39,7 @@ export const LoginComponent = () => { fullWidth id='password' name='password' - label='Password' + label={t('auth.password')} type='password' value={values.password} onChange={handleChange} @@ -46,7 +48,7 @@ export const LoginComponent = () => { helperText={touched.password && errors.password} /> diff --git a/src/components/languageToggler/LanguageToggler.tsx b/src/components/languageToggler/LanguageToggler.tsx new file mode 100644 index 0000000..3563a17 --- /dev/null +++ b/src/components/languageToggler/LanguageToggler.tsx @@ -0,0 +1,19 @@ +import { useTranslation } from 'react-i18next' +import { useLanguageSelect } from '@/utils/hooks/useLanguageSelect' +import { MenuItem, Select } from '@mui/material' + +export const LanguageToggler = () => { + const { currentLanguage, handleLanguageSelect } = useLanguageSelect() + const { t } = useTranslation() + + return ( + + ) +} diff --git a/src/i18n.ts b/src/i18n.ts new file mode 100644 index 0000000..3ae017f --- /dev/null +++ b/src/i18n.ts @@ -0,0 +1,18 @@ +import i18n from 'i18next' +import { initReactI18next } from 'react-i18next' +import en from '@/locales/en.json' +import de from '@/locales/de.json' + +export const initI18n = () => { + i18n.use(initReactI18next).init({ + fallbackLng: 'en', + resources: { + en: { + translation: en + }, + de: { + translation: de + } + } + }) +} diff --git a/src/locales/de.json b/src/locales/de.json new file mode 100644 index 0000000..65f9ad8 --- /dev/null +++ b/src/locales/de.json @@ -0,0 +1,11 @@ +{ + "languages": { + "english": "Englisch", + "german": "Deutsch" + }, + "auth": { + "username": "Benutzername", + "password": "Passwort", + "login": "Einloggen" + } +} diff --git a/src/locales/en.json b/src/locales/en.json new file mode 100644 index 0000000..3517508 --- /dev/null +++ b/src/locales/en.json @@ -0,0 +1,11 @@ +{ + "languages": { + "english": "English", + "german": "German" + }, + "auth": { + "username": "Username", + "password": "Password", + "login": "Login" + } +} diff --git a/src/main.tsx b/src/main.tsx index febfe9d..dffdacb 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -4,12 +4,14 @@ import { StrictMode } from 'react' import { CssBaseline } from '@mui/material' import { App } from '@/App' import { MultiThemeProvider } from '@/utils/ThemeContext' +import { initI18n } from '@/i18n' const rootElement = document.getElementById('appRoot')! if (!rootElement.innerHTML) { const root = ReactDOM.createRoot(rootElement) + initI18n() root.render( diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 4da8b13..8adf890 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -2,6 +2,7 @@ import { createRootRouteWithContext, Outlet } from '@tanstack/react-router' import { QueryClient } from '@tanstack/react-query' import { AppContextProps } from '@/utils/AppContext' import { ThemeToggler } from '@/components/themeToggler/ThemeToggler' +import { LanguageToggler } from '@/components/languageToggler/LanguageToggler' export interface RouterContextProps { auth: AppContextProps @@ -11,8 +12,8 @@ export interface RouterContextProps { export const Route = createRootRouteWithContext()({ component: () => (
- Toggle Theme +
diff --git a/src/utils/hooks/useLanguageSelect.ts b/src/utils/hooks/useLanguageSelect.ts new file mode 100644 index 0000000..ca5ef16 --- /dev/null +++ b/src/utils/hooks/useLanguageSelect.ts @@ -0,0 +1,24 @@ +import { useEffect, useState } from 'react' +import i18n from 'i18next' + +export const useLanguageSelect = () => { + const [currentLanguage, setCurrentLanguage] = useState(i18n.language) + + useEffect(() => { + const handleLanguageChange = () => { + setCurrentLanguage(i18n.language) + } + + i18n.on('languageChanged', handleLanguageChange) + + return () => { + i18n.off('languageChanged', handleLanguageChange) + } + }, []) + + const handleLanguageSelect = (newLanguage: string) => { + i18n.changeLanguage(newLanguage) + } + + return { currentLanguage, handleLanguageSelect } +} From 3922ce49b220c04560b9a79930d913387f125411 Mon Sep 17 00:00:00 2001 From: behcetilhan Date: Fri, 12 Apr 2024 17:29:05 +0200 Subject: [PATCH 04/12] Update README.md --- README.md | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/README.md b/README.md index 0d6babe..60c811f 100644 --- a/README.md +++ b/README.md @@ -1,30 +1 @@ -# React + TypeScript + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh - -## Expanding the ESLint configuration - -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: - -- Configure the top-level `parserOptions` property like this: - -```js -export default { - // other rules... - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['./tsconfig.json', './tsconfig.node.json'], - tsconfigRootDir: __dirname, - }, -} -``` - -- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` -- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list +# ReactRover: React + TypeScript + Vite From 2caf314da93a7d83691d937960ab35ad48f26166 Mon Sep 17 00:00:00 2001 From: behcetilhan Date: Fri, 12 Apr 2024 17:34:50 +0200 Subject: [PATCH 05/12] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3a60d05 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 behcetilhan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From befae42d1081960234d2a2d247a92c9d23c5c4fd Mon Sep 17 00:00:00 2001 From: behcetilhan Date: Sun, 14 Apr 2024 13:37:09 +0200 Subject: [PATCH 06/12] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 3a60d05..b9c2626 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 behcetilhan +Copyright (c) 2024 behcet ilhan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 1ad7755995499f756dcac79302c90ff3ebce18f6 Mon Sep 17 00:00:00 2001 From: behcetilhan Date: Wed, 24 Apr 2024 23:10:07 +0200 Subject: [PATCH 07/12] httponly cookie base --- bun.lockb | Bin 189636 -> 190095 bytes index.html | 2 +- package.json | 1 + src/App.tsx | 5 ++ src/components/RootComponent.tsx | 14 +++++ src/components/auth/LoginComponent.tsx | 26 +++++++- .../dashboard/DashboardComponent.tsx | 41 +++++++++++++ src/components/profile/ProfileComponent.tsx | 17 ++++++ src/main.tsx | 5 +- src/routeTree.gen.ts | 39 +++++++++++- src/routes/__root.tsx | 14 +---- src/routes/_authenticated.ts | 21 +++++++ src/routes/_authenticated/dashboard.tsx | 6 ++ src/routes/_authenticated/profile.tsx | 6 ++ src/routes/index.tsx | 4 +- src/routes/login.tsx | 7 ++- src/utils/AppContext.tsx | 22 +++---- src/utils/AppProvider.tsx | 46 ++++++++++++++ src/utils/apiDefaults.ts | 32 +++++++++- src/utils/hooks/useApi.ts | 18 ++++++ src/utils/hooks/useLogin.ts | 56 ++++++++++++++++++ src/utils/hooks/useLogout.ts | 21 +++++++ 22 files changed, 367 insertions(+), 36 deletions(-) create mode 100644 src/components/RootComponent.tsx create mode 100644 src/components/dashboard/DashboardComponent.tsx create mode 100644 src/components/profile/ProfileComponent.tsx create mode 100644 src/routes/_authenticated.ts create mode 100644 src/routes/_authenticated/dashboard.tsx create mode 100644 src/routes/_authenticated/profile.tsx create mode 100644 src/utils/AppProvider.tsx create mode 100644 src/utils/hooks/useApi.ts create mode 100644 src/utils/hooks/useLogin.ts create mode 100644 src/utils/hooks/useLogout.ts diff --git a/bun.lockb b/bun.lockb index 7d93d7b36f8676673f93cb66e355291d7d2d3959..a2f1a250faab0b792cc4a3ce7f2235e024d5422d 100755 GIT binary patch delta 34455 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 delta 33986 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 diff --git a/index.html b/index.html index 7a0ee2c..8c9ed38 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - Vite + React + TS + ReactRover
diff --git a/package.json b/package.json index 8a66934..805176a 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^14.1.0", + "react-toastify": "^10.0.5", "zod": "^3.22.4", "zod-formik-adapter": "^1.3.0" }, diff --git a/src/App.tsx b/src/App.tsx index d173c87..7c47be3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,6 +6,7 @@ import { } from '@tanstack/react-router' import { useAuth } from '@/utils/hooks/useAuth' import { routeTree } from '@/routeTree.gen' +import { useEffect } from 'react' const queryClient = new QueryClient() @@ -31,6 +32,10 @@ const router = createRouter({ export const App = () => { const auth = useAuth() + useEffect(() => { + router.invalidate() + }, [auth]) + return ( diff --git a/src/components/RootComponent.tsx b/src/components/RootComponent.tsx new file mode 100644 index 0000000..6b63cc5 --- /dev/null +++ b/src/components/RootComponent.tsx @@ -0,0 +1,14 @@ +import { ThemeToggler } from '@/components/themeToggler/ThemeToggler' +import { LanguageToggler } from '@/components/languageToggler/LanguageToggler' +import { Outlet } from '@tanstack/react-router' + +export const RootComponent = () => { + return ( +
+ + +
+ +
+ ) +} diff --git a/src/components/auth/LoginComponent.tsx b/src/components/auth/LoginComponent.tsx index 774c713..c5a8d89 100644 --- a/src/components/auth/LoginComponent.tsx +++ b/src/components/auth/LoginComponent.tsx @@ -3,9 +3,20 @@ import { loginSchema } from '@/components/auth/loginSchema' import { toFormikValidationSchema } from 'zod-formik-adapter' import { Button, Container, Stack, TextField } from '@mui/material' import { useTranslation } from 'react-i18next' +import { useAuth } from '@/utils/hooks/useAuth' +import { useRouter } from '@tanstack/react-router' +import { Route } from '@/routes/login' +import { useLayoutEffect } from 'react' +import { useLogin } from '@/utils/hooks/useLogin' export const LoginComponent = () => { const { t } = useTranslation() + const { isAuthenticated } = useAuth() + const { redirect } = Route.useSearch() + const router = useRouter() + + const loginMutation = useLogin() + const { handleSubmit, values, handleChange, handleBlur, touched, errors } = useFormik({ initialValues: { @@ -14,12 +25,23 @@ export const LoginComponent = () => { }, validationSchema: toFormikValidationSchema(loginSchema), onSubmit: (values) => { - console.log(JSON.stringify(values, null, 2)) + const { username, password } = values + return loginMutation.mutate({ + username, + password + }) } }) + useLayoutEffect(() => { + if (!isAuthenticated) { + return + } + redirect ? router.history.push(redirect) : router.history.push('/dashboard') + }, [isAuthenticated, redirect, router.history]) + return ( - +
{ + const { user } = useAuth() + const navigate = useNavigate() + const { mutate: logout } = useLogout() + + const { data, refetch } = useApi('/protected', { + queryKey: ['protectedDataExample'], + enabled: !!user + }) + + return ( + <> +
dashboard user: {user?.username}
+
{data?.secret}
+ + + + + + + ) +} diff --git a/src/components/profile/ProfileComponent.tsx b/src/components/profile/ProfileComponent.tsx new file mode 100644 index 0000000..50587e4 --- /dev/null +++ b/src/components/profile/ProfileComponent.tsx @@ -0,0 +1,17 @@ +import { Button } from '@mui/material' +import { useNavigate } from '@tanstack/react-router' + +export const ProfileComponent = () => { + const navigate = useNavigate() + return ( + <> +
profile page
+ + + ) +} diff --git a/src/main.tsx b/src/main.tsx index dffdacb..388494a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,10 +1,12 @@ import ReactDOM from 'react-dom/client' -import { AppProvider } from '@/utils/AppContext' import { StrictMode } from 'react' import { CssBaseline } from '@mui/material' import { App } from '@/App' import { MultiThemeProvider } from '@/utils/ThemeContext' import { initI18n } from '@/i18n' +import { AppProvider } from '@/utils/AppProvider' +import { ToastContainer } from 'react-toastify' +import 'react-toastify/dist/ReactToastify.min.css' const rootElement = document.getElementById('appRoot')! @@ -17,6 +19,7 @@ if (!rootElement.innerHTML) { + diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 748cd85..f92b7c0 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -12,7 +12,10 @@ import { Route as rootRoute } from './routes/__root' import { Route as LoginImport } from './routes/login' +import { Route as AuthenticatedImport } from './routes/_authenticated' import { Route as IndexImport } from './routes/index' +import { Route as AuthenticatedProfileImport } from './routes/_authenticated/profile' +import { Route as AuthenticatedDashboardImport } from './routes/_authenticated/dashboard' // Create/Update Routes @@ -21,11 +24,26 @@ const LoginRoute = LoginImport.update({ getParentRoute: () => rootRoute, } as any) +const AuthenticatedRoute = AuthenticatedImport.update({ + id: '/_authenticated', + getParentRoute: () => rootRoute, +} as any) + const IndexRoute = IndexImport.update({ path: '/', getParentRoute: () => rootRoute, } as any) +const AuthenticatedProfileRoute = AuthenticatedProfileImport.update({ + path: '/profile', + getParentRoute: () => AuthenticatedRoute, +} as any) + +const AuthenticatedDashboardRoute = AuthenticatedDashboardImport.update({ + path: '/dashboard', + getParentRoute: () => AuthenticatedRoute, +} as any) + // Populate the FileRoutesByPath interface declare module '@tanstack/react-router' { @@ -34,15 +52,34 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexImport parentRoute: typeof rootRoute } + '/_authenticated': { + preLoaderRoute: typeof AuthenticatedImport + parentRoute: typeof rootRoute + } '/login': { preLoaderRoute: typeof LoginImport parentRoute: typeof rootRoute } + '/_authenticated/dashboard': { + preLoaderRoute: typeof AuthenticatedDashboardImport + parentRoute: typeof AuthenticatedImport + } + '/_authenticated/profile': { + preLoaderRoute: typeof AuthenticatedProfileImport + parentRoute: typeof AuthenticatedImport + } } } // Create and export the route tree -export const routeTree = rootRoute.addChildren([IndexRoute, LoginRoute]) +export const routeTree = rootRoute.addChildren([ + IndexRoute, + AuthenticatedRoute.addChildren([ + AuthenticatedDashboardRoute, + AuthenticatedProfileRoute, + ]), + LoginRoute, +]) /* prettier-ignore-end */ diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 8adf890..8dcb3f4 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -1,8 +1,7 @@ -import { createRootRouteWithContext, Outlet } from '@tanstack/react-router' +import { createRootRouteWithContext } from '@tanstack/react-router' import { QueryClient } from '@tanstack/react-query' import { AppContextProps } from '@/utils/AppContext' -import { ThemeToggler } from '@/components/themeToggler/ThemeToggler' -import { LanguageToggler } from '@/components/languageToggler/LanguageToggler' +import { RootComponent } from '@/components/RootComponent' export interface RouterContextProps { auth: AppContextProps @@ -10,12 +9,5 @@ export interface RouterContextProps { } export const Route = createRootRouteWithContext()({ - component: () => ( -
- - -
- -
- ) + component: RootComponent }) diff --git a/src/routes/_authenticated.ts b/src/routes/_authenticated.ts new file mode 100644 index 0000000..c76299d --- /dev/null +++ b/src/routes/_authenticated.ts @@ -0,0 +1,21 @@ +import { createFileRoute, redirect } from '@tanstack/react-router' + +export const Route = createFileRoute('/_authenticated')({ + beforeLoad: ({ context, location }) => { + const { isAuthenticated, user } = context.auth + console.log('_authenticated -->', isAuthenticated, user) + + if (!isAuthenticated) { + throw redirect({ + to: '/login', + search: { + redirect: location.href + } + }) + } + + return { + username: context.auth.user + } + } +}) diff --git a/src/routes/_authenticated/dashboard.tsx b/src/routes/_authenticated/dashboard.tsx new file mode 100644 index 0000000..8eb5f97 --- /dev/null +++ b/src/routes/_authenticated/dashboard.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { DashboardComponent } from '@/components/dashboard/DashboardComponent' + +export const Route = createFileRoute('/_authenticated/dashboard')({ + component: () => +}) diff --git a/src/routes/_authenticated/profile.tsx b/src/routes/_authenticated/profile.tsx new file mode 100644 index 0000000..0bed0a5 --- /dev/null +++ b/src/routes/_authenticated/profile.tsx @@ -0,0 +1,6 @@ +import { createFileRoute } from '@tanstack/react-router' +import { ProfileComponent } from '@/components/profile/ProfileComponent' + +export const Route = createFileRoute('/_authenticated/profile')({ + component: () => +}) diff --git a/src/routes/index.tsx b/src/routes/index.tsx index eeaf1b5..fbf3caa 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,5 +1,3 @@ import { createFileRoute } from '@tanstack/react-router' -export const Route = createFileRoute('/')({ - component: () =>
Hello /!
-}) +export const Route = createFileRoute('/')() diff --git a/src/routes/login.tsx b/src/routes/login.tsx index 90ef509..07dbb2c 100644 --- a/src/routes/login.tsx +++ b/src/routes/login.tsx @@ -1,6 +1,11 @@ import { createFileRoute } from '@tanstack/react-router' import { LoginComponent } from '@/components/auth/LoginComponent' +import { z } from 'zod' export const Route = createFileRoute('/login')({ - component: () => + validateSearch: z.object({ + redirect: z.string().optional() + }) +}).update({ + component: LoginComponent }) diff --git a/src/utils/AppContext.tsx b/src/utils/AppContext.tsx index 7c245b5..2a2cbdb 100644 --- a/src/utils/AppContext.tsx +++ b/src/utils/AppContext.tsx @@ -1,6 +1,12 @@ -import { createContext, PropsWithChildren, useMemo, useState } from 'react' +import { createContext } from 'react' export interface User { + username: string + accessToken: string + userId: number +} + +export interface LoginRequestProps { username: string password: string } @@ -18,17 +24,3 @@ const appInitials: AppContextProps = { } export const AppContext = createContext(appInitials) - -export const AppProvider = (props: PropsWithChildren) => { - const [user, setUser] = useState(null) - const isAuthenticated = !!user - - const value = useMemo( - () => ({ isAuthenticated, user, setUser }), - [isAuthenticated, user] - ) - - return ( - {props.children} - ) -} diff --git a/src/utils/AppProvider.tsx b/src/utils/AppProvider.tsx new file mode 100644 index 0000000..5c6ccd9 --- /dev/null +++ b/src/utils/AppProvider.tsx @@ -0,0 +1,46 @@ +import { PropsWithChildren, useEffect, useMemo, useState } from 'react' +import { AppContext, User } from '@/utils/AppContext' + +export const AppProvider = (props: PropsWithChildren) => { + const [user, setUser] = useState(null) + const isAuthenticated = !!user + const persistedUserInfo = localStorage.getItem('user') + + useEffect(() => { + if (persistedUserInfo) { + setUser(JSON.parse(persistedUserInfo)) + } + }, [persistedUserInfo]) + + /* const initializeAuth = useCallback(async () => { + if (!persistedUserInfo) { + return + } + try { + const response = await axiosBase.post('/public/refresh') + const { accessToken } = response.data + + setAuthToken(accessToken) + + setUser({ + accessToken: accessToken, + ...(persistedUserInfo && JSON.parse(persistedUserInfo)) + }) + } catch (err) { + console.log('err', err) + } + }, [persistedUserInfo]) + + useEffect(() => { + initializeAuth() + }, [initializeAuth])*/ + + const value = useMemo( + () => ({ isAuthenticated, user, setUser }), + [isAuthenticated, user] + ) + + return ( + {props.children} + ) +} diff --git a/src/utils/apiDefaults.ts b/src/utils/apiDefaults.ts index 751ab89..2af484b 100644 --- a/src/utils/apiDefaults.ts +++ b/src/utils/apiDefaults.ts @@ -1,6 +1,36 @@ -import axios from 'axios' +import axios, { AxiosError, AxiosResponse } from 'axios' +import createAuthRefreshInterceptor from 'axios-auth-refresh' export const axiosBase = axios.create({ withCredentials: true, baseURL: 'https://localhost:3001' }) + +export interface TokenResponse { + accessToken: string +} + +export const setAuthToken = (token: string | null) => { + if (token) { + axiosBase.defaults.headers.common['Authorization'] = `Bearer ${token}` + } else { + delete axiosBase.defaults.headers.common['Authorization'] + } +} + +export const refreshAuth = async (failedRequest: AxiosError) => { + return axiosBase + .post('/public/refresh') + .then((tokenRefreshResponse: AxiosResponse) => { + const newAccessToken = tokenRefreshResponse.data.accessToken + setAuthToken(newAccessToken) + + if (failedRequest.response && failedRequest.response.config) { + failedRequest.response.config.headers['Authorization'] = + `Bearer ${newAccessToken}` + } + return Promise.resolve() + }) +} + +createAuthRefreshInterceptor(axiosBase, refreshAuth) diff --git a/src/utils/hooks/useApi.ts b/src/utils/hooks/useApi.ts new file mode 100644 index 0000000..f5d46b7 --- /dev/null +++ b/src/utils/hooks/useApi.ts @@ -0,0 +1,18 @@ +import { QueryKey, useQuery, UseQueryOptions } from '@tanstack/react-query' +import { axiosBase } from '@/utils/apiDefaults' + +const fetchData = async (endpoint: string): Promise => { + const { data } = await axiosBase.get(endpoint) + return data +} + +export const useApi = ( + endpoint: string, + options?: UseQueryOptions +) => { + return useQuery({ + queryKey: [endpoint], + queryFn: () => fetchData(endpoint), + ...options + }) +} diff --git a/src/utils/hooks/useLogin.ts b/src/utils/hooks/useLogin.ts new file mode 100644 index 0000000..9af91b5 --- /dev/null +++ b/src/utils/hooks/useLogin.ts @@ -0,0 +1,56 @@ +import { useMutation } from '@tanstack/react-query' +import { LoginRequestProps, User } from '@/utils/AppContext' +import { axiosBase, setAuthToken } from '@/utils/apiDefaults' +import { useAuth } from '@/utils/hooks/useAuth' +import { AxiosError } from 'axios' +import { toast } from 'react-toastify' +import type { CustomAxiosRequestConfig } from 'axios-auth-refresh/dist/utils' + +interface ErrorResponse { + error: string +} + +export const useLogin = () => { + const { setUser } = useAuth() + + const customAxiosRequestConfig: CustomAxiosRequestConfig = { + skipAuthRefresh: true + } + + return useMutation({ + mutationFn: ({ username, password }: LoginRequestProps) => { + return axiosBase.post( + '/login', + { username, password }, + customAxiosRequestConfig + ) + }, + onSuccess: (res) => { + const { username, userId, accessToken } = res.data + + const userData = { + username, + userId + } + + localStorage.setItem('user', JSON.stringify(userData)) + + setUser({ + username, + accessToken, + userId + }) + + setAuthToken(accessToken) + }, + onError: (err: AxiosError) => { + let errMsg = 'Network Error' + + if (err.response && err.response.status === 401) { + errMsg = err.response.data.error + } + + toast.error(errMsg) + } + }) +} diff --git a/src/utils/hooks/useLogout.ts b/src/utils/hooks/useLogout.ts new file mode 100644 index 0000000..270a72a --- /dev/null +++ b/src/utils/hooks/useLogout.ts @@ -0,0 +1,21 @@ +import { useMutation } from '@tanstack/react-query' +import { axiosBase, setAuthToken } from '@/utils/apiDefaults' +import type { CustomAxiosRequestConfig } from 'axios-auth-refresh/dist/utils' +import { useAuth } from '@/utils/hooks/useAuth' + +export const useLogout = () => { + const { setUser } = useAuth() + + const customAxiosRequestConfig: CustomAxiosRequestConfig = { + skipAuthRefresh: true + } + + return useMutation({ + mutationFn: () => axiosBase.post('/logout', {}, customAxiosRequestConfig), + onSuccess: () => { + setUser(null) + localStorage.removeItem('user') + setAuthToken(null) + } + }) +} From bf418905b51b0d4f7352a6fc3b60fa0c456c4c51 Mon Sep 17 00:00:00 2001 From: behcetilhan Date: Sat, 27 Apr 2024 22:04:20 +0200 Subject: [PATCH 08/12] refresh token handling --- .eslintrc.cjs | 1 + src/App.tsx | 46 ++----------------- src/components/RootComponent.tsx | 26 +++++++++-- src/components/auth/LoginComponent.tsx | 14 ------ .../dashboard/DashboardComponent.tsx | 33 ++++++++----- src/components/profile/ProfileComponent.tsx | 11 +++-- src/main.tsx | 36 +++++++++++++-- src/routes/_authenticated.ts | 24 ++++++++-- src/routes/index.tsx | 18 +++++++- src/utils/AppContext.tsx | 9 ++-- src/utils/AppProvider.tsx | 40 +++------------- src/utils/apiDefaults.ts | 20 +++++++- src/utils/hooks/useApi.ts | 18 -------- .../hooks/{useAuth.ts => useAppContext.ts} | 2 +- src/utils/hooks/useLogin.ts | 22 ++++----- src/utils/hooks/useLogout.ts | 9 ++-- 16 files changed, 171 insertions(+), 158 deletions(-) delete mode 100644 src/utils/hooks/useApi.ts rename src/utils/hooks/{useAuth.ts => useAppContext.ts} (86%) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index baa3492..f877798 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -24,6 +24,7 @@ module.exports = { '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/no-unsafe-return':'off', '@typescript-eslint/no-floating-promises':'off', + '@typescript-eslint/no-misused-promises':'off', 'react-refresh/only-export-components': [ 'warn', {allowConstantExport: true}, diff --git a/src/App.tsx b/src/App.tsx index 7c47be3..e39945e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,44 +1,8 @@ -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { - createRouter, - ErrorComponent, - RouterProvider -} from '@tanstack/react-router' -import { useAuth } from '@/utils/hooks/useAuth' -import { routeTree } from '@/routeTree.gen' -import { useEffect } from 'react' +import { Router, RouterProvider } from '@tanstack/react-router' +import { useAppContext } from '@/utils/hooks/useAppContext' -const queryClient = new QueryClient() +export const App = ({ router }: { router: Router }) => { + const auth = useAppContext() -declare module '@tanstack/react-router' { - interface Register { - router: typeof router - } -} - -const router = createRouter({ - routeTree, - context: { - auth: undefined!, - queryClient - }, - defaultPreload: 'intent', - defaultPreloadStaleTime: 0, - defaultPendingComponent: () => ...loading..., - defaultErrorComponent: ({ error }) => , - defaultNotFoundComponent: () => is a 404 -}) - -export const App = () => { - const auth = useAuth() - - useEffect(() => { - router.invalidate() - }, [auth]) - - return ( - - - - ) + return } diff --git a/src/components/RootComponent.tsx b/src/components/RootComponent.tsx index 6b63cc5..9de4af7 100644 --- a/src/components/RootComponent.tsx +++ b/src/components/RootComponent.tsx @@ -1,12 +1,32 @@ import { ThemeToggler } from '@/components/themeToggler/ThemeToggler' import { LanguageToggler } from '@/components/languageToggler/LanguageToggler' -import { Outlet } from '@tanstack/react-router' +import { Outlet, useRouter } from '@tanstack/react-router' +import { Button, Stack } from '@mui/material' +import { setAuthToken, tokenGlobal } from '@/utils/apiDefaults' export const RootComponent = () => { + const router = useRouter() return (
- - + + {tokenGlobal && ( + + )} + + +
diff --git a/src/components/auth/LoginComponent.tsx b/src/components/auth/LoginComponent.tsx index c5a8d89..2b2bc51 100644 --- a/src/components/auth/LoginComponent.tsx +++ b/src/components/auth/LoginComponent.tsx @@ -3,17 +3,10 @@ import { loginSchema } from '@/components/auth/loginSchema' import { toFormikValidationSchema } from 'zod-formik-adapter' import { Button, Container, Stack, TextField } from '@mui/material' import { useTranslation } from 'react-i18next' -import { useAuth } from '@/utils/hooks/useAuth' -import { useRouter } from '@tanstack/react-router' -import { Route } from '@/routes/login' -import { useLayoutEffect } from 'react' import { useLogin } from '@/utils/hooks/useLogin' export const LoginComponent = () => { const { t } = useTranslation() - const { isAuthenticated } = useAuth() - const { redirect } = Route.useSearch() - const router = useRouter() const loginMutation = useLogin() @@ -33,13 +26,6 @@ export const LoginComponent = () => { } }) - useLayoutEffect(() => { - if (!isAuthenticated) { - return - } - redirect ? router.history.push(redirect) : router.history.push('/dashboard') - }, [isAuthenticated, redirect, router.history]) - return ( diff --git a/src/components/dashboard/DashboardComponent.tsx b/src/components/dashboard/DashboardComponent.tsx index fc1181c..0917a2e 100644 --- a/src/components/dashboard/DashboardComponent.tsx +++ b/src/components/dashboard/DashboardComponent.tsx @@ -1,8 +1,9 @@ -import { Button, Stack } from '@mui/material' +import { Avatar, Box, Button, Container, Stack } from '@mui/material' import { useNavigate } from '@tanstack/react-router' -import { useAuth } from '@/utils/hooks/useAuth' +import { useAppContext } from '@/utils/hooks/useAppContext' import { useLogout } from '@/utils/hooks/useLogout' -import { useApi } from '@/utils/hooks/useApi' +import { axiosBase } from '@/utils/apiDefaults' +import { useQuery } from '@tanstack/react-query' interface ProtectedDataProps { id: number @@ -11,19 +12,27 @@ interface ProtectedDataProps { } export const DashboardComponent = () => { - const { user } = useAuth() + const { user } = useAppContext() const navigate = useNavigate() const { mutate: logout } = useLogout() - const { data, refetch } = useApi('/protected', { - queryKey: ['protectedDataExample'], - enabled: !!user + const { data: protectedData, refetch } = useQuery({ + queryKey: ['protectedExample'], + queryFn: async () => { + return await axiosBase.get('/protected') + } }) return ( - <> -
dashboard user: {user?.username}
-
{data?.secret}
+ + Logged in User Info + {user && ( + + + {user.username} + + )} + {protectedData?.data.secret} - + - + ) } diff --git a/src/components/profile/ProfileComponent.tsx b/src/components/profile/ProfileComponent.tsx index 50587e4..e59c943 100644 --- a/src/components/profile/ProfileComponent.tsx +++ b/src/components/profile/ProfileComponent.tsx @@ -1,17 +1,18 @@ -import { Button } from '@mui/material' +import { Button, Container } from '@mui/material' import { useNavigate } from '@tanstack/react-router' export const ProfileComponent = () => { const navigate = useNavigate() return ( - <> -
profile page
+ +
Another protected route example
- +
) } diff --git a/src/main.tsx b/src/main.tsx index 388494a..85ca738 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -7,6 +7,30 @@ import { initI18n } from '@/i18n' import { AppProvider } from '@/utils/AppProvider' import { ToastContainer } from 'react-toastify' import 'react-toastify/dist/ReactToastify.min.css' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { createRouter, ErrorComponent } from '@tanstack/react-router' +import { routeTree } from '@/routeTree.gen' + +const queryClient = new QueryClient() + +declare module '@tanstack/react-router' { + interface Register { + router: typeof router + } +} + +const router = createRouter({ + routeTree, + context: { + auth: undefined!, + queryClient + }, + defaultPreload: 'intent', + defaultPreloadStaleTime: 0, + defaultPendingComponent: () => ...loading..., + defaultErrorComponent: ({ error }) => , + defaultNotFoundComponent: () => is a 404 +}) const rootElement = document.getElementById('appRoot')! @@ -17,11 +41,13 @@ if (!rootElement.innerHTML) { root.render( - - - - - + + + + + + + ) diff --git a/src/routes/_authenticated.ts b/src/routes/_authenticated.ts index c76299d..bebc3cc 100644 --- a/src/routes/_authenticated.ts +++ b/src/routes/_authenticated.ts @@ -1,11 +1,12 @@ import { createFileRoute, redirect } from '@tanstack/react-router' +import { getRefreshToken, setAuthToken, tokenGlobal } from '@/utils/apiDefaults' export const Route = createFileRoute('/_authenticated')({ - beforeLoad: ({ context, location }) => { - const { isAuthenticated, user } = context.auth - console.log('_authenticated -->', isAuthenticated, user) + beforeLoad: async ({ context, location }) => { + const { setUser } = context.auth + const persistedUserInfo = localStorage.getItem('user') - if (!isAuthenticated) { + if (!persistedUserInfo) { throw redirect({ to: '/login', search: { @@ -14,6 +15,21 @@ export const Route = createFileRoute('/_authenticated')({ }) } + try { + const accessToken = await getRefreshToken() + + if (tokenGlobal !== accessToken) { + setAuthToken(accessToken) + } + + setUser({ + ...(persistedUserInfo && JSON.parse(persistedUserInfo)) + }) + } catch (err) { + console.error('err', err) + redirect({ to: '/login' }) + } + return { username: context.auth.user } diff --git a/src/routes/index.tsx b/src/routes/index.tsx index fbf3caa..6fcfef5 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,3 +1,17 @@ -import { createFileRoute } from '@tanstack/react-router' +import { createFileRoute, redirect } from '@tanstack/react-router' +import { DashboardComponent } from '@/components/dashboard/DashboardComponent' -export const Route = createFileRoute('/')() +export const Route = createFileRoute('/')({ + beforeLoad: ({ context }) => { + if (context.auth.user) { + throw redirect({ + to: '/login' + }) + } + + throw redirect({ + to: '/dashboard' + }) + }, + component: DashboardComponent +}) diff --git a/src/utils/AppContext.tsx b/src/utils/AppContext.tsx index 2a2cbdb..c86a0e4 100644 --- a/src/utils/AppContext.tsx +++ b/src/utils/AppContext.tsx @@ -1,24 +1,25 @@ import { createContext } from 'react' -export interface User { +export interface LoginResponseProps { username: string - accessToken: string userId: number + accessToken: string | undefined + avatarURL: string } +export interface User extends Omit {} + export interface LoginRequestProps { username: string password: string } export interface AppContextProps { - isAuthenticated: boolean setUser: (user: User | null) => void user: User | null } const appInitials: AppContextProps = { - isAuthenticated: false, setUser: () => {}, user: null } diff --git a/src/utils/AppProvider.tsx b/src/utils/AppProvider.tsx index 5c6ccd9..dc5c215 100644 --- a/src/utils/AppProvider.tsx +++ b/src/utils/AppProvider.tsx @@ -1,43 +1,15 @@ -import { PropsWithChildren, useEffect, useMemo, useState } from 'react' +import { PropsWithChildren, useMemo, useState } from 'react' import { AppContext, User } from '@/utils/AppContext' export const AppProvider = (props: PropsWithChildren) => { const [user, setUser] = useState(null) - const isAuthenticated = !!user - const persistedUserInfo = localStorage.getItem('user') - - useEffect(() => { - if (persistedUserInfo) { - setUser(JSON.parse(persistedUserInfo)) - } - }, [persistedUserInfo]) - - /* const initializeAuth = useCallback(async () => { - if (!persistedUserInfo) { - return - } - try { - const response = await axiosBase.post('/public/refresh') - const { accessToken } = response.data - - setAuthToken(accessToken) - - setUser({ - accessToken: accessToken, - ...(persistedUserInfo && JSON.parse(persistedUserInfo)) - }) - } catch (err) { - console.log('err', err) - } - }, [persistedUserInfo]) - - useEffect(() => { - initializeAuth() - }, [initializeAuth])*/ const value = useMemo( - () => ({ isAuthenticated, user, setUser }), - [isAuthenticated, user] + () => ({ + user, + setUser + }), + [user] ) return ( diff --git a/src/utils/apiDefaults.ts b/src/utils/apiDefaults.ts index 2af484b..5c27091 100644 --- a/src/utils/apiDefaults.ts +++ b/src/utils/apiDefaults.ts @@ -10,7 +10,25 @@ export interface TokenResponse { accessToken: string } -export const setAuthToken = (token: string | null) => { +export let tokenGlobal: string | undefined = undefined + +export const getRefreshToken = async () => { + if (tokenGlobal) { + return tokenGlobal + } + + try { + const refreshedToken = + await axiosBase.post('/public/refresh') + + return refreshedToken.data.accessToken + } catch (err) { + console.error('error getRefreshToken', err) + } +} + +export const setAuthToken = (token: string | undefined) => { + tokenGlobal = token if (token) { axiosBase.defaults.headers.common['Authorization'] = `Bearer ${token}` } else { diff --git a/src/utils/hooks/useApi.ts b/src/utils/hooks/useApi.ts deleted file mode 100644 index f5d46b7..0000000 --- a/src/utils/hooks/useApi.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { QueryKey, useQuery, UseQueryOptions } from '@tanstack/react-query' -import { axiosBase } from '@/utils/apiDefaults' - -const fetchData = async (endpoint: string): Promise => { - const { data } = await axiosBase.get(endpoint) - return data -} - -export const useApi = ( - endpoint: string, - options?: UseQueryOptions -) => { - return useQuery({ - queryKey: [endpoint], - queryFn: () => fetchData(endpoint), - ...options - }) -} diff --git a/src/utils/hooks/useAuth.ts b/src/utils/hooks/useAppContext.ts similarity index 86% rename from src/utils/hooks/useAuth.ts rename to src/utils/hooks/useAppContext.ts index 2c84882..651020e 100644 --- a/src/utils/hooks/useAuth.ts +++ b/src/utils/hooks/useAppContext.ts @@ -1,7 +1,7 @@ import { useContext } from 'react' import { AppContext } from '@/utils/AppContext' -export const useAuth = () => { +export const useAppContext = () => { const context = useContext(AppContext) if (!context) { diff --git a/src/utils/hooks/useLogin.ts b/src/utils/hooks/useLogin.ts index 9af91b5..717577e 100644 --- a/src/utils/hooks/useLogin.ts +++ b/src/utils/hooks/useLogin.ts @@ -1,17 +1,19 @@ import { useMutation } from '@tanstack/react-query' -import { LoginRequestProps, User } from '@/utils/AppContext' +import { LoginRequestProps, LoginResponseProps } from '@/utils/AppContext' import { axiosBase, setAuthToken } from '@/utils/apiDefaults' -import { useAuth } from '@/utils/hooks/useAuth' +import { useAppContext } from '@/utils/hooks/useAppContext' import { AxiosError } from 'axios' import { toast } from 'react-toastify' import type { CustomAxiosRequestConfig } from 'axios-auth-refresh/dist/utils' +import { useRouter } from '@tanstack/react-router' interface ErrorResponse { error: string } export const useLogin = () => { - const { setUser } = useAuth() + const { setUser } = useAppContext() + const router = useRouter() const customAxiosRequestConfig: CustomAxiosRequestConfig = { skipAuthRefresh: true @@ -19,29 +21,27 @@ export const useLogin = () => { return useMutation({ mutationFn: ({ username, password }: LoginRequestProps) => { - return axiosBase.post( + return axiosBase.post( '/login', { username, password }, customAxiosRequestConfig ) }, onSuccess: (res) => { - const { username, userId, accessToken } = res.data + const { username, userId, accessToken, avatarURL } = res.data const userData = { username, - userId + userId, + avatarURL } localStorage.setItem('user', JSON.stringify(userData)) - setUser({ - username, - accessToken, - userId - }) + setUser(userData) setAuthToken(accessToken) + router.history.push('/dashboard') }, onError: (err: AxiosError) => { let errMsg = 'Network Error' diff --git a/src/utils/hooks/useLogout.ts b/src/utils/hooks/useLogout.ts index 270a72a..6e247bc 100644 --- a/src/utils/hooks/useLogout.ts +++ b/src/utils/hooks/useLogout.ts @@ -1,10 +1,12 @@ import { useMutation } from '@tanstack/react-query' import { axiosBase, setAuthToken } from '@/utils/apiDefaults' import type { CustomAxiosRequestConfig } from 'axios-auth-refresh/dist/utils' -import { useAuth } from '@/utils/hooks/useAuth' +import { useAppContext } from '@/utils/hooks/useAppContext' +import { useRouter } from '@tanstack/react-router' export const useLogout = () => { - const { setUser } = useAuth() + const { setUser } = useAppContext() + const router = useRouter() const customAxiosRequestConfig: CustomAxiosRequestConfig = { skipAuthRefresh: true @@ -15,7 +17,8 @@ export const useLogout = () => { onSuccess: () => { setUser(null) localStorage.removeItem('user') - setAuthToken(null) + setAuthToken(undefined) + router.history.push('/login') } }) } From 8c5daf5beb7215a167532730fc8a3e4748567c75 Mon Sep 17 00:00:00 2001 From: behcetilhan Date: Sat, 27 Apr 2024 23:29:12 +0200 Subject: [PATCH 09/12] readme init --- README.md | 2 +- index.html | 2 +- public/favico.svg | 63 ++++++++++++++++++++++++++++++++++++++++++++++ public/rrLogo.png | Bin 0 -> 36322 bytes public/vite.svg | 1 - 5 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 public/favico.svg create mode 100644 public/rrLogo.png delete mode 100644 public/vite.svg diff --git a/README.md b/README.md index 60c811f..df5f3dc 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# ReactRover: React + TypeScript + Vite +# ReactRover diff --git a/index.html b/index.html index 8c9ed38..d0d9346 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - + ReactRover diff --git a/public/favico.svg b/public/favico.svg new file mode 100644 index 0000000..e299be6 --- /dev/null +++ b/public/favico.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/rrLogo.png b/public/rrLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..b02c1519e238718dde671de8b58334fa3543bdad GIT binary patch literal 36322 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 tfF61{j_DBqJ@jxK(<1