aboutsummaryrefslogtreecommitdiff
path: root/react-frontend/src
diff options
context:
space:
mode:
authorJulia McCauley <skurvyj@gmail.com>2021-04-18 20:28:46 -0400
committerJulia McCauley <skurvyj@gmail.com>2021-04-18 20:28:46 -0400
commit8019e169643d2d988e994470cdd814dca83ecb28 (patch)
treec80bd0ab62e9b9432911827161f42c13b4783ae1 /react-frontend/src
parent79ff716c29a80d7a53abce69cb406a23953320c8 (diff)
parentf0866fc8c35b2124d1690ff83fc6a55c3e720eda (diff)
pulling latest changes Merge branch 'master' of github.com:cs0320-2021/term-project-cohwille-jmccaul3-mfoiani-rhunt2
Diffstat (limited to 'react-frontend/src')
-rw-r--r--react-frontend/src/App.js226
-rw-r--r--react-frontend/src/components/WatchDogs.js89
-rw-r--r--react-frontend/src/css/App.css1
-rw-r--r--react-frontend/src/css/Landing.css322
-rw-r--r--react-frontend/src/images/mainlogo.png (renamed from react-frontend/src/components/images/mainlogo.png)bin269065 -> 269065 bytes
5 files changed, 406 insertions, 232 deletions
diff --git a/react-frontend/src/App.js b/react-frontend/src/App.js
index 0a6e6c1..a639edd 100644
--- a/react-frontend/src/App.js
+++ b/react-frontend/src/App.js
@@ -1,89 +1,161 @@
// React/component imports
import React, {useEffect, useState} from 'react';
-import TimeSelector from './components/TimeSelector.js';
-import Visualization from './components/Visualization.js';
-import HubList from './components/HubList.js';
-import Loading from './components/Loading.js';
-import Modal from './components/Modal.js';
-import logo from './components/images/logo.png';
-
-// CSS import
-import './css/App.css';
-
-/**
- * Main component of the app. Holds the main layout of the big components.
- * @returns {import('react').HtmlHTMLAttributes} A div of the body of the page.
- */
+import WatchDogs from './components/WatchDogs.js';
+import reagan from './images/reagan.png';
+import previewwatchdog from './images/previewwatchdog.png';
+import mainlogo from './images/mainlogo.png';
+
+
+import './css/Landing.css';
+
function App() {
- // State to open app when loaded
- const [hasLoaded, setHasLoaded] = useState(false);
- // State indicate if canvas is redrawing
- const [isChanging, setIsChanging] = useState(false);
- // State to hold dates -> two weeks apart on initialization.
- const [dates, setDates] = useState({
- start: new Date(Date.now() - 12096e5),
- end: new Date()
- });
- // State for visualization data
- const [data, setData] = useState([]);
- // State for selected person
- const [selected, setSelected] = useState(-1);
-
- const toEpochMilli = date => Date.parse(date);
- const getGraphData = () => {
- console.log({
- start: toEpochMilli(dates.start),
- end: toEpochMilli(dates.end)
- });
- fetch("http://localhost:4567/data", {
- method: "POST",
- body: JSON.stringify({
- start: toEpochMilli(dates.start),
- end: toEpochMilli(dates.end)
- }),
- headers: {
- "Content-Type": "application/json",
- },
- credentials: "same-origin"
- })
- .then(res => res.json())
- .then(data => {
- //TODO: optimize this
- const sliced = data.holders.slice(0, 500);
- console.log(sliced);
- setData(sliced);
- setHasLoaded(true);
- })
- .catch(err => console.log(err));
-
- setIsChanging(false);
- }
-
-
- // Hooks to update data on init and switching of data
- //useEffect(() => getGraphData(), []);
- useEffect(() => {
- setIsChanging(true);
- getGraphData();
- }, [dates]);
+ const [startApp, setStartApp] = useState(false);
+
+ const startModal = () => {
+ document.getElementById("main-modal").style.display = 'block';
+ setStartApp(false);
+ }
+ const exitModal = () => {
+ document.getElementById("main-modal").style.display = 'none';
+ setStartApp(true);
+ }
+
return (
<>
- {(!hasLoaded) ? <Loading></Loading> :
- <div className="App">
- <Modal>PHP</Modal>
- <header id="in-app-logo-holder" className="App-header">
- <img id="in-app-logo" src={logo} alt="logo"/></header>
- <div className="Canvas-filler Canvas-filler-1"></div>
- <div className="Canvas-filler Canvas-filler-2"></div>
- <div className="Canvas-filler Canvas-filler-3"></div>
- <HubList setHasLoaded={setHasLoaded} data={data} setSelected={setSelected} selected={selected} dates={dates}></HubList>
- <TimeSelector isChanging={isChanging} dates={dates} setDates={setDates}></TimeSelector>
- <Visualization hasLoaded={hasLoaded} data={data} setSelected={setSelected}></Visualization>
+
+ {(!startApp) ?
+ <div className="body" id="main-modal">
+ <div class="nav-bar">
+ <div class="topnav">
+ <a href="#team">Team</a>
+ <a href="#app-intro">About</a>
+ <a href="#intro">Home</a>
+ </div>
+ </div>
+
+ <main>
+
+ <section id="intro" class="intro">
+ <img src={mainlogo} alt="logo"></img>
+ <button id="enter-watchdogs" onClick={exitModal}>ENTER</button>
+ </section>
+
+ <section id="1" class="app-preview">
+ <img id="preview" src={previewwatchdog}></img>
+ <span id="preview-text">preview</span>
+ </section>
+
+ <section id="app-intro">
+ <h1 class="heading">About Our App</h1>
+ <p></p>
+ <p class="text">WatchDogs utilizes a simple,
+ interactive interface to provide you with the latest
+ data relating to high-profile investors’ trades. Directly from
+ the SEC, WatchDogs relays information regarding “inside” investors
+ and their recent trades, as well as provides computed values such
+ as an individual’s net profit from a stock at time of trade and a
+ ranking of individuals most likely recently involved in insider trading.
+ The computed “suspicion ranks” are determined using multiple factors
+ (including recent trade profitability and investor connectedness)
+ and a complex algorithm. For added convenience, YOU choose the
+ timeframe WatchDogs considers when analyzing trade data. WatchDogs
+ makes insider trade data accessible to the public, and provides
+ low-level intuition regarding which investors are more and less
+ likely to be committing unlawful insider trading.</p>
+ <div class="appinfotxt">It is important to remember that suspicion
+ ranks returned by WatchDogs’ algorithm DO NOT prove--or even suggest--that
+ an individual has engaged in insider trading. WatchDogs suspicion
+ ranks should not be interpreted as indication of an individual’s
+ participation in illegal activity. WatchDogs data, including suspicion ranks,
+ cannot be used as evidence in legal proceedings. Please use WatchDogs
+ as it is intended, and use discretion when interpreting algorithmic
+ results.</div>
+ <p></p>
+ <p class="text h2">The Data</p>
+ <div class="text">WatchDogs uses data retrieved from SEC.gov’s
+ EDGAR API. Trades analyzed by WatchDogs are of the type Form 4,
+ meaning the filing individual is an “insider” (e.g. the CEO) at
+ the company whose stock they are trading. In-app data relating
+ to investors, trades, and profitability is accessible to the public via
+ the SEC, and only public data is input to the SuspicionRank algorithm.</div>
+ <p></p>
+ <p class="text h2">Our Algorithm</p>
+ <div class="text">WatchDogs suspicion rank represents the likelihood
+ of an individual being involved in insider trading. The SuspicionRank algorithm,
+ a derivative of Lary Page’s PageRank algorithm, considers “insiders” who similarly
+ trade stocks (within a given timeframe) as “linked”, while simultaneously
+ considering involved individuals’ net profit on their stocks at the time
+ of trade. (Obviously, an “inside” investor who makes a counter-productive
+ trade is not likely to be insider trading.)</div>
+ <p></p><p></p><p></p><p></p><p></p>
+ </section>
+
+ <section id="team">
+ <div class="team">
+ <div id="team-holder" class="center">
+ <h1 id="team-heading" class="heading">Meet the Team</h1>
+ <div id="people-holder">
+ <div class="team-person-holder">
+ <div class="team-person">
+ <img src="" height="100%"></img>
+ </div>
+ <p class="team-text">Clark Oh-Willeke</p>
+ </div>
+
+ <div class="team-person-holder">
+ <div class="team-person">
+ <img src="" height="100%"></img>
+ </div>
+ <p class="team-text">Julia McCauley</p>
+ </div>
+
+ <div class="team-person-holder">
+ <div class="team-person">
+ <img src="" height="100%"></img>
+ </div>
+ <p class="team-text">Michael Foiani</p>
+ </div>
+
+ <div class="team-person-holder">
+ <div class="team-person">
+ <img src={reagan} height="100%"></img>
+ </div>
+ <p class="team-text">Reagan Hunt</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </section>
+ </main>
+
+ <footer id="footer">
+ <p></p>
+ <div class="footer-item">Disclaimer</div>
+ <p></p>
+ <div class="footer-subtext">Suspicion ranks returned by <span>WatchDogs</span>’
+ algorithm DO NOT prove--or even suggest--that an individual has
+ engaged in insider trading. <span>WatchDogs</span> suspicion ranks should not
+ be interpreted as indication of an individual’s participation in
+ illegal activity. <span>WatchDogs</span> data, including suspicion ranks, cannot
+ be used as evidence in legal proceedings. Please use WatchDogs as
+ it is intended, and use discretion when interpreting algorithmic results.
+ </div>
+ <p></p>
+ </footer>
</div>
+
+ :
+ <WatchDogs></WatchDogs>
}
+
</>
);
}
-export default App;
+
+
+
+
+
+export default App; \ No newline at end of file
diff --git a/react-frontend/src/components/WatchDogs.js b/react-frontend/src/components/WatchDogs.js
new file mode 100644
index 0000000..d631ea9
--- /dev/null
+++ b/react-frontend/src/components/WatchDogs.js
@@ -0,0 +1,89 @@
+// React/component imports
+import React, {useEffect, useState} from 'react';
+import TimeSelector from './TimeSelector.js';
+import Visualization from './Visualization.js';
+import HubList from './HubList.js';
+import Loading from './Loading.js';
+import Modal from './Modal.js';
+import logo from './images/logo.png';
+
+// CSS import
+import '../css/App.css';
+
+/**
+ * Main component of the app. Holds the main layout of the big components.
+ * @returns {import('react').HtmlHTMLAttributes} A div of the body of the page.
+ */
+function WatchDogs() {
+ // State to open app when loaded
+ const [hasLoaded, setHasLoaded] = useState(false);
+ // State indicate if canvas is redrawing
+ const [isChanging, setIsChanging] = useState(false);
+ // State to hold dates -> two weeks apart on initialization.
+ const [dates, setDates] = useState({
+ start: new Date(Date.now() - 12096e5),
+ end: new Date()
+ });
+ // State for visualization data
+ const [data, setData] = useState([]);
+ // State for selected person
+ const [selected, setSelected] = useState(-1);
+
+ const toEpochMilli = date => Date.parse(date);
+ const getGraphData = () => {
+ console.log({
+ start: toEpochMilli(dates.start),
+ end: toEpochMilli(dates.end)
+ });
+ fetch("http://localhost:4567/data", {
+ method: "POST",
+ body: JSON.stringify({
+ start: toEpochMilli(dates.start),
+ end: toEpochMilli(dates.end)
+ }),
+ headers: {
+ "Content-Type": "application/json",
+ },
+ credentials: "same-origin"
+ })
+ .then(res => res.json())
+ .then(data => {
+ //TODO: optimize this
+ const sliced = data.holders.slice(0, 500);
+ console.log(sliced);
+ setData(sliced);
+ setHasLoaded(true);
+ })
+ .catch(err => console.log(err));
+
+ setIsChanging(false);
+ }
+
+
+ // Hooks to update data on init and switching of data
+ //useEffect(() => getGraphData(), []);
+ useEffect(() => {
+ setIsChanging(true);
+ getGraphData();
+ }, [dates]);
+
+ return (
+ <>
+ {(!hasLoaded) ? <Loading></Loading> :
+ <div className="App">
+ <Modal>PHP</Modal>
+ <header id="in-app-logo-holder" className="App-header">
+ <img id="in-app-logo" src={logo} alt="logo"/></header>
+ <div className="Canvas-filler Canvas-filler-1"></div>
+ <div className="Canvas-filler Canvas-filler-2"></div>
+ <div className="Canvas-filler Canvas-filler-3"></div>
+ <HubList setHasLoaded={setHasLoaded} data={data} setSelected={setSelected} selected={selected} dates={dates}></HubList>
+ <TimeSelector isChanging={isChanging} dates={dates} setDates={setDates}></TimeSelector>
+ <Visualization hasLoaded={hasLoaded} data={data} setSelected={setSelected}></Visualization>
+ </div>
+ }
+ </>
+ );
+}
+
+export default WatchDogs;
diff --git a/react-frontend/src/css/App.css b/react-frontend/src/css/App.css
index f632a7f..e39eb3e 100644
--- a/react-frontend/src/css/App.css
+++ b/react-frontend/src/css/App.css
@@ -6,6 +6,7 @@
grid-template-rows: max-content auto max-content;
grid-template-columns: max-content auto max-content max-content;
background-color: #121212;
+
}
.App-logo {
diff --git a/react-frontend/src/css/Landing.css b/react-frontend/src/css/Landing.css
index c2bc567..58658b0 100644
--- a/react-frontend/src/css/Landing.css
+++ b/react-frontend/src/css/Landing.css
@@ -1,244 +1,256 @@
html {
- scroll-behavior: smooth;
- }
+ scroll-behavior: smooth;
+ z-index: 1000;
+
+}
.nav-bar{
- position: fixed;
- top: 0px;
- left: 0px;
- width: 100vw;
- height: 70px;
- background-color: rgb(7, 7, 44);
- z-index: 100;
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100vw;
+ height: 70px;
+ background-color: rgb(7, 7, 44);
+ z-index: 100;
}
.topnav {
- background-color: rgb(7, 7, 44);
- overflow: hidden;
- margin-right: 30px;
+ background-color: rgb(7, 7, 44);
+ overflow: hidden;
+ margin-right: 30px;
}
.topnav a {
- float: right;
- color: #f2f2f2;
- text-align: center;
- padding: 14px 16px;
- text-decoration: none;
- font-size: 17px;
- height: 30px;
- padding-top: 25px;
+ float: right;
+ color: #f2f2f2;
+ text-align: center;
+ padding: 14px 16px;
+ text-decoration: none;
+ font-size: 17px;
+ height: 30px;
+ padding-top: 25px;
}
.topnav a:hover {
- background-color: rgb(17, 11, 99);
- color: white;
+ background-color: rgb(17, 11, 99);
+ color: white;
}
.topnav a.active {
- background-color: #4CAF50;
- color: white;
+ background-color: #4CAF50;
+ color: white;
}
-body {
- background-color: #f3f3f3;
- font-family:Verdana, Geneva, Tahoma, sans-serif;
- overflow-y: scroll;
- overflow-x: hidden;
- display: flex;
- flex-direction: column;
- width: 80vw;
- scroll-behavior: smooth slow;
+.body {
+ background-color: #f3f3f3;
+ font-family:Verdana, Geneva, Tahoma, sans-serif;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ display: flex;
+ flex-direction: column;
+ width: 100vw;
+ scroll-behavior: smooth slow;
+ z-index: 100;
}
main {
- margin-top: 65px;
- display: flex;
- flex-direction: column;
+ margin-top: 65px;
+ display: flex;
+ flex-direction: column;
}
.intro {
- height: 900px;
- width: 100vw;
- background-color: rgb(3, 2, 24);
- color: white;
- position: relative;
- left: -10px;
+ height: 900px;
+ width: 100vw;
+ background-color: rgb(3, 2, 24);
+ color: white;
+ position: relative;
+ left: -10px;
}
#enter-watchdogs {
- background-color: rgb(206, 206, 206);
- color: rgba(10, 9, 71);
- border: 2px solid rgb(255, 255, 255);
- border-radius: 5px;
- padding: 5px 10px;
- text-align: center;
- text-decoration: none;
- display: inline-block;
- font-size: 16px;
- height: 70px;
- width: 200px;
- font-weight: bold;
- font-family:sans-serif;
+ background-color: rgb(206, 206, 206);
+ color: rgba(10, 9, 71);
+ border: 2px solid rgb(255, 255, 255);
+ border-radius: 5px;
+ padding: 5px 10px;
+ text-align: center;
+ text-decoration: none;
+ display: inline-block;
+ font-size: 16px;
+ height: 70px;
+ width: 200px;
+ font-weight: bold;
+ font-family:sans-serif;
}
#enter-watchdogs:hover {
- background-color: #94ff73;
- }
+ background-color: #94ff73;
+}
.app-preview {
- height: 900px;
- width: 100vw;
- background-color: #b7ffb9;
- color: white;
- position: relative;
- left: 0px;
- position: relative;
- left: -10px;
+ height: 900px;
+ width: 100vw;
+ background-color: #b7ffb9;
+ color: white;
+ position: relative;
+ left: 0px;
+ position: relative;
+ left: -10px;
}
#preview {
- width: 70vw;
- border: 10px solid rgb(255, 255, 255);
- border-radius: 5px;
+ width: 70vw;
+ border: 10px solid rgb(255, 255, 255);
+ border-radius: 5px;
}
#preview-text {
- color:#868686;
- font-size: small;
+ color:#868686;
+ font-size: small;
}
section {
- width: 100vw;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
+width: 100vw;
+overflow: hidden;
+display: flex;
+flex-direction: column;
+justify-content: center;
+align-items: center;
}
#app-intro{
- padding-top: 160px;
- height: fit-content;
- width: 100vw;
+padding-top: 160px;
+height: fit-content;
+width: 100vw;
}
.team {
- width: 100%;
- max-width: 1600px;
- display: flex;
- flex-direction: row;
- justify-content: space-evenly;
- padding-top: 0px;
- width: 80%;
- min-height: 500px;
- align-items: center;
+width: 100%;
+max-width: 1600px;
+display: flex;
+flex-direction: row;
+justify-content: space-evenly;
+padding-top: 0px;
+width: 80%;
+min-height: 500px;
+align-items: center;
}
.center {
- display: flex;
- flex-direction: column;
- justify-content: center;
+display: flex;
+flex-direction: column;
+justify-content: center;
}
.heading{
- font-size: 45px;
- margin: 10px 0 0 0;
- text-align: center;
- font-weight: bold;
+font-size: 45px;
+margin: 10px 0 0 0;
+text-align: center;
+font-weight: bold;
}
.text{
- color: rgba(0,0,0, 0.6);
- font-size: 18px;
- display: flex;
- justify-content: center;
- align-items: center;
- text-align: center;
- max-width: 700px;
- margin: 10px 0 20px 0;
+color: rgba(0,0,0, 0.6);
+font-size: 18px;
+display: flex;
+justify-content: center;
+align-items: center;
+text-align: center;
+max-width: 70vw;
+margin: 10px 0 20px 0;
}
#team {
- width: 100vw;
- padding: 50px 0 200px 0;
- justify-content: flex-start;
- background-color: #cccccc;
- position: relative;
- left: -10px;
+width: 100vw;
+padding: 50px 0 200px 0;
+justify-content: flex-start;
+background-color: #cccccc;
+position: relative;
+left: -10px;
}
#team-heading{
- margin-bottom: 0px;
+margin-bottom: 0px;
}
#team-holder {
- flex-direction: column;
- max-width: 1000px;
- max-height: 500px;
- height: 500px;
+flex-direction: column;
+max-width: 1000px;
+max-height: 500px;
+height: 500px;
}
#people-holder{
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: center;
- width: 100%;
+display: flex;
+flex-direction: row;
+justify-content: center;
+align-items: center;
+width: 100%;
}
.team-person-holder{
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- margin-top: 50px;
+display: flex;
+flex-direction: column;
+justify-content: center;
+align-items: center;
+margin-top: 50px;
}
.team-person{
- border-radius: 100px;
- overflow: hidden;
- margin: 20px;
- height: 200px;
- width: 200px;
- box-shadow: 0 0 2px 2px rgba(0,0,0,0.15);
+border-radius: 100px;
+overflow: hidden;
+margin: 20px;
+height: 200px;
+width: 200px;
+box-shadow: 0 0 2px 2px rgba(0,0,0,0.15);
}
.team-text{
- color: rgba(0,0,0, 1);
- font-size: 18px;
+color: rgba(0,0,0, 1);
+font-size: 18px;
+display: flex;
+justify-content: center;
+align-items: center;
+text-align: center;
+max-width: 700px;
+margin: 0;
+}
+
+#footer {
+ width: 100vw;
+ background: rgb(7, 7, 44);
display: flex;
+ flex-direction: column;
justify-content: center;
align-items: center;
- text-align: center;
- max-width: 700px;
- margin: 0;
+ position: relative;
+ left: -10px;
+ height: fit-content;
+ width: 100vw;
}
-#footer {
- width: 100vw;
- background: rgb(7, 7, 44);
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- position: relative;
- left: -10px;
- height: fit-content;
- width: 100vw;
- }
-
.footer-item{
- color: white;
- font-size: 20px;
+ color: white;
+ font-size: 20px;
}
.footer-subtext{
- color: white;
- font-size: 15px;
- width: 80vw;
+ color: white;
+ font-size: 15px;
+ width: 80vw;
}
.appinfotxt {
- font-size: 15px;
- color:rgb(3, 2, 24);
+font-size: 15px;
+color:rgb(3, 2, 24);
+max-width: 70vw;
+}
+
+.h2 {
+font-size: 30px;
+color: black;
}
+#return-to-landing {
+z-index: 1000;
+}
diff --git a/react-frontend/src/components/images/mainlogo.png b/react-frontend/src/images/mainlogo.png
index a26df0f..a26df0f 100644
--- a/react-frontend/src/components/images/mainlogo.png
+++ b/react-frontend/src/images/mainlogo.png
Binary files differ