appears to have a protected route
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
40
client/src/pages/protected/Items.jsx
Normal file
40
client/src/pages/protected/Items.jsx
Normal 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
|
||||||
42
client/src/pages/protected/SingleItem.jsx
Normal file
42
client/src/pages/protected/SingleItem.jsx
Normal 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
|
||||||
20
client/src/pages/protected/Welcome.jsx
Normal file
20
client/src/pages/protected/Welcome.jsx
Normal 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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user