From 27a6a4b817b809e5d8d324f686b9c4cb73ccd1a1 Mon Sep 17 00:00:00 2001 From: matiasgarcia91 Date: Thu, 12 May 2022 15:24:40 +0200 Subject: [PATCH 1/2] add login page --- src/App.js | 2 ++ src/pages/LoginPage.js | 51 ++++++++++++++++++++++++++++++++++++++++ src/store/auth/slice.js | 24 +++++++++++++++++++ src/store/auth/thunks.js | 23 ++++++++++++++++++ src/store/index.js | 2 ++ 5 files changed, 102 insertions(+) create mode 100644 src/pages/LoginPage.js create mode 100644 src/store/auth/slice.js create mode 100644 src/store/auth/thunks.js diff --git a/src/App.js b/src/App.js index 4442af9..55b3c00 100644 --- a/src/App.js +++ b/src/App.js @@ -4,6 +4,7 @@ import "./App.css"; import { Routes, Route } from "react-router-dom"; import Homepage from "./pages/Homepage"; import PostPage from "./pages/PostPage"; +import LoginPage from "./pages/LoginPage"; export default function App() { return ( @@ -12,6 +13,7 @@ export default function App() { {/* more pages to be added here later */} } /> } /> + } /> ); diff --git a/src/pages/LoginPage.js b/src/pages/LoginPage.js new file mode 100644 index 0000000..8f025c7 --- /dev/null +++ b/src/pages/LoginPage.js @@ -0,0 +1,51 @@ +// src/pages/LoginPage.js +import React, { useState } from "react"; +import { useDispatch } from "react-redux"; +import { login } from "../store/auth/thunks"; + +export default function LoginPage() { + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const dispatch = useDispatch(); + + function handleSubmit(event) { + event.preventDefault(); + + // Make a POST request + // Create a thunk for this! + dispatch(login(email, password)); + // TODO + console.log("TODO login with:", email, password); + } + + return ( +
+

Login

+
+

+ +

+

+ +

+

+ +

