#21 Using wouter for navigation and links. Register page works by sending request to register endpoint

This commit is contained in:
2023-03-19 16:34:44 -04:00
parent 0d4c4facd5
commit f6e2b445d7
7 changed files with 235 additions and 46 deletions

View File

@@ -2,17 +2,33 @@ import "./App.css";
import { Route } from "wouter";
import HomePage from "./pages/HomePage";
import LoginPage from "./pages/LoginPage";
import { UserContextProvider } from "./contexts/UserContext";
import LogoutPage from "./pages/LogoutPage";
import RegisterPage from "./pages/RegisterPage";
import AuthenticatedRoute from "./components/AuthenticatedRoute";
function App() {
return (
<div className="App">
<UserContextProvider>
<Route path="/" component={HomePage} />
<Route path="/login" component={LoginPage} />
<Route path="/logout" component={LogoutPage} />
</UserContextProvider>
<Route path="/login">
<AuthenticatedRoute isAuthenticated={false}>
<LoginPage />
</AuthenticatedRoute>
</Route>
<Route path="/logout">
<AuthenticatedRoute isAuthenticated={false}>
<LogoutPage />
</AuthenticatedRoute>
</Route>
<Route path="/register">
<AuthenticatedRoute isAuthenticated={false}>
<RegisterPage />
</AuthenticatedRoute>
</Route>
<Route path="/">
<AuthenticatedRoute isAuthenticated={true}>
<HomePage />
</AuthenticatedRoute>
</Route>
</div>
);
}

View File

@@ -0,0 +1,20 @@
import { useContext, useEffect } from "react";
import { useLocation } from "wouter";
import UserContext from "../contexts/UserContext";
const AuthenticatedRoute = ({ children, isAuthenticated }) => {
const { currentUser } = useContext(UserContext);
const [location, setLocation] = useLocation();
useEffect(() => {
if (isAuthenticated && !currentUser?.id) {
setLocation("/login");
} else if (!isAuthenticated && currentUser?.id) {
setLocation("/");
}
}, [currentUser]);
return children;
};
export default AuthenticatedRoute;

View File

@@ -1,24 +1,32 @@
import { useContext } from "react";
import React, { useContext } from "react";
import { Nav, Container, Navbar } from "react-bootstrap";
import { Link } from "wouter";
import UserContext from "../contexts/UserContext";
const MyNavbar = () => {
const { currentUser } = useContext(UserContext);
const MyLink = ({ children, ...rest }) => {
return <Nav.Link as={Link} {...rest}>{children}</Nav.Link>;
};
return (
<React.Fragment>
<Navbar variant="dark" bg="dark" expand="lg">
<Container>
<Navbar.Brand href="/">LearningTree</Navbar.Brand>
<Navbar.Toggle aria-controls="navbar-nav" />
<Navbar.Collapse id="navbar-nav">
<Nav className="ms-auto">
<Nav.Link href="/">Home</Nav.Link>
<MyLink href="/">Home</MyLink>
{(currentUser?.id && (
<Nav.Link href="/logout">Logout</Nav.Link>
)) || <Nav.Link href="/login">Login</Nav.Link>}
<MyLink href="/logout">Logout</MyLink>
)) || <MyLink href="/login">Login</MyLink>}
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
</React.Fragment>
);
};

View File

@@ -1,14 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import 'bootstrap/dist/css/bootstrap.min.css';
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import "bootstrap/dist/css/bootstrap.min.css";
import { UserContextProvider } from "./contexts/UserContext";
const root = ReactDOM.createRoot(document.getElementById('root'));
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<UserContextProvider>
<App />
</UserContextProvider>
</React.StrictMode>
);

View File

