Skip to content

Commit

Permalink
update: auth with redux
Browse files Browse the repository at this point in the history
  • Loading branch information
dioveath committed Feb 8, 2023
1 parent 2272967 commit ea59b18
Show file tree
Hide file tree
Showing 17 changed files with 148 additions and 189 deletions.
64 changes: 16 additions & 48 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import "./App.css";

import HomePage from "./containers/HomePage";
import DashboardPage from "./containers/DashboardPage";
import OrganizerDashboardPage from "./containers/OrganizerDashboardPage";
import TourneyDashboardPage from "./containers/TourneyDashboardPage";
Expand All @@ -9,17 +8,12 @@ import ProfilePage from "./containers/ProfilePage";
import FifaLeagueRegister from "./containers/FifaLeagueRegister";
import TourneysPage from "./containers/TourneysPage";

import { Routes, Route, Navigate, Outlet } from "react-router-dom";
import { Routes, Route, Navigate } from "react-router-dom";
import RequireAuth from './containers/Auth/RequireAuth';

import axios from "axios";
import { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { updateToken, logout } from "./redux/AuthSlice";
import { updateUser, pending, deleteUser } from "./redux/UserSlice";

import { useGetUserQuery } from "./redux/UserApi";

import config from "./config/config.js";
import { updateToken } from './redux/AuthSlice';

import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.min.css";
Expand All @@ -29,54 +23,28 @@ import "react-loading-skeleton/dist/skeleton.css";

function App() {
const dispatch = useDispatch();
const auth = useSelector((state) => state.auth);

const { data } = useGetUserQuery(auth.userId);
const { accessToken: loggedIn } = useSelector((state) => state.auth);

useEffect(() => {
(async () => {
dispatch(updateToken());
dispatch(deleteUser());
if (auth.accessToken != null) {
dispatch(pending());

const options = {
method: "GET",
url: `${config.serverUrl}/api/v1/users/${auth.userId}`,
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + auth.accessToken,
},
};

try {
const response = await axios.request(options);
if (response.data.status !== "fail") {
dispatch(updateUser(response.data.user));
}
} catch (e) {
console.log(e.response);
// dispatch(error(e.response.data.errorList));
dispatch(logout());
dispatch(deleteUser());
}
}
})();
}, [auth.accessToken, auth.userId, dispatch]);
dispatch(updateToken());
}, [dispatch]);

