diff --git a/client/src/App.tsx b/client/src/App.tsx index e5f3b04..f834bf4 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -3,7 +3,7 @@ import { createBrowserRouter, Navigate, } from 'react-router-dom'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import Chat from './pages/Chat.tsx'; import Login from './pages/Login.tsx'; import Signup from './pages/Signup.tsx'; @@ -11,7 +11,9 @@ import Settings from './pages/Settings.tsx'; import Lost from './pages/404.tsx'; import { AuthContext } from './utils/AuthProvider.tsx'; import ProtectedRoutes from './utils/ProtectedRoutes.tsx'; +import PublicRoute from '@/utils/PublicRoute.tsx'; import axios from 'axios'; +import Cookies from 'js-cookie'; export const axiosClient = axios.create({ baseURL: import.meta.env.VITE_BASE_URL, }); @@ -34,12 +36,17 @@ const router = createBrowserRouter([ ], }, { - path: '/login', - element: , - }, - { - path: '/signup', - element: , + element: , + children: [ + { + path: '/login', + element: , + }, + { + path: '/signup', + element: , + }, + ], }, { path: '*', @@ -48,12 +55,38 @@ const router = createBrowserRouter([ ]); function App() { - const [authorized, setAuthorized] = useState(null); + const [authorized, setAuthorized] = useState(false); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + async function validateToken() { + const token = Cookies.get('token'); + if (!token) { + setAuthorized(false); + setIsLoading(false); + return; + } + + try { + await axiosClient.get('/api/auth/validate', { + withCredentials: true, + }); + setAuthorized(true); + } catch (e) { + setAuthorized(false); + console.log('Failed to validate token: ', e); + } finally { + setIsLoading(false); + } + } + + validateToken(); + }, []); + return ( - + ); } - export default App; diff --git a/client/src/utils/AuthProvider.tsx b/client/src/utils/AuthProvider.tsx index b86dba3..991d944 100644 --- a/client/src/utils/AuthProvider.tsx +++ b/client/src/utils/AuthProvider.tsx @@ -1,10 +1,13 @@ import { createContext } from 'react'; type AuthContextType = { - authorized: boolean | null; + authorized: boolean; + isLoading: boolean; setAuthorized: (value: boolean) => void; }; + export const AuthContext = createContext({ - authorized: null, + authorized: false, + isLoading: true, setAuthorized: () => {}, }); diff --git a/client/src/utils/ProtectedRoutes.tsx b/client/src/utils/ProtectedRoutes.tsx index d33892c..f289cd4 100644 --- a/client/src/utils/ProtectedRoutes.tsx +++ b/client/src/utils/ProtectedRoutes.tsx @@ -1,6 +1,5 @@ import { Navigate, Outlet } from 'react-router-dom'; import { useState, useEffect, useContext } from 'react'; -import Cookie from 'js-cookie'; import { AuthContext } from './AuthProvider.tsx'; import LoadingScreen from '../components/LoadingScreen.tsx'; import { axiosClient } from '../App.tsx'; @@ -11,37 +10,24 @@ export type UsernameType = { }; function ProtectedRoutes() { - const { authorized, setAuthorized } = useContext(AuthContext); + const { authorized, isLoading } = useContext(AuthContext); const [user, setUser] = useState({ username: null, user_id: null, }); useEffect(() => { - function validateToken() { - const token = Cookie.get('token'); - if (!token) { - setAuthorized(false); - return; - } - + if (authorized) { axiosClient .get('/api/auth/validate', { withCredentials: true }) - .then(async (res) => { + .then((res) => { setUser(res.data); - console.log('User: ', res.data); - setAuthorized(true); }) - .catch((err) => { - setAuthorized(false); - console.log(err); - console.log('Unauthorized'); - }); + .catch(console.error); } - validateToken(); - }, [setAuthorized]); + }, [authorized]); - if (authorized === null) { + if (isLoading) { return ; } diff --git a/client/src/utils/PublicRoute.tsx b/client/src/utils/PublicRoute.tsx new file mode 100644 index 0000000..d784e91 --- /dev/null +++ b/client/src/utils/PublicRoute.tsx @@ -0,0 +1,16 @@ +import { Navigate, Outlet } from 'react-router-dom'; +import { useContext } from 'react'; +import { AuthContext } from './AuthProvider'; +import LoadingScreen from '../components/LoadingScreen'; + +function PublicRoute() { + const { authorized, isLoading } = useContext(AuthContext); + + if (isLoading) { + return ; + } + + return authorized ? : ; +} + +export default PublicRoute;