@@ -6,18 +6,12 @@ import UserContext from "../contexts/UserContext";
const HomePage = () => {
const { currentUser } = useContext(UserContext);
useEffect(() => {
if (!currentUser?.id) {
window.location.replace("/login");
}
}, [currentUser]);
return (
<div>
<MyNavbar />
<Container>
<Container className="p-5">
<div>
<h1>This is the home page</h1>
<h1>Welcome back {currentUser?.username}!</h1>
</div>
</Container>
</div>

View File

@@ -1,5 +1,6 @@
import React, { useContext, useEffect, useState } from "react";
import { Button, Col, Container, Form, Row, Alert } from "react-bootstrap";
import { Link } from "wouter";
import MyNavbar from "../components/MyNavbar";
import UserContext from "../contexts/UserContext";
import { makeRequest } from "../utils.ts";
@@ -12,7 +13,6 @@ const LoginPage = () => {
const { currentUser, setCurrentUser } = useContext(UserContext);
useEffect(() => {
console.log(currentUser);
if (currentUser?.id) {
gotoHome();
}
@@ -42,14 +42,16 @@ const LoginPage = () => {
return (
<React.Fragment>
<MyNavbar />
<Container className="p-5">
{error && (
<Container>
<Alert variant="danger" className="m-4 mx-auto w-50 text-center">
<Alert variant="danger" className="mx-auto w-50 text-center">
{error.message}
</Alert>
</Container>
)}
<Container className="p-5">
<h2>Login</h2>
<br />
<Form onSubmit={sendLoginRequest}>
<Form.Group as={Row} className="mb-3" controlId="username">
<Form.Label column sm={2} className="me-2">
@@ -87,7 +89,7 @@ const LoginPage = () => {
</Form.Group>
<Form.Group as={Row}>
<p>
Don't have an account? <a href="/register">Register here</a>
Don't have an account? <Link href="/register">Register here</Link>
</p>
</Form.Group>
</Form>

View File

@@ -0,0 +1,146 @@
import React, { useState } from "react";
import { Button, Col, Container, Form, Row, Alert } from "react-bootstrap";
import { Link } from "wouter";
import MyNavbar from "../components/MyNavbar";
import { makeRequest } from "../utils.ts";
const RegisterPage = () => {
const [role, setRole] = useState("student");
const [username, setUsername] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [password2, setPassword2] = useState("");
const [error, setError] = useState(null);
const sendRegisterRequest = (e) => {
e?.preventDefault();
makeRequest({
url: "http://localhost:5000/register",
method: "POST",
body: {
role,
email,
username,
password,
password2,
},
})
.then((resp) => resp.json())
.then((data) => {
if (data.error) {
setError(data);
return;
}
window.location.href = "/login";
});
};
return (
<React.Fragment>
<MyNavbar />
<Container className="p-5">
{error && (
<Container>
<Alert variant="danger" className="mx-auto w-50 text-center">
{error.message}
</Alert>
</Container>
)}
<h2>Register</h2>
<br />
<Form onSubmit={sendRegisterRequest}>
<Form.Group as={Row} className="mb-3" controlId="role">
<Form.Label column sm={2} className="me-2">
Role
</Form.Label>
<Col sm={9}>
<Form.Select
onChange={(e) => {
setRole(e.target.value);
}}
>
<option value="student">Student</option>
<option value="teacher">Teacher</option>
</Form.Select>
</Col>
</Form.Group>
<Form.Group as={Row} className="mb-3" controlId="username">
<Form.Label column sm={2} className="me-2">
Username
</Form.Label>
<Col sm={9}>
<Form.Control
type="username"
placeholder="username"
onChange={(e) => {
setUsername(e.target.value);
}}
/>
</Col>
</Form.Group>
<Form.Group as={Row} className="mb-3" controlId="email">
<Form.Label column sm={2} className="me-2">
Email
</Form.Label>
<Col sm={9}>
<Form.Control
type="email"
placeholder="email"
onChange={(e) => {
setEmail(e.target.value);
}}
/>
</Col>
</Form.Group>
<Form.Group as={Row} className="mb-3" controlId="password">
<Form.Label column sm={2} className="me-2">
Password
</Form.Label>
<Col sm={9}>
<Form.Control
type="password"
placeholder="password"
onChange={(e) => {
setPassword(e.target.value);
}}
/>
</Col>
</Form.Group>
<Form.Group as={Row} className="mb-3" controlId="password2">
<Form.Label column sm={2} className="me-2">
Confirm Password
</Form.Label>
<Col sm={9}>
<Form.Control
type="password"
placeholder="password"
onChange={(e) => {
setPassword2(e.target.value);
}}
/>
</Col>
</Form.Group>
<Form.Group as={Row} className="mb-3" controlId="submit">
<Col sm={2}></Col>
<Col sm={2}>
<Button
type="submit"
disabled={!password || password !== password2}
>
Submit
</Button>
</Col>
</Form.Group>
<Form.Group as={Row}>
<p>
Already have an account? <Link href="/login">Login here</Link>
</p>
</Form.Group>
</Form>
</Container>
</React.Fragment>
);
};
export default RegisterPage;