improved AuthProvider
This commit is contained in:
@@ -3,7 +3,7 @@ import {
|
|||||||
createBrowserRouter,
|
createBrowserRouter,
|
||||||
Navigate,
|
Navigate,
|
||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import Chat from './pages/Chat.tsx';
|
import Chat from './pages/Chat.tsx';
|
||||||
import Login from './pages/Login.tsx';
|
import Login from './pages/Login.tsx';
|
||||||
import Signup from './pages/Signup.tsx';
|
import Signup from './pages/Signup.tsx';
|
||||||
@@ -11,7 +11,9 @@ import Settings from './pages/Settings.tsx';
|
|||||||
import Lost from './pages/404.tsx';
|
import Lost from './pages/404.tsx';
|
||||||
import { AuthContext } from './utils/AuthProvider.tsx';
|
import { AuthContext } from './utils/AuthProvider.tsx';
|
||||||
import ProtectedRoutes from './utils/ProtectedRoutes.tsx';
|
import ProtectedRoutes from './utils/ProtectedRoutes.tsx';
|
||||||
|
import PublicRoute from '@/utils/PublicRoute.tsx';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
export const axiosClient = axios.create({
|
export const axiosClient = axios.create({
|
||||||
baseURL: import.meta.env.VITE_BASE_URL,
|
baseURL: import.meta.env.VITE_BASE_URL,
|
||||||
});
|
});
|
||||||
@@ -34,12 +36,17 @@ const router = createBrowserRouter([
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
element: <PublicRoute />,
|
||||||
element: <Login />,
|
children: [
|
||||||
},
|
{
|
||||||
{
|
path: '/login',
|
||||||
path: '/signup',
|
element: <Login />,
|
||||||
element: <Signup />,
|
},
|
||||||
|
{
|
||||||
|
path: '/signup',
|
||||||
|
element: <Signup />,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '*',
|
path: '*',
|
||||||
@@ -48,12 +55,38 @@ const router = createBrowserRouter([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [authorized, setAuthorized] = useState<boolean | null>(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 (
|
return (
|
||||||
<AuthContext.Provider value={{ authorized, setAuthorized }}>
|
<AuthContext.Provider value={{ authorized, isLoading, setAuthorized }}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
</AuthContext.Provider>
|
</AuthContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { createContext } from 'react';
|
import { createContext } from 'react';
|
||||||
|
|
||||||
type AuthContextType = {
|
type AuthContextType = {
|
||||||
authorized: boolean | null;
|
authorized: boolean;
|
||||||
|
isLoading: boolean;
|
||||||
setAuthorized: (value: boolean) => void;
|
setAuthorized: (value: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AuthContext = createContext<AuthContextType>({
|
export const AuthContext = createContext<AuthContextType>({
|
||||||
authorized: null,
|
authorized: false,
|
||||||
|
isLoading: true,
|
||||||
setAuthorized: () => {},
|
setAuthorized: () => {},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Navigate, Outlet } from 'react-router-dom';
|
import { Navigate, Outlet } from 'react-router-dom';
|
||||||
import { useState, useEffect, useContext } from 'react';
|
import { useState, useEffect, useContext } from 'react';
|
||||||
import Cookie from 'js-cookie';
|
|
||||||
import { AuthContext } from './AuthProvider.tsx';
|
import { AuthContext } from './AuthProvider.tsx';
|
||||||
import LoadingScreen from '../components/LoadingScreen.tsx';
|
import LoadingScreen from '../components/LoadingScreen.tsx';
|
||||||
import { axiosClient } from '../App.tsx';
|
import { axiosClient } from '../App.tsx';
|
||||||
@@ -11,37 +10,24 @@ export type UsernameType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function ProtectedRoutes() {
|
function ProtectedRoutes() {
|
||||||
const { authorized, setAuthorized } = useContext(AuthContext);
|
const { authorized, isLoading } = useContext(AuthContext);
|
||||||
const [user, setUser] = useState<UsernameType>({
|
const [user, setUser] = useState<UsernameType>({
|
||||||
username: null,
|
username: null,
|
||||||
user_id: null,
|
user_id: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function validateToken() {
|
if (authorized) {
|
||||||
const token = Cookie.get('token');
|
|
||||||
if (!token) {
|
|
||||||
setAuthorized(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
axiosClient
|
axiosClient
|
||||||
.get('/api/auth/validate', { withCredentials: true })
|
.get('/api/auth/validate', { withCredentials: true })
|
||||||
.then(async (res) => {
|
.then((res) => {
|
||||||
setUser(res.data);
|
setUser(res.data);
|
||||||
console.log('User: ', res.data);
|
|
||||||
setAuthorized(true);
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(console.error);
|
||||||
setAuthorized(false);
|
|
||||||
console.log(err);
|
|
||||||
console.log('Unauthorized');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
validateToken();
|
}, [authorized]);
|
||||||
}, [setAuthorized]);
|
|
||||||
|
|
||||||
if (authorized === null) {
|
if (isLoading) {
|
||||||
return <LoadingScreen />;
|
return <LoadingScreen />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
client/src/utils/PublicRoute.tsx
Normal file
16
client/src/utils/PublicRoute.tsx
Normal file
@@ -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 <LoadingScreen />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return authorized ? <Navigate to="/chat" replace /> : <Outlet />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PublicRoute;
|
||||||
Reference in New Issue
Block a user