return (
<>
<SkeletonTheme baseColor="#202020" highlightColor="#444">
<Routes>
<Route path="/" element={<Navigate to='/auth'/>}/>
<Route path="/auth/*" element={auth.accessToken ? <Navigate to='/dashboard'/> : <LoginPage/>}/>
<Route path="/auth/*" element={loggedIn ? <Navigate to='/dashboard'/> : <LoginPage/>}/>
<Route path="/profile/:profileId" element={<ProfilePage/>}/>
<Route path="/dashboard" element={<DashboardPage/>}/>
<Route path="/organizer" element={<OrganizerDashboardPage/>}/>
<Route path="/organizer/tourneys/:tourneyId" element={<TourneyDashboardPage/>}/>
<Route path="/organizer/tourney/:tourneyId" element={<TourneyDashboardPage/>}/>
<Route path="/tourneys/:tourneyId" element={<FifaLeagueRegister/>}/>
<Route path="/tourneys" element={<TourneysPage/>}/>

<Route element={<RequireAuth/>}>
<Route path="/dashboard" element={<DashboardPage/>}/>
<Route path="/organizer" element={<OrganizerDashboardPage/>}/>
<Route path="/organizer/tourneys/:tourneyId" element={<TourneyDashboardPage/>}/>
<Route path="/organizer/tourney/:tourneyId" element={<TourneyDashboardPage/>}/>
<Route path="/tourneys/:tourneyId" element={<FifaLeagueRegister/>}/>
<Route path="/tourneys" element={<TourneysPage/>}/>
</Route>
</Routes>
</SkeletonTheme>
<ToastContainer
Expand Down
66 changes: 28 additions & 38 deletions client/src/components/AccountBox/LoginForm.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from "react";
import { useRef } from "react";
import { useRef, useState, useEffect } from "react";

import axios from "axios";
import { useSelector, useDispatch } from "react-redux";
import { login, pending, error } from "../../redux/AuthSlice";
import { useDispatch } from "react-redux";
import { setCredentials } from "../../redux/AuthSlice";
import { useLoginMutation } from '../../containers/Auth/authApiSlice';

import {
FormContainer,
Expand All @@ -14,49 +14,42 @@ import {
SubmitButton,
} from "./FormElements";
import { Marginer } from "../../components/Marginer";
import config from "../../config/config.js";

import { motion } from "framer-motion";

export function LoginForm() {
const dispatch = useDispatch();
const email = useRef();
const password = useRef();

const [ login, { isLoading } ] = useLoginMutation();
const [errorMsg, setErrorMsg] = useState('');

const auth = useSelector((state) => state.auth);
const dispatch = useDispatch();

useEffect(() => {
setErrorMsg('');
}, [email.current?.value, password.current?.value]);

const handleLoginClick = async (e) => {
e.preventDefault();

dispatch(pending());
const cred = {
email: email.current.value,
password: password.current.value
};

try {
console.log(config.serverUrl);
var response = await axios.post(`${config.serverUrl}/auth/login`, {
email: email.current.value,
password: password.current.value,
});
if (response.data.status === "success") {
dispatch(
login({
accessToken: response.data.accessToken,
userId: response.data.userId,
})
);
const data = await login(cred).unwrap();
dispatch(setCredentials({ ...data }));
} catch(e) {
if(e?.data?.status === 'fail') {
setErrorMsg(e.data.errorList.join(', '));
} else if (e?.status) {
setErrorMsg("Failed to fetch!");
} else {
dispatch(
error({
errorMessages: response.data.errorList,
})
);
setErrorMsg('Failed - Something went wrong!');
}
} catch (e) {
dispatch(
error({
errorMessages: [e.message],
})
);
}

};

return (
Expand All @@ -75,21 +68,18 @@ export function LoginForm() {
ref={password}
/>
<Marginer vertical="5px" />
{auth.isError &&
auth.errorMessages.map((message, i) => {
return <ErrorMessage errorMessage={message} key={i} />;
})}
{errorMsg && <ErrorMessage errorMessage={errorMsg} /> }
<Marginer vertical="5px" />
<SubmitButton type="submit">
{auth.isPending ? "Logging in..." : "LOGIN"}
{isLoading ? "Logging in..." : "LOGIN"}
</SubmitButton>
<Marginer vertical="10px" />
<MutedLink>
Don't have an Account?
<BoldLink to="/auth/register"> Register Now! </BoldLink>{" "}
</MutedLink>
<Marginer vertical="10px" />

<BoldLink to="/"> Home </BoldLink>
</FormContainer>
</motion.div>
Expand Down
9 changes: 7 additions & 2 deletions client/src/components/AccountBox/Logout.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { useDispatch } from 'react-redux';
import { logout } from '../../redux/AuthSlice';
import { deleteUser } from '../../redux/UserSlice';
import { resetMenu } from '../../redux/UserDashboardSlice';
import { useNavigate } from 'react-router-dom';

export default function Logout(){
const navigate = useNavigate();
const dispatch = useDispatch();

dispatch(logout());
navigate('/');
dispatch(deleteUser());
dispatch(resetMenu());

return <></>;
navigate('/');
return <p> Logging out... </p>;
}
8 changes: 3 additions & 5 deletions client/src/components/AccountBox/RegisterForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import { Marginer } from '../../components/Marginer';
import axios from 'axios';
import { useSelector, useDispatch } from 'react-redux';
import { pending, error, complete } from '../../redux/RegisterSlice';
import { login } from '../../redux/AuthSlice';
import { setCredentials } from '../../redux/AuthSlice';

import config from '../../config/config.js';
import { motion } from 'framer-motion';


export function RegisterForm(props){

const firstName = useRef();
const lastName = useRef();
const gamingName = useRef();
Expand Down Expand Up @@ -55,8 +54,8 @@ export function RegisterForm(props){
}
);

if(response.data.status == 'success') {
dispatch(login({
if(response.data.status === 'success') {
dispatch(setCredentials({
accessToken: response.data.accessToken,
userId: response.data.userId
}));
Expand All @@ -66,7 +65,6 @@ export function RegisterForm(props){
}));
}


} catch (e) {

dispatch(error({
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/AccountBox/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function AccountBox(props) {
<Route path={`/`} element={<Navigate to='login'/>}/>
<Route path={`/login`} element={<LoginForm/>}/>
<Route path={`/register`} element={<RegisterForm/>}/>
<Route path={`/logout`} elemtn={<Logout/>}/>
<Route path={`/logout`} element={<Logout/>}/>
</Routes>
</ContentContainer>
</AnimatePresence>
Expand Down
12 changes: 12 additions & 0 deletions client/src/containers/Auth/RequireAuth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useLocation, Outlet, Navigate } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { useGetUserQuery } from '../../redux/UserApi';

const RequireAuth = () => {
const { accessToken: loggedIn } = useSelector(state => state.auth);
const location = useLocation();

return (loggedIn ? <Outlet/> : <Navigate to='/' state={{from: location}} replace/>);
};

export default RequireAuth;
11 changes: 0 additions & 11 deletions client/src/containers/Auth/RequiresAuth.js

This file was deleted.

15 changes: 15 additions & 0 deletions client/src/containers/Auth/authApiSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { apiSlice } from '../../redux/ApiSlice';

export const authApiSlice = apiSlice.injectEndpoints({
endpoints: builder => ({
login: builder.mutation({
query: credentials => ({
url: '/auth/login',
method: 'POST',
body: { ...credentials }
})
})
})
});

export const { useLoginMutation } = authApiSlice;
10 changes: 5 additions & 5 deletions client/src/containers/DashboardPage/LeftSideBar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default function LeftSideBar({ menuItems, onChangeMenu }) {
const [revNavCycle, setRevNavCycle] = useState(false); //back & forth cycling of sidebarState
const dispatch = useDispatch();
const navigate = useNavigate();

const navNode = useClickOutside(() => {
setSidebarState(SidebarState.MOBILE);
setRevNavCycle(false);
Expand Down Expand Up @@ -232,10 +232,10 @@ export default function LeftSideBar({ menuItems, onChangeMenu }) {
icon={item.icon}
name={item.name}
onClick={() => {
if (item.name === "Log out") {
navigate("/auth/logout");
return;
}
/* if (item.name === "Log out") { */
/* navigate("/auth/logout"); */
/* return; */
/* } */
dispatch(setActiveMenu(item.name));

let currentState = sidebarState;
Expand Down
7 changes: 4 additions & 3 deletions client/src/containers/DashboardPage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ClanPage from "./Clan";
import ExplorePage from './Explore';
import TournamentsPage from './Tournaments';
import SettingsPage from './Settings';
import Logout from '../../components/AccountBox/Logout';

import { FlexContainer } from "../../components/base";
import { Text } from "../../components/Text";
Expand Down Expand Up @@ -69,7 +70,7 @@ const MenuItems = [
{
name: "Log out",
icon: <RiLogoutCircleLine />,
content: <></>
content: <Logout/>
},
];

Expand All @@ -84,9 +85,9 @@ px-2


export default function DashboardPage() {
const auth = useSelector(state => state.auth);
const { isLoading, error } = useGetUserQuery(auth.userId);
const { dashboard } = useSelector((state) => state.userDashboard);
const { userId } = useSelector((state) => state.auth);
const { isLoading, error } = useGetUserQuery(userId);

const renderContent = MenuItems.find(
(menu) => menu.name === dashboard.activeMenu
Expand Down
6 changes: 6 additions & 0 deletions client/src/helpers/jwt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function isTokenExpired(token) {
const expiry = (JSON.parse(atob(token.split('.')[1]))).exp;
return (Math.floor((new Date()).getTime() / 1000)) >= expiry;
}

export { isTokenExpired };
6 changes: 3 additions & 3 deletions client/src/redux/ApiSlice.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import config from '../config/config';
import { login, logout } from './AuthSlice';
import { setCredentials, logout } from './AuthSlice';
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';

const baseQuery = fetchBaseQuery({
baseUrl: `${config.serverUrl}`,
credentials: 'include',
// credentials: 'include',
prepareHeaders: (headers, { getState }) => {
const token = getState().auth.accessToken;
if(token) headers.set('Authorization', `Bearer ${token}`);
Expand All @@ -20,7 +20,7 @@ const baseQueryWithReauth = async (args, api, extraOptions) => {
console.log('sending refresh token..');
const refreshResult = await baseQuery('/auth/refresh', api, extraOptions);
if(refreshResult?.data){
api.dispatch(login({ accessToken: result.data.accessToken, userId: result.data.userId }));
api.dispatch(setCredentials({ accessToken: result.data.accessToken, userId: result.data.userId }));
} else {
api.dispatch(logout());
}
Expand Down
Loading

0 comments on commit ea59b18

Please sign in to comment.