diff --git a/sports-matcher/client/src/Layout.js b/sports-matcher/client/src/Layout.js index f93165e..9864c39 100644 --- a/sports-matcher/client/src/Layout.js +++ b/sports-matcher/client/src/Layout.js @@ -1,6 +1,6 @@ import "./styles/Layout.css"; import "./styles/extra.css"; -import React, { useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { NavLink, Route, Routes, useNavigate } from "react-router-dom"; import Welcome from "./pages/Welcome"; import Navbar from "react-bootstrap/Navbar"; @@ -10,11 +10,11 @@ import NavbarCollapse from "react-bootstrap/esm/NavbarCollapse"; import Dashboard from "./pages/Dashboard"; import Login from "./pages/Login"; import { apiClient } from "./utils/httpClients"; +import { globalContext } from "./context.js"; export default function layout() { const navigate = useNavigate(); - const navigationContext = React.createContext(navigate); const [state, setState] = useState({ user: null, }); @@ -58,7 +58,7 @@ export default function layout() { return (
- +
@@ -85,7 +85,7 @@ export default function layout() { - +
); } \ No newline at end of file diff --git a/sports-matcher/client/src/components/MatchInfoCard.js b/sports-matcher/client/src/components/MatchInfoCard.js index f99832f..f7deb91 100644 --- a/sports-matcher/client/src/components/MatchInfoCard.js +++ b/sports-matcher/client/src/components/MatchInfoCard.js @@ -9,7 +9,6 @@ export default class MatchInfoCard extends React.Component { getParticipants() { let participants = []; - console.log(this.props); this.props.match.participants.forEach(user => { participants.push(user.firstName); }); diff --git a/sports-matcher/client/src/context.js b/sports-matcher/client/src/context.js new file mode 100644 index 0000000..8f6e61c --- /dev/null +++ b/sports-matcher/client/src/context.js @@ -0,0 +1,3 @@ +import React from "react"; + +export const globalContext = React.createContext({}); diff --git a/sports-matcher/client/src/pages/Login.js b/sports-matcher/client/src/pages/Login.js index a74018d..a7f5793 100644 --- a/sports-matcher/client/src/pages/Login.js +++ b/sports-matcher/client/src/pages/Login.js @@ -1,40 +1,74 @@ import React from "react"; -import { Button, Card, Form } from "react-bootstrap"; +import { Button, Card, Container, Form } from "react-bootstrap"; +import { globalContext } from "../context"; import { apiClient } from "../utils/httpClients"; import { guard } from "../utils/routing"; export default class Login extends React.Component { constructor(props) { super(props); + this.state = { + email: "", + password: "" + }; + + this.attemptLogin = this.attemptLogin.bind(this); } + static contextType = globalContext; + async componentDidMount() { - const getUserResponse = await apiClient.get("/user"); - guard(() => getUserResponse.status === 401, "/dashboard"); // If it's not 401, then we redirect to dashboard. + try { + const getUserResponse = await apiClient.get("/user"); + guard(this.context.navigate, () => getUserResponse.status === 401, "/dashboard"); // If it's not 401, then we redirect to dashboard. + } catch (error) { + if (error.message !== "Request failed with status code 401") { + throw error; + } + } + } + + async attemptLogin(e) { + e.preventDefault(); + const loginResponse = await apiClient.post("/user/login", { + email: this.state.email, + password: this.state.password, + }); + + if (loginResponse.status === 200) { + this.context.navigate("/dashboard", { replace: true }); + } } render() { return ( -
- - - Login - Welcome back! -
- - E-mail - - - - Password - - - -
-
-
+
+ + + + Login + Welcome back! +
+ + E-mail + { + this.setState({ email: e.target.value }); + }} /> + + + Password + { + this.setState({ password: e.target.value }); + }} /> + + +
+
+
+
); } diff --git a/sports-matcher/client/src/pages/Logout.js b/sports-matcher/client/src/pages/Logout.js new file mode 100644 index 0000000..517d95c --- /dev/null +++ b/sports-matcher/client/src/pages/Logout.js @@ -0,0 +1,36 @@ +import React from "react"; +import { useNavigate } from "react-router-dom"; +import { apiClient } from "../utils/httpClients"; + +export default class Logout extends React.Component { + constructor(props) { + super(props); + } + + async componentDidMount() { + const logoutResponse = await apiClient.get("/user/logout"); + let navigation = useNavigate(); + if (logoutResponse.status === 401) { + navigation("/dashboard", { replace: true }); + } else { + this.redirectTimer = setTimeout(() => { + navigation("/", { replace: true }); + }, 2000); + } + } + + async componentWillUnmount() { + clearTimeout(this.redirectTimer); + } + + render() { + return ( +
+
+

You are now logged out. See you later!

+

We will redirect you shortly...

+
+
+ ); + } +} \ No newline at end of file diff --git a/sports-matcher/client/src/utils/routing.js b/sports-matcher/client/src/utils/routing.js index 94c328e..46caad9 100644 --- a/sports-matcher/client/src/utils/routing.js +++ b/sports-matcher/client/src/utils/routing.js @@ -1,7 +1,6 @@ -import { useNavigate } from "react-router-dom"; import { apiClient } from "./httpClients"; -export function guard(evaluator, redirect, navigateOptions, onRedirect) { +export function guard(navigator, evaluator, redirect, navigateOptions, onRedirect) { if (!evaluator) throw new Error("evaluator required."); if (!redirect) throw new Error("redirect required."); if (!navigateOptions) { @@ -9,16 +8,15 @@ export function guard(evaluator, redirect, navigateOptions, onRedirect) { replace: true }; } - let navigate = useNavigate(); let redirecting = !evaluator(); if (redirecting) { if (onRedirect) onRedirect(); - navigate(redirect, navigateOptions); + navigator(redirect, navigateOptions); } } -export async function needUser() { +export async function needUser(navigator) { let userDataResponse = await apiClient.get("/user"); - guard(() => userDataResponse.status === 200, "/login"); + guard(navigator, () => userDataResponse.status === 200, "/login"); return userDataResponse.data; } \ No newline at end of file