mirror of
https://github.com/Rushilwiz/openly.git
synced 2025-04-06 21:30:17 -04:00
react components created
This commit is contained in:
parent
562b3232f9
commit
b9ca1943e3
15722
frontend/package-lock.json
generated
Normal file
15722
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -6,8 +6,11 @@
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
|
"bootstrap": "^4.6.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
|
"react-bootstrap": "^1.5.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"web-vitals": "^1.0.1"
|
"web-vitals": "^1.0.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,23 +1,32 @@
|
||||||
import logo from "./logo.svg";
|
import React, { useState } from "react";
|
||||||
import "./App.css";
|
import { BrowserRouter, Route, Switch } from "react-router-dom";
|
||||||
|
import Nav from "./components/Nav";
|
||||||
|
import Signin from "./components/auth/Signin";
|
||||||
|
import Signup from "./components/auth/Signup";
|
||||||
|
import Posts from "./components/Posts";
|
||||||
|
import Post from "./components/Post";
|
||||||
|
|
||||||
|
import Events from "./components/Events";
|
||||||
|
import Profile from "./components/Profile";
|
||||||
|
|
||||||
|
import "bootstrap/dist/css/bootstrap.min.css";
|
||||||
|
import "./App.css";
|
||||||
|
import ProtectedRoute from "./components/ProtectedRoute.js";
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<header className="App-header">
|
<BrowserRouter>
|
||||||
<img src={logo} className="App-logo" alt="logo" />
|
<Nav />
|
||||||
<p>
|
<Switch>
|
||||||
Edit <code>src/App.js</code> and save to reload.
|
<Route component={Signup} path="/register" />
|
||||||
</p>
|
<Route component={Signin} path="/login" />
|
||||||
<a
|
<ProtectedRoute component={Posts} path="/posts" />
|
||||||
className="App-link"
|
<ProtectedRoute component={Post} path="/post/:id" />
|
||||||
href="https://reactjs.org"
|
|
||||||
target="_blank"
|
<ProtectedRoute component={Events} path="/events" />
|
||||||
rel="noopener noreferrer"
|
<ProtectedRoute component={Profile} path="/profile" />
|
||||||
>
|
</Switch>
|
||||||
Learn React
|
</BrowserRouter>
|
||||||
</a>
|
|
||||||
</header>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
0
frontend/src/components/Event.js
Normal file
0
frontend/src/components/Event.js
Normal file
0
frontend/src/components/Events.js
Normal file
0
frontend/src/components/Events.js
Normal file
45
frontend/src/components/Nav.js
Normal file
45
frontend/src/components/Nav.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const Nav = (props) => {
|
||||||
|
return (
|
||||||
|
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
|
<button
|
||||||
|
className="navbar-toggler"
|
||||||
|
type="button"
|
||||||
|
data-toggle="collapse"
|
||||||
|
data-target="#navbarNavDropdown"
|
||||||
|
aria-controls="navbarNavDropdown"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-label="Toggle navigation"
|
||||||
|
>
|
||||||
|
<span className="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div className="collapse navbar-collapse" id="navbarNavDropdown">
|
||||||
|
<ul className="navbar-nav mr-auto">
|
||||||
|
<li className="nav-item">
|
||||||
|
<a className="nav-link text-white" href="/">
|
||||||
|
<span className="sr-only">(current)</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li className="nav-item">
|
||||||
|
<a className="nav-link text-white" href="/profile">
|
||||||
|
Profile <span className="sr-only">(current)</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li className="nav-item">
|
||||||
|
<a className="nav-link text-white" href="/events">
|
||||||
|
Events
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li className="nav-item">
|
||||||
|
<a className="nav-link text-white" href="/Posts">
|
||||||
|
Posts
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Nav;
|
44
frontend/src/components/Post.js
Normal file
44
frontend/src/components/Post.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
const Post = (props) => {
|
||||||
|
const [state, setState] = useState({
|
||||||
|
user: { username: "" },
|
||||||
|
post_text: "",
|
||||||
|
upvotes: 0,
|
||||||
|
keywords: [],
|
||||||
|
comments: [],
|
||||||
|
});
|
||||||
|
const [stocks, setStocks] = useState([]);
|
||||||
|
|
||||||
|
const requestOptions = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const callAPI = () => {
|
||||||
|
fetch(`${process.env.REACT_APP_API_ENDPOINT}/post/`, requestOptions)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data !== undefined) {
|
||||||
|
setState(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
callAPI();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1 className="d-flex justify-content-center m-2 p-4">Post</h1>
|
||||||
|
<div className="container">
|
||||||
|
<h1>Hello {state.user.username}!</h1>
|
||||||
|
<h2>Post {props.match.params.id}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Post;
|
0
frontend/src/components/Posts.js
Normal file
0
frontend/src/components/Posts.js
Normal file
41
frontend/src/components/Profile.js
Normal file
41
frontend/src/components/Profile.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
const Post = (props) => {
|
||||||
|
const [state, setState] = useState({
|
||||||
|
user: { username: "" },
|
||||||
|
upvotes: 0,
|
||||||
|
keywords: [],
|
||||||
|
});
|
||||||
|
const [stocks, setStocks] = useState([]);
|
||||||
|
|
||||||
|
const requestOptions = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const callAPI = () => {
|
||||||
|
fetch(`${process.env.REACT_APP_API_ENDPOINT}/post/`, requestOptions)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data !== undefined) {
|
||||||
|
setState(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
callAPI();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1 className="d-flex justify-content-center m-2 p-4">Profile</h1>
|
||||||
|
<div className="container">
|
||||||
|
<h1>Hello {state.user.username}!</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Post;
|
82
frontend/src/components/ProtectedRoute.js
Normal file
82
frontend/src/components/ProtectedRoute.js
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Route, Redirect } from "react-router-dom";
|
||||||
|
|
||||||
|
const ProtectedRoute = ({ component: Component, ...rest }) => {
|
||||||
|
const isAuthenticated = async () => {
|
||||||
|
try {
|
||||||
|
const requestOptions = {
|
||||||
|
method: "GET",
|
||||||
|
headers: { Authorization: `Bearer ${localStorage.getItem("token")}` },
|
||||||
|
};
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.REACT_APP_API_ENDPOINT}/profile`,
|
||||||
|
requestOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`Checking status! ${response.status}`);
|
||||||
|
if (response.status === 200) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
const requestOptions = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: { refresh: localStorage.getItem("refresh") },
|
||||||
|
};
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.REACT_APP_API_ENDPOINT}/token/refresh/`,
|
||||||
|
requestOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = response.json();
|
||||||
|
|
||||||
|
localStorage.setItem("token", data.access);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
const requestOptions = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: { refresh: localStorage.getItem("refresh") },
|
||||||
|
};
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.REACT_APP_API_ENDPOINT}/token/refresh/`,
|
||||||
|
requestOptions
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = response.json();
|
||||||
|
|
||||||
|
localStorage.setItem("token", data.access);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Route
|
||||||
|
{...rest}
|
||||||
|
render={(props) => {
|
||||||
|
if (isAuthenticated()) {
|
||||||
|
return <Component {...props} {...rest} />;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Redirect
|
||||||
|
to={{
|
||||||
|
pathname: "/login",
|
||||||
|
state: {
|
||||||
|
from: props.location,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProtectedRoute;
|
66
frontend/src/components/auth/Signin.js
Normal file
66
frontend/src/components/auth/Signin.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useHistory } from "react-router-dom";
|
||||||
|
|
||||||
|
const Signup = (props) => {
|
||||||
|
let history = useHistory();
|
||||||
|
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
|
const onSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const requestOptions = {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ username: username, password: password }),
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.REACT_APP_API_ENDPOINT}/token/`,
|
||||||
|
requestOptions
|
||||||
|
);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
localStorage.setItem("token", data.access);
|
||||||
|
localStorage.setItem("refresh", data.refresh);
|
||||||
|
history.push("/");
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={onSubmit}>
|
||||||
|
<div className="form-inner">
|
||||||
|
<h2>Login</h2>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="name">Username:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
onChange={(e) => {
|
||||||
|
setUsername(e.target.value);
|
||||||
|
}}
|
||||||
|
value={username}
|
||||||
|
name="name"
|
||||||
|
id="name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="password">Password:</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
onChange={(e) => {
|
||||||
|
setPassword(e.target.value);
|
||||||
|
}}
|
||||||
|
value={password}
|
||||||
|
name="password"
|
||||||
|
id="password"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Signup;
|
127
frontend/src/components/auth/Signup.js
Normal file
127
frontend/src/components/auth/Signup.js
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useHistory } from "react-router-dom";
|
||||||
|
|
||||||
|
const Signup = (props) => {
|
||||||
|
let history = useHistory();
|
||||||
|
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [verifyPassword, setVerifyPassword] = useState("");
|
||||||
|
const [email, setEmail] = useState("");
|
||||||
|
const [firstName, setFirstName] = useState("");
|
||||||
|
const [lastName, setLastName] = useState("");
|
||||||
|
|
||||||
|
const onSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (verifyPassword !== password) {
|
||||||
|
alert("The passwords don't match!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const requestOptions = {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
email: email,
|
||||||
|
first_name: firstName,
|
||||||
|
last_name: lastName,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${process.env.REACT_APP_API_ENDPOINT}/profile/create`,
|
||||||
|
requestOptions
|
||||||
|
);
|
||||||
|
const data = await response.json();
|
||||||
|
console.log(data.username);
|
||||||
|
|
||||||
|
history.push("/login");
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={onSubmit}>
|
||||||
|
<div className="form-inner">
|
||||||
|
<h2>Register</h2>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="name">Username:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
onChange={(e) => {
|
||||||
|
setUsername(e.target.value);
|
||||||
|
}}
|
||||||
|
value={username}
|
||||||
|
name="name"
|
||||||
|
id="name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="password">Password:</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
onChange={(e) => {
|
||||||
|
setPassword(e.target.value);
|
||||||
|
}}
|
||||||
|
value={password}
|
||||||
|
name="password"
|
||||||
|
id="password"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="password">Verify Password:</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
onChange={(e) => {
|
||||||
|
setVerifyPassword(e.target.value);
|
||||||
|
}}
|
||||||
|
value={verifyPassword}
|
||||||
|
name="password"
|
||||||
|
id="password"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="name">Email:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
onChange={(e) => {
|
||||||
|
setEmail(e.target.value);
|
||||||
|
}}
|
||||||
|
value={email}
|
||||||
|
name="name"
|
||||||
|
id="name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="name">First Name:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
onChange={(e) => {
|
||||||
|
setFirstName(e.target.value);
|
||||||
|
}}
|
||||||
|
value={firstName}
|
||||||
|
name="name"
|
||||||
|
id="name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="name">Last Name:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
onChange={(e) => {
|
||||||
|
setLastName(e.target.value);
|
||||||
|
}}
|
||||||
|
value={lastName}
|
||||||
|
name="name"
|
||||||
|
id="name"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Signup;
|
|
@ -3,7 +3,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>ReInvest</title>
|
<title>PoliTalk</title>
|
||||||
<link rel="stylesheet" href="css/index.css" />
|
<link rel="stylesheet" href="css/index.css" />
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
|
@ -11,17 +11,14 @@
|
||||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
|
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
|
||||||
crossorigin="anonymous"
|
crossorigin="anonymous"
|
||||||
/>
|
/>
|
||||||
<link rel="shortcut icon" href="images/logo.ico" />
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-expand-lg navbar-light">
|
<nav class="navbar navbar-expand-lg navbar-light">
|
||||||
<a href="#reinvest"
|
<a href="#reinvest"
|
||||||
><img
|
><h1 class="navbar-brand" width="100px" href="#reinvest">
|
||||||
class="navbar-brand"
|
PoliTalk
|
||||||
src="images/logo.png"
|
</h1></a
|
||||||
width="100px"
|
>
|
||||||
href="#reinvest"
|
|
||||||
/></a>
|
|
||||||
<button
|
<button
|
||||||
class="navbar-toggler"
|
class="navbar-toggler"
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -75,7 +72,9 @@
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<h1 class="text-primary bg-white rounded-lg shadow-lg p-3 mb-5">
|
<h1
|
||||||
|
class="text-primary text-center bg-white rounded-lg shadow-lg p-3 mb-5"
|
||||||
|
>
|
||||||
PoliTalk
|
PoliTalk
|
||||||
</h1>
|
</h1>
|
||||||
<br />
|
<br />
|
||||||
|
|
Loading…
Reference in New Issue
Block a user