diff --git a/client/src/App.tsx b/client/src/App.tsx index 7fc96c3..3d98dae 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -2,12 +2,13 @@ import React from 'react'; import { Route, Routes } from 'react-router-dom'; import MainLayout from './pages/MainLayout'; import ProtectedRoute from './pages/ProtectedRoute'; +import LoginPage from './pages/LoginPage'; function App() { return (
- login
} /> + } /> }> }> diff --git a/client/src/api/api.ts b/client/src/api/api.ts index 0fee327..c691e11 100644 --- a/client/src/api/api.ts +++ b/client/src/api/api.ts @@ -1,5 +1,8 @@ import axios from 'axios'; import { Access, Auth } from '../types/auth'; +import { User } from '../types/user'; +import { AuthService } from '../services/auth'; +import axiosRetry from 'axios-retry'; const baseURL = `${process.env.REACT_APP_HTTP_PROTOCOL}://${process.env.REACT_APP_API_URL}/api/v1`; @@ -11,20 +14,75 @@ const base = axios.create({ }, }); -// base.interceptors.request.use((config) => { -// const token = localStorage.getItem('accessToken'); -// if (token) { -// config.headers.Authorization = `Bearer ${token}`; -// } -// return config; -// }); +base.interceptors.request.use((config) => { + const token = localStorage.getItem('accessToken'); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + return config; +}); + +axiosRetry(base, { + retries: 3, + retryDelay: (retryCount: number) => { + console.log(`retry attempt: ${retryCount}`); + return retryCount * 2000; + }, + retryCondition: async (error: any) => { + if (error.code === 'ERR_CANCELED') { + return true; + } + return false; + }, +}); + +base.interceptors.response.use( + (response) => { + return response; + }, + async function (error) { + console.log('error', error); + const originalRequest = error.response.config; + console.log('originalRequest._retry', originalRequest); + const urlTokens = error?.request?.responseURL.split('/'); + const url = urlTokens[urlTokens.length - 1]; + console.log('url', url); + if ( + error.response.status === 401 && + !(originalRequest?._retry != null) && + url !== 'login' && + url !== 'refresh' && + url !== 'logout' + ) { + originalRequest._retry = true; + const res = await AuthService.refresh().catch(async () => { + await AuthService.logout(); + }); + console.log('res', res); + return await base(originalRequest); + } + return await Promise.reject(error); + } +); const api = { + // auth async login(auth: Auth): Promise { console.log(auth); const response = await base.post('/auth', auth); return response.data; }, + + async refreshToken(): Promise { + const response = await base.post('/auth/refresh'); + return response.data; + }, + + // user + async getProfile(): Promise { + const response = await base.get('/profile'); + return response.data; + }, }; export default api; diff --git a/client/src/pages/MainLayout.tsx b/client/src/pages/MainLayout.tsx index 2933a89..599a88b 100644 --- a/client/src/pages/MainLayout.tsx +++ b/client/src/pages/MainLayout.tsx @@ -9,6 +9,8 @@ import RunningProcessesPage from './RunningProcessesPage'; import AccountsPage from './AccountsPage'; import EventsListPage from './EventsListPage'; import ConfigurationPage from './ConfigurationPage'; +import { useSetUserSelector } from '../store/user'; +import { UserService } from '../services/user'; export default function MainLayout() { const navigate = useNavigate(); @@ -19,6 +21,8 @@ export default function MainLayout() { const [width, setWidth] = useState('15%'); const [collapsedWidth, setCollapsedWidth] = useState(50); + const setUser = useSetUserSelector(); + const calculateWidths = () => { const windowWidth = window.innerWidth; const expanded = Math.min(Math.max(windowWidth * 0.15, 180), 240); @@ -54,6 +58,21 @@ export default function MainLayout() { navigate(key); } + useEffect(() => { + const token = localStorage.getItem('accessToken'); + if (!token) { + navigate('/login'); + } else { + if (localStorage.getItem('user')) { + setUser(JSON.parse(localStorage.getItem('user') as string)); + } else { + UserService.getProfile().then((user) => { + setUser(user); + }); + } + } + }, []); + return ( { + const user = api.getProfile(); + + return user; + } +} diff --git a/client/src/store/user.ts b/client/src/store/user.ts index f9c9517..137d3e8 100644 --- a/client/src/store/user.ts +++ b/client/src/store/user.ts @@ -11,6 +11,7 @@ type UserStoreState = { type UserStoreActions = { setUser: (user: User) => void; + removeUser: () => void; }; type UserStore = UserStoreState & UserStoreActions; @@ -22,6 +23,7 @@ export const useUserStore = create()( user: userInfo != null ? JSON.parse(userInfo) : ({} as User), loading: false, setUser: (user: User) => set({ user }), + removeUser: () => set({ user: {} as User }), }), { name: 'userInfo' } )