+
+
+ ); +} diff --git a/src/store/auth/slice.js b/src/store/auth/slice.js new file mode 100644 index 0000000..fec8fa2 --- /dev/null +++ b/src/store/auth/slice.js @@ -0,0 +1,24 @@ +import { createSlice } from "@reduxjs/toolkit"; + +const initialState = { + loading: false, + token: null, + user: null, +}; + +export const authSlice = createSlice({ + name: "auth", + initialState, + reducers: { + startLoading: (state) => { + state.loading = true; + }, + saveToken: (state, action) => { + state.token = action.payload; + }, + }, +}); + +export const { startLoading, saveToken } = authSlice.actions; + +export default authSlice.reducer; diff --git a/src/store/auth/thunks.js b/src/store/auth/thunks.js new file mode 100644 index 0000000..7ed3749 --- /dev/null +++ b/src/store/auth/thunks.js @@ -0,0 +1,23 @@ +import axios from "axios"; +import { saveToken, startLoading } from "./slice"; + +import { API_URL } from "../../config"; + +export const login = (email, password) => async (dispatch, getState) => { + try { + // dispatch => set loading to true + dispatch(startLoading()); + + // Make POST to /login + const response = await axios.post(`${API_URL}/login`, { + email, + password, + }); + + console.log("login response", response); + // store it in redux => dispatch something. + dispatch(saveToken(response.data.jwt)); + } catch (e) { + console.log(e.message); + } +}; diff --git a/src/store/index.js b/src/store/index.js index 98aa5e1..5b27baa 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2,11 +2,13 @@ import { configureStore } from "@reduxjs/toolkit"; import feedReducer from "./feed/slice"; import postPageReducer from "./postPage/slice"; +import authReducer from "./auth/slice"; const store = configureStore({ reducer: { feed: feedReducer, postPage: postPageReducer, + auth: authReducer, }, }); From a042743dd49c84f52cfb9d9a84cfdec8e5d03056 Mon Sep 17 00:00:00 2001 From: matiasgarcia91 Date: Thu, 12 May 2022 18:32:36 +0200 Subject: [PATCH 2/2] login lecture - 58 --- src/App.js | 2 ++ src/component/NavBar.js | 39 +++++++++++++++++++++++++++++ src/pages/LoginPage.js | 7 +++++- src/store/auth/selectors.js | 1 + src/store/auth/slice.js | 10 +++++--- src/store/auth/thunks.js | 50 +++++++++++++++++++++++-------------- 6 files changed, 86 insertions(+), 23 deletions(-) create mode 100644 src/component/NavBar.js create mode 100644 src/store/auth/selectors.js diff --git a/src/App.js b/src/App.js index 55b3c00..f636ebe 100644 --- a/src/App.js +++ b/src/App.js @@ -5,10 +5,12 @@ import { Routes, Route } from "react-router-dom"; import Homepage from "./pages/Homepage"; import PostPage from "./pages/PostPage"; import LoginPage from "./pages/LoginPage"; +import NavBar from "./component/NavBar"; export default function App() { return (
+ {/* more pages to be added here later */} } /> diff --git a/src/component/NavBar.js b/src/component/NavBar.js new file mode 100644 index 0000000..f56bab1 --- /dev/null +++ b/src/component/NavBar.js @@ -0,0 +1,39 @@ +import { Link } from "react-router-dom"; +import { useSelector, useDispatch } from "react-redux"; +import { getUser } from "../store/auth/selectors"; +import { logout } from "../store/auth/slice"; + +const NavBar = () => { + const user = useSelector(getUser); + const dispatch = useDispatch(); + + return ( +
+ +

Coders!

+ +
+ {user ? ( +
+

Welcome {user.name}!

+ +
+ ) : ( + + + + )} +
+
+ ); +}; + +export default NavBar; diff --git a/src/pages/LoginPage.js b/src/pages/LoginPage.js index 8f025c7..bcbb483 100644 --- a/src/pages/LoginPage.js +++ b/src/pages/LoginPage.js @@ -2,20 +2,25 @@ import React, { useState } from "react"; import { useDispatch } from "react-redux"; import { login } from "../store/auth/thunks"; +import { useNavigate } from "react-router-dom"; export default function LoginPage() { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const dispatch = useDispatch(); + const navigate = useNavigate(); function handleSubmit(event) { event.preventDefault(); // Make a POST request // Create a thunk for this! - dispatch(login(email, password)); + dispatch(login(email, password, navigate)); + // TODO console.log("TODO login with:", email, password); + setEmail(""); + setPassword(""); } return ( diff --git a/src/store/auth/selectors.js b/src/store/auth/selectors.js new file mode 100644 index 0000000..1260f49 --- /dev/null +++ b/src/store/auth/selectors.js @@ -0,0 +1 @@ +export const getUser = (reduxState) => reduxState.auth.user; diff --git a/src/store/auth/slice.js b/src/store/auth/slice.js index fec8fa2..da83880 100644 --- a/src/store/auth/slice.js +++ b/src/store/auth/slice.js @@ -13,12 +13,16 @@ export const authSlice = createSlice({ startLoading: (state) => { state.loading = true; }, - saveToken: (state, action) => { - state.token = action.payload; + saveLoginData: (state, action) => { + state.token = action.payload.token; + state.user = action.payload.user; + }, + logout: (state) => { + return { ...initialState }; }, }, }); -export const { startLoading, saveToken } = authSlice.actions; +export const { startLoading, saveLoginData, logout } = authSlice.actions; export default authSlice.reducer; diff --git a/src/store/auth/thunks.js b/src/store/auth/thunks.js index 7ed3749..7d27d32 100644 --- a/src/store/auth/thunks.js +++ b/src/store/auth/thunks.js @@ -1,23 +1,35 @@ import axios from "axios"; -import { saveToken, startLoading } from "./slice"; +import { saveLoginData, startLoading } from "./slice"; import { API_URL } from "../../config"; -export const login = (email, password) => async (dispatch, getState) => { - try { - // dispatch => set loading to true - dispatch(startLoading()); - - // Make POST to /login - const response = await axios.post(`${API_URL}/login`, { - email, - password, - }); - - console.log("login response", response); - // store it in redux => dispatch something. - dispatch(saveToken(response.data.jwt)); - } catch (e) { - console.log(e.message); - } -}; +export const login = + (email, password, navigate) => async (dispatch, getState) => { + try { + // dispatch => set loading to true + dispatch(startLoading()); + + // Make POST to /login + const response = axios.post(`${API_URL}/login`, { + email, + password, + }); + + const token = response.data.jwt; + + const profileResponse = axios.get(`${API_URL}/me`, { + headers: { + authorization: `Bearer ${token}`, + }, + }); + + navigate("/"); + + console.log("me response", profileResponse.data); + // store it in redux => dispatch something. + + dispatch(saveLoginData({ token, user: profileResponse.data })); + } catch (e) { + console.log(e.message); + } + };