appears to have a protected route

This commit is contained in:
Mikayla Dobson
2023-02-02 17:23:10 -06:00
parent 6739170e2e
commit 12989e2739
9 changed files with 189 additions and 85 deletions

View File

@@ -12,7 +12,9 @@
"axios": "^1.3.0", "axios": "^1.3.0",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0" "react-dom": "^18.2.0",
"react-router-dom": "^6.8.0",
"uuid": "^9.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.0.26", "@types/react": "^18.0.26",

View File

@@ -1,75 +1,20 @@
import { useEffect, useState } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom';
import jwt_decode from "jwt-decode"; import Home from './pages/Home';
import API from './util/API'; import SingleItem from './pages/protected/SingleItem';
import Auth from './pages/Auth'; import Items from './pages/protected/Items';
import './App.css' import './App.css'
function App() { function App() {
const [user, setUser] = useState(null);
const [contents, setContents] = useState(<></>);
async function handleLogin(info) {
if (!info.email || !info.password) return;
const response = await API.login(info);
console.log(response);
const user = jwt_decode(response.token);
console.log(user);
localStorage.setItem('user', JSON.stringify(user));
localStorage.setItem('token', response.token);
}
async function handleLogout() {
await API.logout();
localStorage.removeItem("user");
localStorage.removeItem("token");
}
async function handleRegister(register) {
if (!register.username || !register.email || !register.password) return;
await API.register(register);
}
useEffect(() => {
let item = localStorage.getItem('user');
if (item) {
item = JSON.parse(item);
setUser(item.user);
}
}, [])
useEffect(() => {
let protectedData;
if (user) {
(async() => {
protectedData = await API.getItems();
console.log(protectedData);
})();
}
setContents(
user ? (
<div>
<p>Welcome, {user.username}!</p>
<div>
</div>
<button onClick={handleLogout}>Log Out</button>
</div>
) : (
<Auth handleLogin={handleLogin} handleRegister={handleRegister} />
)
)
}, [user])
return ( return (
<div className="App"> <BrowserRouter>
<h1>Auth Testing</h1> <div className="App">
{ contents } <Routes>
</div> <Route path="/" element={<Home />} />
<Route path="/item" element={<Items />} />
<Route path="/item/:id" element={<SingleItem />} />
</Routes>
</div>
</BrowserRouter>
) )
} }

View File

@@ -1,24 +1,67 @@
import { useNavigate } from "react-router-dom";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import jwt_decode from "jwt-decode";
import API from "../util/API"; import API from "../util/API";
import Auth from "./Auth";
import Welcome from "./protected/Welcome";
function Home({ user, handleLogout }) { function Home() {
const [items, setItems] = useState(null); const [user, setUser] = useState(null);
console.log(user); const [contents, setContents] = useState(<></>);
const [update, setUpdate] = useState(false);
const navigate = useNavigate();
async function getStatus() { async function handleLogin(info) {
const res = await API.validate(); if (!info.email || !info.password) return;
console.log(res);
const response = await API.login(info);
const user = jwt_decode(response.token);
console.log(user);
localStorage.setItem('user', JSON.stringify(user));
localStorage.setItem('token', response.token);
setUpdate(!update);
} }
async function handleLogout() {
await API.logout();
localStorage.removeItem("user");
localStorage.removeItem("token");
setUpdate(!update);
navigate('/');
}
async function handleRegister(register) {
if (!register.username || !register.email || !register.password) return;
const response = await API.register(register);
console.log(response);
if (response.ok) {
await API.login({ email: register.email, password: register.password });
}
setUpdate(!update);
}
useEffect(() => {
let item = localStorage.getItem('user');
if (item) {
item = JSON.parse(item);
setUser(item.user);
}
}, [update])
useEffect(() => {
setContents(user ? <Welcome user={user} handleLogout={handleLogout} /> : <Auth handleLogin={handleLogin} handleRegister={handleRegister} />)
}, [user, update])
return ( return (
<section> <main>
<h1>Testing user auth workflow with PERN stack</h1> <h1>This is my auth testing app</h1>
<button onClick={getStatus}>Get status</button> { contents }
</main>
{ items }
<button onClick={handleLogout}>Log Out</button>
</section>
) )
} }

View File

@@ -0,0 +1,40 @@
import { useState, useEffect } from "react";
import API from "../../util/API";
import { v4 } from "uuid";
function Items() {
const [items, setItems] = useState(<p>Loading...</p>);
const [content, setContent] = useState();
useEffect(() => {
(async() => {
try {
const data = await API.getItems();
setItems(data.map(item => (
<div className="item" key={v4()}>
<a href={`/item/${item.id}`}>{item.name}</a>
<p>{item.description}</p>
</div>
)))
} catch(e) {
setItems(
<div>
<h2>Access Forbidden</h2>
<p>{e.message}</p>
</div>
)
}
})();
}, [])
return (
<main>
<a href="/">Home</a>
<h1>List of items!</h1>
{ items }
</main>
)
}
export default Items

View File

@@ -0,0 +1,42 @@
import { useState, useEffect } from "react";
import { useParams } from "react-router-dom"
import API from "../../util/API";
function SingleItem() {
const [content, setContent] = useState(<p>Loading...</p>);
const { id } = useParams();
useEffect(() => {
(async() => {
try {
const data = await API.getOneItem(id);
console.log(data);
setContent(
<>
<h1>{data.name}</h1>
<p>{data.description}</p>
</>
)
} catch (e) {
setContent(
<div>
<h2>Access Forbidden</h2>
<p>{e.message}</p>
</div>
)
}
})();
}, []);
return (
<div>
<div>
<a href="/">Home </a>
<a href="/item">Back</a>
</div>
{ content }
</div>
)
}
export default SingleItem

View File

@@ -0,0 +1,20 @@
import { useNavigate } from "react-router-dom"
function Welcome({ user, handleLogout }) {
const navigate = useNavigate();
return (
<section>
<h2>Welcome, {user.username}!</h2>
<hr />
<h3>Check out some cool protected actions:</h3>
<div>
<button onClick={() => navigate('/item')}>View restricted content</button>
<button onClick={handleLogout}>Log Out</button>
</div>
</section>
)
}
export default Welcome

View File

@@ -51,4 +51,16 @@ export default class API {
}); });
return Promise.resolve(response.data); return Promise.resolve(response.data);
} }
static async getOneItem(id) {
const token = localStorage.getItem("token");
const response = await _api.get(`/app/item/${id}`, {
headers: {
"Content-Type": "application/json",
"Authorization": ("Bearer " + token)
}
});
return Promise.resolve(response.data);
}
} }

View File

@@ -26,7 +26,7 @@ module.exports = class Item {
static async getOne(id) { static async getOne(id) {
const query = `SELECT * FROM item WHERE id = $1`; const query = `SELECT * FROM item WHERE id = $1`;
const result = await pool.query(query, [id]); const result = await pool.query(query, [parseInt(id)]);
if (result.rows.length) { if (result.rows.length) {
return result.rows[0]; return result.rows[0];
} }

View File

@@ -17,7 +17,7 @@ async function authRoute(app, passport) {
} }
}) })
router.post('/login', passport.authenticate('local'), async (req, res, next) => { router.post('/login', async (req, res, next) => {
try { try {
const data = req.body; const data = req.body;
let response = await AuthController.login(data); let response = await AuthController.login(data);