connecting to front end
This commit is contained in:
1
client/.gitignore
vendored
1
client/.gitignore
vendored
@@ -12,6 +12,7 @@ package-lock.json
|
|||||||
dist
|
dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
|
*.env
|
||||||
|
|
||||||
# Editor directories and files
|
# Editor directories and files
|
||||||
.vscode/*
|
.vscode/*
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios": "^1.3.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
@@ -18,4 +19,4 @@
|
|||||||
"@vitejs/plugin-react": "^3.0.0",
|
"@vitejs/plugin-react": "^3.0.0",
|
||||||
"vite": "^4.0.0"
|
"vite": "^4.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,52 @@
|
|||||||
import { useState } from 'react'
|
import { useEffect, useState } from 'react';
|
||||||
import reactLogo from './assets/react.svg'
|
import Home from './pages/Home'
|
||||||
|
import API from './util/API';
|
||||||
import './App.css'
|
import './App.css'
|
||||||
|
import Auth from './pages/Auth';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [count, setCount] = useState(0)
|
const [user, setUser] = useState(null);
|
||||||
|
const [contents, setContents] = useState();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async() => {
|
||||||
|
const res = await API.validate();
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
|
if (res.user) {
|
||||||
|
setUser(res.user);
|
||||||
|
} else {
|
||||||
|
setUser(null);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setContents(user ? <Home user={user} handleLogout={handleLogout} /> : <Auth handleLogin={handleLogin} handleRegister={handleRegister} />);
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
|
async function handleLogout() {
|
||||||
|
await API.logout();
|
||||||
|
setUser(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleLogin(info) {
|
||||||
|
const res = await API.login(info);
|
||||||
|
if (res.data) setUser(res.data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleRegister(info) {
|
||||||
|
const res = await API.register(info);
|
||||||
|
console.log(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<div>
|
<h1>Auth Testing</h1>
|
||||||
<a href="https://vitejs.dev" target="_blank">
|
|
||||||
<img src="/vite.svg" className="logo" alt="Vite logo" />
|
{ contents }
|
||||||
</a>
|
|
||||||
<a href="https://reactjs.org" target="_blank">
|
|
||||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<h1>Vite + React</h1>
|
|
||||||
<div className="card">
|
|
||||||
<button onClick={() => setCount((count) => count + 1)}>
|
|
||||||
count is {count}
|
|
||||||
</button>
|
|
||||||
<p>
|
|
||||||
Edit <code>src/App.jsx</code> and save to test HMR
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<p className="read-the-docs">
|
|
||||||
Click on the Vite and React logos to learn more
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
33
client/src/components/Form.jsx
Normal file
33
client/src/components/Form.jsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
export function LoginForm({ info, setInfo }) {
|
||||||
|
return (
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label>Email</label>
|
||||||
|
<input type="text" onChange={(e) => setInfo({ ...info, email: e.target.value })} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Password</label>
|
||||||
|
<input type="password" onChange={(e) => setInfo({ ...info, password: e.target.value })} />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RegisterForm({ info, setInfo }) {
|
||||||
|
return (
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label>Username</label>
|
||||||
|
<input type="text" onChange={(e) => setInfo({ ...info, username: e.target.value })} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Email</label>
|
||||||
|
<input type="text" onChange={(e) => setInfo({ ...info, email: e.target.value })} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Password</label>
|
||||||
|
<input type="password" onChange={(e) => setInfo({ ...info, password: e.target.value })} />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
7
client/src/components/Page.jsx
Normal file
7
client/src/components/Page.jsx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function Page({ classes = "", children = <></> }) {
|
||||||
|
return (
|
||||||
|
<main className={`page ${classes}`}>
|
||||||
|
{ children }
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
54
client/src/pages/Auth.jsx
Normal file
54
client/src/pages/Auth.jsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { LoginForm, RegisterForm } from "../components/Form";
|
||||||
|
|
||||||
|
function Auth({ handleLogin, handleRegister }) {
|
||||||
|
const [info, setInfo] = useState({ username: "", email: "", password: "" });
|
||||||
|
const [mode, setMode] = useState("login");
|
||||||
|
const [form, setForm] = useState(<LoginForm info={info} setInfo={setInfo} />);
|
||||||
|
const [button, setButton] = useState(
|
||||||
|
<>
|
||||||
|
<button onClick={() => handleLogin(info)}>Login</button>
|
||||||
|
<aside>Not registered? Click <a onClick={swapForm}>here</a> to register</aside>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(mode);
|
||||||
|
}, [info]);
|
||||||
|
|
||||||
|
function swapForm() {
|
||||||
|
if (mode === "register") {
|
||||||
|
setMode("login");
|
||||||
|
setForm(<LoginForm info={info} setInfo={setInfo} />);
|
||||||
|
setButton(
|
||||||
|
<>
|
||||||
|
<button onClick={() => handleLogin(info)}>Login</button>
|
||||||
|
<aside>Not registered? Click <a onClick={swapForm}>here</a> to register</aside>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
setMode("register");
|
||||||
|
setForm(<RegisterForm info={info} setInfo={setInfo} />);
|
||||||
|
setButton(
|
||||||
|
<>
|
||||||
|
<button onClick={() => handleRegister(info)}>Register</button>
|
||||||
|
<aside>Looking for the login section? Click <a onClick={swapForm}>here</a></aside>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<LoginForm info={info} setInfo={setInfo} />
|
||||||
|
<button onClick={() => handleLogin(info)}>Login</button>
|
||||||
|
{/* <aside>Not registered? Click <a onClick={swapForm}>here</a> to register</aside> */}
|
||||||
|
|
||||||
|
<RegisterForm info={info} setInfo={setInfo} />
|
||||||
|
<button onClick={() => handleRegister(info)}>Register</button>
|
||||||
|
{/* <aside>Looking for the login section? Click <a onClick={swapForm}>here</a></aside> */}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Auth
|
||||||
38
client/src/pages/Home.jsx
Normal file
38
client/src/pages/Home.jsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import API from "../util/API";
|
||||||
|
|
||||||
|
function Home({ user, handleLogout }) {
|
||||||
|
const [items, setItems] = useState(null);
|
||||||
|
console.log(user);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (user) {
|
||||||
|
(async() => {
|
||||||
|
const myItems = await API.getItems();
|
||||||
|
|
||||||
|
setItems(myItems.map(each => <>{each.id}</>));
|
||||||
|
})();
|
||||||
|
} else {
|
||||||
|
setItems(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
async function getStatus() {
|
||||||
|
const res = await API.validate();
|
||||||
|
console.log(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<h1>Testing user auth workflow with PERN stack</h1>
|
||||||
|
<button onClick={getStatus}>Get status</button>
|
||||||
|
|
||||||
|
{ items }
|
||||||
|
|
||||||
|
<button onClick={handleLogout}>Log Out</button>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Home
|
||||||
48
client/src/util/API.js
Normal file
48
client/src/util/API.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import axiosInstance from './axiosInstance';
|
||||||
|
const _api = axiosInstance();
|
||||||
|
|
||||||
|
export default class API {
|
||||||
|
static async validate() {
|
||||||
|
try {
|
||||||
|
const response = await _api.get('/');
|
||||||
|
const data = Promise.resolve(response.data);
|
||||||
|
console.log(data);
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async login(data) {
|
||||||
|
try {
|
||||||
|
const response = await _api.post('/auth/login', data);
|
||||||
|
return Promise.resolve(response.data);
|
||||||
|
} catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async logout() {
|
||||||
|
try {
|
||||||
|
const response = await _api.delete('/auth/logout');
|
||||||
|
console.log(response);
|
||||||
|
return Promise.resolve(response.data);
|
||||||
|
} catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async register(data) {
|
||||||
|
try {
|
||||||
|
const response = await _api.post('/auth/register', data);
|
||||||
|
return Promise.resolve(response.data);
|
||||||
|
} catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getItems() {
|
||||||
|
const response = await _api.get('/app/item');
|
||||||
|
return Promise.resolve(response.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
client/src/util/axiosInstance.js
Normal file
11
client/src/util/axiosInstance.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
const apiUrl = import.meta.env.VITE_APIURL;
|
||||||
|
|
||||||
|
export default function axiosInstance() {
|
||||||
|
if (!apiUrl) {
|
||||||
|
throw new Error("API URL not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return axios.create({ baseURL: apiUrl });
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ require('dotenv').config();
|
|||||||
const secret = process.env.SECRET;
|
const secret = process.env.SECRET;
|
||||||
|
|
||||||
async function expressLoader(app) {
|
async function expressLoader(app) {
|
||||||
app.use(cors());
|
app.use(cors({ origin: "http://localhost:5173" }));
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user