diff --git a/index.html b/index.html index e8729f3..60139b2 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,10 @@ FLApp - + diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx index 4359953..58afd70 100644 --- a/src/components/App/App.tsx +++ b/src/components/App/App.tsx @@ -1,45 +1,73 @@ import './App.scss'; import { useDispatch, useSelector } from 'react-redux'; -import { useCallback, useEffect } from 'react'; +import { useEffect } from 'react'; +import { FetchBaseQueryError } from '@reduxjs/toolkit/query'; import Routes from '../../routes'; import { AppContextProvider } from '../../context/AppContext'; -import { useRefreshTokenMutation } from '../../store/rtk/tokensApi'; +import { + useRefreshTokenMutation, + useVerifyTokenMutation, +} from '../../store/rtk/tokensApi'; import { clearStorage, readStorage } from '../../store/slices/tokens'; import { useGetUserMutation } from '../../store/rtk/userApi'; -import { store, AppDispatch, RootState } from '../../store'; +import type { AppDispatch, RootState } from '../../store'; import Loader from '../Loader/Loader'; +import { stopLoading } from '../../store/slices/user'; function App() { const dispatch = useDispatch(); const { refresh, access } = useSelector((state: RootState) => state.tokens); const { isLoading } = useSelector((state: RootState) => state.user); const [updateToken] = useRefreshTokenMutation(); - const [getUser, { isError }] = useGetUserMutation(); + const [getUser] = useGetUserMutation(); + const [verifyToken] = useVerifyTokenMutation(); - const readInitialData = useCallback(() => { - if (!isLoading) { - if (!access) { - dispatch(readStorage()); - } else { - getUser(null) - .unwrap() - .then(() => { - if (isError && store.getState().user.requestCounter === 0) { - if (refresh && access) { - updateToken({ refresh }) - .unwrap() - .catch(() => dispatch(clearStorage())); - } - } - }) - .catch(() => {}); - } - } - }, [access, dispatch, getUser, isError, isLoading, refresh, updateToken]); + function isFetchBaseQueryError(error: unknown): error is FetchBaseQueryError { + return typeof error === 'object' && error != null && 'status' in error; + } useEffect(() => { - readInitialData(); - }, [readInitialData]); + if (!access) { + dispatch(readStorage()); + dispatch(stopLoading()); + } else { + verifyToken(access) + .then((verification) => { + if (isFetchBaseQueryError(verification)) { + if (refresh) { + verifyToken(refresh) + .then((refreshVerification) => { + if (isFetchBaseQueryError(refreshVerification)) { + dispatch(clearStorage()); + } else { + getUser(null) + .then((data) => { + if (isFetchBaseQueryError(data)) { + updateToken({ refresh }) + .unwrap() + .catch(() => dispatch(clearStorage())); + } + }) + .catch(() => {}); + } + }) + .catch(() => {}); + } + } else { + getUser(null) + .then((data) => { + if (isFetchBaseQueryError(data)) { + updateToken({ refresh }) + .unwrap() + .catch(() => dispatch(clearStorage())); + } + }) + .catch(() => {}); + } + }) + .catch(() => {}); + } + }, [dispatch, getUser, access, refresh, updateToken, verifyToken]); return isLoading ? ( diff --git a/src/pages/Welcome/Welcome.tsx b/src/pages/Welcome/Welcome.tsx index 6725ea4..eb46d94 100644 --- a/src/pages/Welcome/Welcome.tsx +++ b/src/pages/Welcome/Welcome.tsx @@ -1,11 +1,18 @@ import './Welcome.scss'; import { Link } from 'react-router-dom'; +import { useSelector } from 'react-redux'; import Button from '../../components/Button/Button'; import Carousel from '../../components/Carousel/Carousel'; import RoutesPath from '../../constants/enums/routesPath'; +import type { RootState } from '../../store'; +import Loader from '../../components/Loader/Loader'; function Welcome() { - return ( + const { isLoading } = useSelector((state: RootState) => state.user); + + return isLoading ? ( + + ) : ( <>
diff --git a/src/store/rtk/tokensApi.ts b/src/store/rtk/tokensApi.ts index cda2246..0018761 100644 --- a/src/store/rtk/tokensApi.ts +++ b/src/store/rtk/tokensApi.ts @@ -30,7 +30,6 @@ export const tokensApi = createApi({ query: (body: RefreshTokenDTO) => ({ url: '/refresh/', method: 'POST', - headers: { 'Content-Type': 'application/json' }, body, }), transformResponse: (response: AccessTokenDTO) => response, @@ -40,14 +39,26 @@ export const tokensApi = createApi({ }) => response.data, }), verifyToken: builder.mutation({ - query: (body: string) => ({ + query: (token: string) => ({ url: '/verify/', method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body, + body: { token }, }), + transformResponse: (response: { status: number; data: unknown }) => { + return response.status === 200; + }, + transformErrorResponse: (response: { + status: number; + data: TokenErrorMessage; + }) => { + return response.status === 200; + }, }), }), }); -export const { useCreateTokenMutation, useRefreshTokenMutation } = tokensApi; +export const { + useCreateTokenMutation, + useRefreshTokenMutation, + useVerifyTokenMutation, +} = tokensApi; diff --git a/src/store/rtk/userApi.ts b/src/store/rtk/userApi.ts index 6b9d97b..0ff142f 100644 --- a/src/store/rtk/userApi.ts +++ b/src/store/rtk/userApi.ts @@ -25,12 +25,11 @@ export const userApi = createApi({ url: '/me/', method: 'GET', }), - extraOptions: { maxRetries: 3 }, transformResponse: (response: UserDTO) => response, transformErrorResponse: (response: { status: number; data?: UserErrorMessage; - }) => response, + }) => response.data, }), updateCoordinates: builder.mutation({ query: (location) => ({ diff --git a/src/store/slices/user.ts b/src/store/slices/user.ts index 5918658..a1316f4 100644 --- a/src/store/slices/user.ts +++ b/src/store/slices/user.ts @@ -17,7 +17,7 @@ const initialState: UserState = { email: '', userpic: null, status: '', - isLoading: false, + isLoading: true, errorMessage: undefined, registerSuccess: false, isAuthenticated: false, @@ -33,6 +33,7 @@ const userSlice = createSlice({ localStorage.removeItem('refresh_token'); return { ...initialState, + isLoading: false, }; }, setLocationError(state, action: { payload: { errorMessage: string } }) { @@ -43,6 +44,9 @@ const userSlice = createSlice({ errorMessage: action.payload.errorMessage, }; }, + stopLoading(state) { + return { ...state, isLoading: false }; + }, }, extraReducers: (builder) => { builder.addMatcher( @@ -140,4 +144,4 @@ const userSlice = createSlice({ export default userSlice.reducer; -export const { logout, setLocationError } = userSlice.actions; +export const { logout, stopLoading, setLocationError } = userSlice.actions;