Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement private route component #234

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions client/src/components/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Link, useNavigate } from "react-router-dom";
import { login } from "../services/auth.js";
import { useLoginContext } from "../contexts/LoginContext.js";
import { useRegisterContext } from "../contexts/RegisterContext.js";
import { useUserContext } from "../contexts/UserContext.js"
import Alert from "./Alert.js";

import {
Expand Down Expand Up @@ -42,6 +43,8 @@ const Login = ({ toggleForm }) => {
const { registerSuccessMessageVisible, setRegisterSuccessMessageVisible } =
useRegisterContext();

const { setUser } = useUserContext()

const navigate = useNavigate();

const clearData = () => {
Expand All @@ -66,11 +69,12 @@ const Login = ({ toggleForm }) => {
e.preventDefault();
setLoginPending(true);
try {
const responseStatus = await login(loginData);
const { responseStatus, user } = await login(loginData);

if (responseStatus === 200) {
setUser(user) // store user in state because user is checked to determine private route access
setLoggedIn(true);
navigate("/");
navigate("/", { state:user }); // store user in route state because "/" route will render with the old user state at this point
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QQ here. If we update the state via our context as we do a few lines up from this, does route "/" render old user state data? I haven't really used this feature from react router dom, but it looks like its a way to carry state across routes. If so our user context is already doing this, correct?

} else if (responseStatus === 403) {
setLoginFailMessage("User does not exist");
} else if (responseStatus === 400) {
Expand Down
3 changes: 3 additions & 0 deletions client/src/components/Logout.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { logout } from "../services/auth";
import { useLoginContext } from "../contexts/LoginContext";
import { useUserContext } from "../contexts/UserContext"

const Logout = () => {
const { setLoggedIn } = useLoginContext();
const { setUser } = useUserContext()
const navigate = useNavigate();

const handleLogout = () => {
const isSuccesful = logout();
if (isSuccesful) {
setUser(null) // clear user from state because user is checked to determine private route access
setLoggedIn(false);
navigate("/login");
}
Expand Down
17 changes: 17 additions & 0 deletions client/src/components/PrivateRoute.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Navigate,useLocation } from "react-router-dom";

import { useUserContext } from "../contexts/UserContext";

function PrivateRoute({ children }) {
const location = useLocation();
const userInLocation = location.state;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the difference here vs the state we are tracking on userContext?

const { user } = useUserContext();

if (!user && !userInLocation) {
return <Navigate to="/login" replace />;
}

return children;
}

export default PrivateRoute;
20 changes: 14 additions & 6 deletions client/src/components/ResponsiveAppBar.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { useLoginContext } from "../contexts/LoginContext.js";
import { Adb as AdbIcon, Menu as MenuIcon } from "@mui/icons-material";
import {
AppBar,
Expand All @@ -16,6 +15,8 @@ import {
MenuItem,
} from "@mui/material";

import { useUserContext } from "../contexts/UserContext.js";

const pages = ["Home", "Locations", "Guides", "About"];

function ResponsiveAppBar() {
Expand All @@ -27,15 +28,22 @@ function ResponsiveAppBar() {
"Dashboard",
"Login",
]);
const { loggedIn } = useLoginContext();
const { user } = useUserContext();

useEffect(() => {
if (loggedIn) {
setSettings([...settings.slice(0, settings.length - 1), "Logout"]);
if (user) {
setSettings((prevSettings) => [
...prevSettings.slice(0, prevSettings.length - 1),
"Logout",
]);
} else {
setSettings([...settings.slice(0, settings.length - 1), "Login"]);
setSettings((prevSettings) => [
...prevSettings.slice(0, prevSettings.length - 1),
"Login",
]);
}
}, [loggedIn]);
}, [user]);

const handleOpenNavMenu = (event) => {
setAnchorElNav(event.currentTarget);
};
Expand Down
19 changes: 17 additions & 2 deletions client/src/components/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import LoginPage from "../pages/LoginPage";
import TermsConditionPage from "../pages/TermsConditionPage";
import Demo from "../pages/Demo";
import Logout from "./Logout";
import PrivateRoute from "./PrivateRoute";

/*
* Creating routes via createBrowserRouter method makes project ready for react-router-dom 6.4 data fetching.
Expand All @@ -31,12 +32,26 @@ import Logout from "./Logout";
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<MainLayout />} errorElement={<ErrorPage />}>
<Route index element={<Homepage />} />
<Route
index
element={
<PrivateRoute>
<Homepage />
</PrivateRoute>
}
/>
<Route path="/homepage" element={<Navigate replace to="/" />} />
<Route path="/locations" element={<LocationsPage />} />
<Route path="/guides" element={<GuidesPage />} />
<Route path="/about" element={<AboutPage />} />
<Route path="/profile" element={<ProfilePage />} />
<Route
path="/profile"
element={
<PrivateRoute>
<ProfilePage />
</PrivateRoute>
}
/>
<Route path="/login" element={<LoginPage />} />
<Route path="/logout" element={<Logout />} />
<Route path="/terms" element={<TermsConditionPage />} />
Expand Down
8 changes: 0 additions & 8 deletions client/src/pages/Homepage.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ const Homepage = () => {

const token = localStorage.getItem("token");

useEffect(() => {
if (!loginPending && !loggedIn && !token) {
navigate("/login");
} else {
setLoggedIn(true);
}
}, []);

// Fetch all habits from back end
const getAllHabits = async () => {
const config = {
Expand Down
7 changes: 1 addition & 6 deletions client/src/pages/ProfilePage.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useState } from "react";
import { useLoginContext } from "../contexts/LoginContext";
import { useUserContext } from "../contexts/UserContext";
import { useNavigate } from "react-router-dom";
Expand Down Expand Up @@ -30,11 +30,6 @@ const ProfilePage = () => {

const [showForm, setShowForm] = useState(false);

useEffect(() => {
if (!loginPending && !loggedIn) {
navigate("/login");
}
});
// Clears all form fields and opens/closes form modal
const toggleForm = () => {
setFormData({
Expand Down
4 changes: 2 additions & 2 deletions client/src/services/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ const login = async (userData) => {
);

const json = await response.json();
const token = await json.token;
const { token, user } = json;
localStorage.setItem("token", token);

return response.status;
return { responseStatus: response.status, user };
} catch (error) {
return Promise.reject(error);
}
Expand Down