mirror of
https://github.com/Rushilwiz/openly.git
synced 2025-04-06 05:10:18 -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/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
"bootstrap": "^4.6.0",
|
||||
"react": "^17.0.2",
|
||||
"react-bootstrap": "^1.5.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "4.0.3",
|
||||
"web-vitals": "^1.0.1"
|
||||
},
|
||||
|
|
|
@ -1,23 +1,32 @@
|
|||
import logo from "./logo.svg";
|
||||
import "./App.css";
|
||||
import React, { useState } from "react";
|
||||
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() {
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" />
|
||||
<p>
|
||||
Edit <code>src/App.js</code> and save to reload.
|
||||
</p>
|
||||
<a
|
||||
className="App-link"
|
||||
href="https://reactjs.org"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Learn React
|
||||
</a>
|
||||
</header>
|
||||
<BrowserRouter>
|
||||
<Nav />
|
||||
<Switch>
|
||||
<Route component={Signup} path="/register" />
|
||||
<Route component={Signin} path="/login" />
|
||||
<ProtectedRoute component={Posts} path="/posts" />
|
||||
<ProtectedRoute component={Post} path="/post/:id" />
|
||||
|
||||
<ProtectedRoute component={Events} path="/events" />
|
||||
<ProtectedRoute component={Profile} path="/profile" />
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
</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>
|
||||
<meta charset="UTF-8" />
|
||||
<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"
|
||||
|
@ -11,17 +11,14 @@
|
|||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<link rel="shortcut icon" href="images/logo.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light">
|
||||
<a href="#reinvest"
|
||||
><img
|
||||
class="navbar-brand"
|
||||
src="images/logo.png"
|
||||
width="100px"
|
||||
href="#reinvest"
|
||||
/></a>
|
||||
><h1 class="navbar-brand" width="100px" href="#reinvest">
|
||||
PoliTalk
|
||||
</h1></a
|
||||
>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
|
@ -75,7 +72,9 @@
|
|||
<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
|
||||
</h1>
|
||||
<br />
|
||||
|
|
Loading…
Reference in New Issue
Block a user