Skip to content

Commit

Permalink
Add code of Authentication day to app
Browse files Browse the repository at this point in the history
  • Loading branch information
matiasgarcia91 committed May 12, 2022
1 parent 7f078db commit 3350d8b
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 1 deletion.
14 changes: 13 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
// src/App.js
import React from "react";
import React, { useEffect } from "react";
import { useDispatch } from "react-redux";
import "./App.css";
import { Routes, Route } from "react-router-dom";
import Homepage from "./pages/Homepage";
import PostPage from "./pages/PostPage";
import LoginPage from "./pages/Login";
import Toolbar from "./components/Toolbar";
import { bootstrapLoginState } from "./store/auth/actions";

export default function App() {
const dispatch = useDispatch();

useEffect(() => {
dispatch(bootstrapLoginState());
}, []);

return (
<div>
<Toolbar />
<Routes>
{/* more pages to be added here later */}
<Route path="/" element={<Homepage />} />
<Route path="/post/:id" element={<PostPage />} />
<Route path="/login" element={<LoginPage />} />
</Routes>
</div>
);
Expand Down
32 changes: 32 additions & 0 deletions src/components/Toolbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Link } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
import { getUserProfile } from "../store/auth/selectors";
import { logout } from "../store/auth/slice";
import "./styles.css";

const Toolbar = () => {
const user = useSelector(getUserProfile);
const dispatch = useDispatch();

return (
<div className="toolbar">
<Link to="/" className="logo-link">
<h2>Codaisseur Coders Network!</h2>
</Link>
<div className="button-container">
{user ? (
<>
<h4 className="welcome-text">Welcome {user.name}</h4>
<button onClick={() => dispatch(logout())}>Logout</button>
</>
) : (
<Link to="/login">
<button>Login</button>
</Link>
)}
</div>
</div>
);
};

export default Toolbar;
21 changes: 21 additions & 0 deletions src/components/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.toolbar {
display: flex;
justify-content: space-between;
padding-right: 30px;
padding-left: 30px;
background-color: lightsalmon;
}

.button-container {
display: flex;
align-items: center;
}

.welcome-text {
margin-right: 30px;
}

.logo-link {
text-decoration: none;
color: black;
}
52 changes: 52 additions & 0 deletions src/pages/Login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// src/pages/LoginPage.js
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { login } from "../store/auth/actions";
import { getAuthLoading } from "../store/auth/selectors";

export default function LoginPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const dispatch = useDispatch();
const navigate = useNavigate();

const loading = useSelector(getAuthLoading);

function handleSubmit(event) {
event.preventDefault();
dispatch(login(email, password, navigate));
}

return (
<div style={{ marginLeft: 30 }}>
<h1>Login</h1>
<form onSubmit={handleSubmit}>
<p>
<label>
Email:{" "}
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</label>
</p>
<p>
<label>
Password:{" "}
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</label>
</p>
<p>
<button type="submit">Login</button>
</p>
</form>
{loading && "Loading..."}
</div>
);
}
46 changes: 46 additions & 0 deletions src/store/auth/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// src/store/auth/actions.js
import axios from "axios";
import { API_URL } from "../../config";
import { startLoading, userLoggedIn } from "./slice";
// A thunk creator
export const login = (email, password, navigate) => {
return async function thunk(dispatch, getState) {
try {
dispatch(startLoading());

const response = await axios.post(`${API_URL}/login`, {
email,
password,
});

const { jwt } = response.data;

const profileResponse = await axios.get(`${API_URL}/me`, {
headers: { authorization: `Bearer ${jwt}` },
});

localStorage.setItem("token", jwt);

dispatch(userLoggedIn({ accessToken: jwt, user: profileResponse.data }));
navigate("/");
} catch (e) {
console.log("Error at login", e.message);
}
};
};

export const bootstrapLoginState = () => async (dispatch, getState) => {
try {
const token = localStorage.getItem("token");

if (!token) return;

const response = await axios.get(`${API_URL}/me`, {
headers: { authorization: `Bearer ${token}` },
});

dispatch(userLoggedIn({ accessToken: token, user: response.data }));
} catch (e) {
console.log(e.message);
}
};
2 changes: 2 additions & 0 deletions src/store/auth/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const getUserProfile = (reduxState) => reduxState.auth.me;
export const getAuthLoading = (reduxState) => reduxState.auth.loading;
33 changes: 33 additions & 0 deletions src/store/auth/slice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
me: null, // the logged-in user
accessToken: null,
loading: false,
};

export const authSlice = createSlice({
name: "auth",
initialState,
reducers: {
startLoading: (state) => {
state.loading = true;
},
userLoggedIn: (state, action) => {
state.me = action.payload.user;
state.accessToken = action.payload.accessToken;
state.loading = false;
},
logout: (state) => {
localStorage.removeItem("token");
// when we want to update the whole state
// we can return a new object instead of updating
// each key one by one
return initialState;
},
},
});

export const { startLoading, userLoggedIn, logout } = authSlice.actions;

export default authSlice.reducer;
2 changes: 2 additions & 0 deletions src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
});

Expand Down

0 comments on commit 3350d8b

Please sign in to comment.