From de7b6b4c898b9b0818365474e6e29992ff4a20e1 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Fri, 7 Jun 2024 16:17:10 -0700 Subject: [PATCH] Used redux for auth information --- Client/src/Features/Auth/authSlice.js | 50 +++++++++++++++++++++++++ Client/src/Layouts/HomeLayout/index.jsx | 15 ++++---- Client/src/Pages/Demo/Demo.jsx | 1 - Client/src/Pages/Register/index.jsx | 28 ++++++++++---- Client/src/store.js | 3 +- 5 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 Client/src/Features/Auth/authSlice.js diff --git a/Client/src/Features/Auth/authSlice.js b/Client/src/Features/Auth/authSlice.js new file mode 100644 index 000000000..f8bc106e5 --- /dev/null +++ b/Client/src/Features/Auth/authSlice.js @@ -0,0 +1,50 @@ +import axios from "axios"; +import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; +import { jwtDecode } from "jwt-decode"; +const BASE_URL = import.meta.env.VITE_APP_API_BASE_URL; + +const initialState = { + isLoading: false, + user: "", + success: null, + msg: null, +}; + +export const register = createAsyncThunk( + "auth/register", + async (form, thunkApi) => { + try { + const res = await axios.post(`${BASE_URL}/auth/register`, form); + return res.data; + } catch (error) { + return thunkApi.rejectWithValue(error.response.data); + } + } +); + +const authSlice = createSlice({ + name: "auth", + initialState, + reducers: {}, + extraReducers: (builder) => { + builder + .addCase(register.pending, (state, action) => { + state.isLoading = true; + }) + .addCase(register.fulfilled, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + const decodedToken = jwtDecode(action.payload.data); + const user = { ...decodedToken }; + state.user = user; + }) + .addCase(register.rejected, (state, action) => { + state.isLoading = false; + state.success = action.payload.success; + state.msg = action.payload.msg; + }); + }, +}); + +export default authSlice.reducer; diff --git a/Client/src/Layouts/HomeLayout/index.jsx b/Client/src/Layouts/HomeLayout/index.jsx index 3a4a03dca..d7a7c2977 100644 --- a/Client/src/Layouts/HomeLayout/index.jsx +++ b/Client/src/Layouts/HomeLayout/index.jsx @@ -4,22 +4,23 @@ import DashboardSidebar from "../../Components/DashboardSidebar"; import "./index.css"; // Demo, remove me -import { jwtDecode } from "jwt-decode"; +import { useSelector } from "react-redux"; // Emd Demo const HomeLayout = () => { - const token = localStorage.getItem("token"); - const decodedToken = token && jwtDecode(token); + const authState = useSelector((state) => state.auth); + const { user, msg } = authState; + console.log(user, msg); return (
{/* Remove me later */} - {token &&

You are logged in

} - {token &&

First Name: {decodedToken.firstname}

} - {token &&

Last Name: {decodedToken.lastname}

} - {token &&

Email: {decodedToken.email}

} + {user &&

{user.firstname}

} + {user &&

{user.lastname}

} + {user &&

{user.email}

} + {msg &&

Msg: {msg}

} {/* I am a demo */}
diff --git a/Client/src/Pages/Demo/Demo.jsx b/Client/src/Pages/Demo/Demo.jsx index ec7875167..f2af76fb4 100644 --- a/Client/src/Pages/Demo/Demo.jsx +++ b/Client/src/Pages/Demo/Demo.jsx @@ -1,5 +1,4 @@ import React from "react"; -import axios from "axios"; import Button from "../../Components/Button/"; import Link from "../../Components/Link"; import { diff --git a/Client/src/Pages/Register/index.jsx b/Client/src/Pages/Register/index.jsx index 7b33e8a3c..bd1b63760 100644 --- a/Client/src/Pages/Register/index.jsx +++ b/Client/src/Pages/Register/index.jsx @@ -13,9 +13,13 @@ import Button from "../../Components/Button"; import Google from "../../assets/Images/Google.png"; import { registerValidation } from "../../Validation/validation"; +import { useDispatch } from "react-redux"; +import { register } from "../../Features/Auth/authSlice"; + const BASE_URL = import.meta.env.VITE_APP_API_BASE_URL; const Register = () => { + const dispatch = useDispatch(); const navigate = useNavigate(); // TODO If possible, change the IDs of these fields to match the backend @@ -55,23 +59,31 @@ const Register = () => { }; const handleSubmit = async () => { - console.log("submitting"); try { await registerValidation.validateAsync(form, { abortEarly: false }); + const action = await dispatch(register(form)); - const result = await axios.post(`${BASE_URL}/auth/register`, form); - const token = result.data.data; - localStorage.setItem("token", token); - navigate("/"); // Redirect to home page + if (action.meta.requestStatus === "fulfilled") { + const token = action.payload.data; + localStorage.setItem("token", token); + navigate("/"); + } + + if (action.meta.requestStatus === "rejected") { + const error = new Error("Request rejected"); + error.response = action.payload; + throw error; + } } catch (error) { - // TODO User friendly error display if (error.name === "ValidationError") { + // TODO Handle validation errors console.log(error); alert("Invalid input"); } else if (error.response) { - console.log(error); - alert(error.response.data.msg); + // TODO handle dispatch errors + alert(error.response.msg); } else { + // TODO handle unknown errors console.log(error); alert("Unknown error"); } diff --git a/Client/src/store.js b/Client/src/store.js index e8409d993..385448c6e 100644 --- a/Client/src/store.js +++ b/Client/src/store.js @@ -1,6 +1,7 @@ import { configureStore } from "@reduxjs/toolkit"; import monitorsReducer from "./Features/Monitors/monitorsSlice"; +import authReducer from "./Features/Auth/authSlice"; export default configureStore({ - reducer: { monitors: monitorsReducer }, + reducer: { monitors: monitorsReducer, auth: authReducer }, });