aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--react-frontend/public/assets/outline_cancel_white_18dp.pngbin0 -> 388 bytes
-rw-r--r--react-frontend/public/assets/outline_close_white_18dp.pngbin0 -> 181 bytes
-rw-r--r--react-frontend/public/assets/outline_minimize_white_18dp.pngbin0 -> 97 bytes
-rw-r--r--react-frontend/public/assets/outline_search_white_18dp.pngbin0 -> 397 bytes
-rw-r--r--react-frontend/public/assets/outline_tune_white_18dp.pngbin0 -> 171 bytes
-rw-r--r--react-frontend/public/assets/round_arrow_back_white_18dp.png (renamed from react-frontend/public/round_arrow_back_white_18dp.png)bin163 -> 163 bytes
-rw-r--r--react-frontend/public/assets/round_expand_less_white_18dp.pngbin0 -> 170 bytes
-rw-r--r--react-frontend/public/assets/round_expand_more_white_18dp.pngbin0 -> 166 bytes
-rw-r--r--react-frontend/src/components/Hub.js15
-rw-r--r--react-frontend/src/components/HubList.js69
-rw-r--r--react-frontend/src/components/HubSearch.js64
-rw-r--r--react-frontend/src/components/HubWidget.js69
-rw-r--r--react-frontend/src/components/InvestorInfo.js112
-rw-r--r--react-frontend/src/components/TimeSelector.js3
-rw-r--r--react-frontend/src/components/Visualization.js16
-rw-r--r--react-frontend/src/components/WatchDogs.js4
-rw-r--r--react-frontend/src/css/App.css1
-rw-r--r--react-frontend/src/css/CoordSelector.css4
-rw-r--r--react-frontend/src/css/InvesterInfo.css14
-rw-r--r--react-frontend/src/css/UserCheckin.css34
-rw-r--r--src/main/java/edu/brown/cs/student/term/Main.java3
-rw-r--r--src/main/java/edu/brown/cs/student/term/profit/StockHolding.java35
22 files changed, 281 insertions, 162 deletions
diff --git a/react-frontend/public/assets/outline_cancel_white_18dp.png b/react-frontend/public/assets/outline_cancel_white_18dp.png
new file mode 100644
index 0000000..b989e20
--- /dev/null
+++ b/react-frontend/public/assets/outline_cancel_white_18dp.png
Binary files differ
diff --git a/react-frontend/public/assets/outline_close_white_18dp.png b/react-frontend/public/assets/outline_close_white_18dp.png
new file mode 100644
index 0000000..65867f3
--- /dev/null
+++ b/react-frontend/public/assets/outline_close_white_18dp.png
Binary files differ
diff --git a/react-frontend/public/assets/outline_minimize_white_18dp.png b/react-frontend/public/assets/outline_minimize_white_18dp.png
new file mode 100644
index 0000000..a6a12d6
--- /dev/null
+++ b/react-frontend/public/assets/outline_minimize_white_18dp.png
Binary files differ
diff --git a/react-frontend/public/assets/outline_search_white_18dp.png b/react-frontend/public/assets/outline_search_white_18dp.png
new file mode 100644
index 0000000..52ffe5f
--- /dev/null
+++ b/react-frontend/public/assets/outline_search_white_18dp.png
Binary files differ
diff --git a/react-frontend/public/assets/outline_tune_white_18dp.png b/react-frontend/public/assets/outline_tune_white_18dp.png
new file mode 100644
index 0000000..4168a63
--- /dev/null
+++ b/react-frontend/public/assets/outline_tune_white_18dp.png
Binary files differ
diff --git a/react-frontend/public/round_arrow_back_white_18dp.png b/react-frontend/public/assets/round_arrow_back_white_18dp.png
index bbaccda..bbaccda 100644
--- a/react-frontend/public/round_arrow_back_white_18dp.png
+++ b/react-frontend/public/assets/round_arrow_back_white_18dp.png
Binary files differ
diff --git a/react-frontend/public/assets/round_expand_less_white_18dp.png b/react-frontend/public/assets/round_expand_less_white_18dp.png
new file mode 100644
index 0000000..a64f430
--- /dev/null
+++ b/react-frontend/public/assets/round_expand_less_white_18dp.png
Binary files differ
diff --git a/react-frontend/public/assets/round_expand_more_white_18dp.png b/react-frontend/public/assets/round_expand_more_white_18dp.png
new file mode 100644
index 0000000..f8c7213
--- /dev/null
+++ b/react-frontend/public/assets/round_expand_more_white_18dp.png
Binary files differ
diff --git a/react-frontend/src/components/Hub.js b/react-frontend/src/components/Hub.js
index 94830fa..1906684 100644
--- a/react-frontend/src/components/Hub.js
+++ b/react-frontend/src/components/Hub.js
@@ -10,24 +10,25 @@ import '../css/UserCheckin.css';
* @returns {import('react').HtmlHTMLAttributes} A list element holding a checkin's info.
*/
function Hub(props) {
+ const LEN_NAME = 15;
+
const [isHover, setIsHover] = useState(false);
const formatName = name => {
- if (name.length > 12) {
- return props.name.substring(0, 15) + '...';
+ if (name.length >= LEN_NAME) {
+ return props.name.substring(0, LEN_NAME - 3) + '...';
}
return props.name;
}
return (
- <li
- className='Checkin'
- onMouseOver = {() => setIsHover(true)}
- onMouseLeave = {() => setIsHover(false)}>
+ <li className='Checkin'>
<div className="Img-flex">
<span
className="Clickable-name"
- onClick = {() => console.log(props.id)}>{isHover ? props.name : formatName(props.name)}</span>
+ onMouseOver = {() => setIsHover(true)}
+ onMouseLeave = {() => setIsHover(false)}
+ onClick = {() => props.setSelectedId(props.id)}>{isHover || props.searching ? props.name : formatName(props.name)}</span>
<span>{props.value.toFixed(3)}</span>
</div>
</li>);
diff --git a/react-frontend/src/components/HubList.js b/react-frontend/src/components/HubList.js
index 8e00d0f..383d570 100644
--- a/react-frontend/src/components/HubList.js
+++ b/react-frontend/src/components/HubList.js
@@ -1,6 +1,7 @@
// React and component imports
import { useEffect, useState } from "react";
import Hub from "./Hub.js";
+import uuid from 'react-uuid';
// CSS import
import "../css/UserCheckin.css";
@@ -11,33 +12,53 @@ import "../css/UserCheckin.css";
* in a vertical layout.
*/
function HubList(props) {
- const [hubItems, setHubItems] = useState([]);
+ const [displayedItems, setDisplayedItems] = useState([]);
/**
- * Loads new the checkins into the current cache/map of hubs.
+ * Method that determines whehter the Hub should be showed.
+ * @returns {Boolean} True if to be shown, false if not.
*/
- const updateHubItems = () => {
- // sort and create the elemnts
- let hubs = [];
- //const sorted = props.data.sort((a, b) => b.suspicionScore - a.suspicionScore);
- props.data.forEach(hub =>
- hubs.push(
- <Hub
- key={hub.id}
- id={hub.id}
- name={hub.name}
- value={hub.suspicionScore}
- setSelected={props.setSelected}
- ></Hub>
- )
- );
-
- setHubItems(hubs);
- };
- // React hook that updates when the hubs are recalculated
- useEffect(() => updateHubItems(), [props.data]);
-
- return <ul className='Checkin-list'>{hubItems}</ul>;
+ const toInclude = holder => {
+ // TODO: add number search or differentiate between it
+ // TODO: add sus score range....
+ if (!holder) {
+ return false;
+ };
+
+ // const matchingId = holder.id.toString().includes(queryString.toLowerCase());
+ //console.log(props.queryString.toLowerCase(), props.data.length);
+ const matchingName = holder.name.toLowerCase().includes(props.queryString.toLowerCase());
+ return matchingName;
+ }
+
+ const toHubElement = hub =>
+ <Hub
+ id={hub.id}
+ name={hub.name}
+ value={hub.suspicionScore}
+ setSelectedId={props.setSelectedId}
+ searching={props.searching}
+ ></Hub>;
+
+ /**
+ * Filters the items to be shown, then created the iteams and sets the state with the items.
+ */
+ const filterItems = () => {
+ if (!props.queryString) {
+ // don't need to show all unless searching
+ return setDisplayedItems(props.data.slice(0,600).map(hub => toHubElement(hub)))
+ }
+
+ const criteria = props.data.filter(holder => toInclude(holder));
+ setDisplayedItems(criteria.map(hub => toHubElement(hub)));
+ }
+
+ /**
+ * Hook to update the items on change of the search string or update of data.
+ */
+ useEffect(() => filterItems(), [props.queryString, props.data, props.searching]);
+
+ return <ul className='Checkin-list'>{displayedItems}</ul>;
}
export default HubList;
diff --git a/react-frontend/src/components/HubSearch.js b/react-frontend/src/components/HubSearch.js
deleted file mode 100644
index 827ea6d..0000000
--- a/react-frontend/src/components/HubSearch.js
+++ /dev/null
@@ -1,64 +0,0 @@
-// React and component imports
-import { useEffect, useState } from "react";
-import InvestorInfo from "./InvestorInfo.js";
-
-// CSS import
-import '../css/UserCheckin.css';
-import Hub from "./HubList.js";
-import Search from "./HubSearch.js";
-
-/**
- * Component that build the checkin list and displays checkin info.
- * @returns {import('react').HtmlHTMLAttributes} A div with the hubs
- * in a vertical layout.
- */
-function HubSearch(props) {
- const [queryString, setQueryString] = useState("", (s) => s.toLowerCase());
- const [displayedItems, setDisplayedItems] = useState([]);
-
- /**
- * Method that determines whehter the Hub should be showed.
- * @returns {Boolean} True if to be shown, false if not.
- */
- const toInclude = holder => {
- // TODO: add number search or differentiate between it
- // TODO: add sus score range....
- if (!holder) {
- return false;
- };
-
- // const matchingId = holder.id.toString().includes(queryString.toLowerCase());
- const matchingName = holder.name.toLowerCase().includes(queryString);
- return matchingName;
- }
-
- /**
- * Filters the items to be shown, then created the iteams and sets the state with the items.
- */
- const filterItems = () => {
- console.log(queryString);
- const criteria = props.data.filter(holder => toInclude(holder));
- setDisplayedItems(criteria.map(hub => <p>{hub.name}</p>))
- }
-
- /**
- * Hook to update the items on change of the search string.
- */
- useEffect(() => filterItems(), [queryString]);
-
- // TODO: maybe have a quick explanation of what search gives...
- // TODO: have number of ceos that make it...
- // TODO: weighted search or sort after search....
- // TODO: highlight part of string that matched...
- return (
- <div className="User-checkin">
- <div className="Checkins">
- <h2>Search</h2>
- <input type="text" onChange={(e) => setQueryString(e.target.value)}></input>
- <ul className='Checkin-list'>{displayedItems}</ul>;
- </div>
- </div>
- );
-}
-
-export default HubSearch; \ No newline at end of file
diff --git a/react-frontend/src/components/HubWidget.js b/react-frontend/src/components/HubWidget.js
index de0ae32..7a82c61 100644
--- a/react-frontend/src/components/HubWidget.js
+++ b/react-frontend/src/components/HubWidget.js
@@ -1,12 +1,11 @@
// React and component imports
-import { useEffect, useState } from "react";
+import { useEffect, useState, useRef } from "react";
import Hub from "./Hub.js";
import InvestorInfo from "./InvestorInfo.js";
// CSS import
import '../css/UserCheckin.css';
import HubList from "./HubList.js";
-import HubSearch from "./HubSearch.js";
/**
* Component that build the checkin list and displays checkin info.
@@ -14,20 +13,70 @@ import HubSearch from "./HubSearch.js";
* in a vertical layout.
*/
function HubWidget(props) {
+ // States for selected person
+ const [followers, setFollowers] = useState([]);
+ const [selectedName, setSelectedName] = useState([]);
+
+ const [searching, setSearching] = useState(false);
+ const textInput = useRef();
+
+ const [showSelectedInfo, setShowSelectedInfo] = useState(false);
+
+ const updateSelected = () => {
+ props.data.forEach(holder => {
+ if (holder.id === props.selectedId) {
+ console.log(holder);
+ setFollowers(holder.followers);
+ setSelectedName(holder.name);
+ }
+ });
+ }
+
+ // Don't need to fetch if repeat id...
+ const updateSelectedId = id => {
+ setShowSelectedInfo(true);
+ props.setSelectedId(id);
+ }
+
+ // Hook to update and show the info when a user is clicked on ...
+ useEffect(() => {
+ updateSelected();
+ }, [props.selectedId]);
+ // On init, don't show...
+ useEffect(() => setShowSelectedInfo(false), []);
+
+ useEffect(() => {
+ if (searching) {
+ return;
+ }
+ textInput.current.value = "";
+ setQueryString("");
+ }, [searching])
+
+ const [queryString, setQueryString] = useState("");
+
return (
<>
<div className="User-checkin">
<div className="Checkins">
- <h2>Suspicion Ranks</h2>
- <HubList setHasLoaded={props.setHasLoaded} data={props.data} setSelected={props.setSelected} selected={props.selected} dates={props.dates}></HubList>
+ <h2 className="Img-flex Title">
+ <span hidden={searching}>Sus Ranks</span>
+ <input ref={textInput} hidden={!searching} type="text" onChange={e => setQueryString(e.target.value)} placeholder="Search by name"></input>
+ <img className="Img-btn" hidden={searching} onClick={() => setSearching(true)} src="assets/outline_search_white_18dp.png" alt="image"/>
+ <img className="Img-btn" hidden={!searching} onClick={() => setSearching(false)} src="assets/outline_cancel_white_18dp.png" alt="image"/>
+ </h2>
+ <HubList data={props.data} setSelectedId={updateSelectedId} queryString={queryString} searching={searching}></HubList>
</div>
- <HubSearch data={props.data}></HubSearch>
+ <InvestorInfo
+ selectedId={props.selectedId}
+ setSelectedId={updateSelectedId}
+ dates={props.dates}
+ setShowSelectedInfo={setShowSelectedInfo}
+ showSelectedInfo={showSelectedInfo}
+ followers={followers}
+ name={selectedName}
+ ></InvestorInfo>
</div>
- <InvestorInfo
- personId={props.selected}
- selectedId={props.selectedId}
- dates={props.dates}
- ></InvestorInfo>
</>
);
}
diff --git a/react-frontend/src/components/InvestorInfo.js b/react-frontend/src/components/InvestorInfo.js
index 2a0f0d9..3a3a11f 100644
--- a/react-frontend/src/components/InvestorInfo.js
+++ b/react-frontend/src/components/InvestorInfo.js
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
// CSS import
import "../css/UserCheckin.css";
import "../css/InvesterInfo.css";
+import uuid from "react-uuid";
/**
* Componenet for checkins. Has a toggle to show more info.
@@ -11,78 +12,115 @@ import "../css/InvesterInfo.css";
* @returns {import('react').HtmlHTMLAttributes} A list element holding a checkin's info.
*/
function InvestorInfo(props) {
- const [info, setInfo] = useState({});
+ const [info, setInfo] = useState({
+ percentGain: 0,
+ percentSP500: 0,
+ holdings: []
+ });
- const toEpochMilli = (date) => Date.parse(date);
- const getInfo = () => {
- console.log({
- person: props.name,
- start: toEpochMilli(props.dates.start),
- end: toEpochMilli(props.dates.end),
- });
+ const [showStocks, setShowStocks] = useState(false);
+ const [showFollowers, setShowFollowers] = useState(false);
- if (props.name === "") {
+ const getInfo = () => {
+ if (props.selectedId === -1) {
return;
}
+ const toEpochMilli = date => Date.parse(date);
+
+ console.log({
+ selectedId: props.selectedId,
+ startTime: toEpochMilli(props.dates.start),
+ endTime: toEpochMilli(props.dates.end),
+ });
+
fetch("http://localhost:4567/profit", {
method: "POST",
body: JSON.stringify({
- person: props.name,
- start: toEpochMilli(props.dates.start),
- end: toEpochMilli(props.dates.end),
+ selectedId: props.selectedId,
+ startTime: toEpochMilli(props.dates.start),
+ endTime: toEpochMilli(props.dates.end),
}),
headers: {
"Content-Type": "application/json",
},
credentials: "same-origin",
})
- .then((res) => {
- console.log(res);
- res.json();
- })
- .then((data) => {
- console.log(data);
- //setInfo(data);
- })
- .catch((err) => console.log(err));
+ .then(res => res.json())
+ .then(data => {
+ console.log(data);
+ setInfo(data);
+ props.setShowSelectedInfo(true);
+ })
+ .catch(err => console.log(err));
};
- /*
-
- const coords = userCoords.map((coord, index) =>
- <li key={index}>
- <span>{'('+coord[0].toFixed(6)}, {coord[1].toFixed(6)+')'}</span>
- </li>
- );*/
const stockTable = () => {
return (
- <div id="stockTable">
+ <>
+ <li class="Stock-row">
<div className="tableHeader">
<div className="symbol-row">Symbol</div>
<div className="gain-row">Realized gain</div>
<div className="gain-row">Unrealized gain</div>
</div>
- </div>
+ </li>
+ {info.holdings.map(holding =>
+ <li class="Stock-row">
+ <div className="symbol-row">{holding.ticker}</div>
+ <div className="gain-row">{holding.realizedGain.toFixed(3)}</div>
+ <div className="gain-row">{holding.unrealizedGain.toFixed(3)}</div>
+ </li>)}
+ </>
);
};
- useEffect(() => getInfo(), [props.name, props.isSelected, props.personId]);
+ const followerList = () =>
+ props.followers.map(follower => <li key={uuid()} class="Clickable-name" onClick={() => props.setSelectedId(follower.id)}>{follower.name}</li>);
+
+ // Hook that updates when selected has changed
+ useEffect(() => getInfo(), [props.selectedId]);
return (
- <div className="Chosen-user" hidden={false}>
- <h2 id="investerName">{"CRUTCHFIELD BRADFORD"}</h2>
+ <div className="Chosen-user" hidden={!props.showSelectedInfo}>
+ <h3>
+ <span onClick={() => props.setShowSelectedInfo(false)}><img className="Img-btn" src="assets/round_arrow_back_white_18dp.png" alt="image"/></span>
+ <span>CIK: {props.selectedId}</span>
+ </h3>
+ <h2 id="investerName">
+ {props.name}
+ </h2>
<div id="top-bar">
<div id="gain-number">
- <p className="bigNumber">{583}$</p> gain
+ <p className="bigNumber">{info.percentGain.toFixed(3)}$</p> gain
</div>
<div>
- <p className="bigNumber">{2.8}%</p>
- compared to {1.2}% on SP500
+ <p className="bigNumber">{info.percentGain.toFixed(3)}%</p>
+ compared to {info.percentSP500.toFixed(3)}% on SP500
</div>
</div>
- {stockTable()}
+
+ <div>
+ <div className="Checkin">
+ <div className="Img-flex">
+ <span className="tableHeader">View trades</span>
+ <img className="Img-btn" hidden={showStocks} onClick={() => setShowStocks(toggle => !toggle)} src="assets/round_expand_more_white_18dp.png" alt="image"/>
+ <img className="Img-btn" hidden={!showStocks} onClick={() => setShowStocks(toggle => !toggle)} src="assets/round_expand_less_white_18dp.png" alt="image"/>
+ </div>
+ <ul hidden={!showStocks} class="Stock-table">{stockTable()}</ul>
+ </div>
+
+ <div className="Checkin" hidden={!followerList}>
+ <div className="Img-flex">
+ <span className="tableHeader">View followers</span>
+ <img className="Img-btn" hidden={showFollowers} onClick={() => setShowFollowers(toggle => !toggle)} src="assets/round_expand_more_white_18dp.png" alt="image"/>
+ <img className="Img-btn" hidden={!showFollowers} onClick={() => setShowFollowers(toggle => !toggle)} src="assets/round_expand_less_white_18dp.png" alt="image"/>
+ </div>
+ <ul hidden={!showFollowers}>{followerList()}</ul>
+ </div>
+ </div>
+
</div>
);
}
diff --git a/react-frontend/src/components/TimeSelector.js b/react-frontend/src/components/TimeSelector.js
index 652a9ec..997494d 100644
--- a/react-frontend/src/components/TimeSelector.js
+++ b/react-frontend/src/components/TimeSelector.js
@@ -34,9 +34,8 @@ function TimeSelector(props) {
<DateSelector side={"left"} name={"Start Date"} className="Coord-select-left" clickedFunc={setCurrent}
changedFunc={setStartDate} disabled={current==='start' || props.isChanging} value={toValue(startDate)}></DateSelector>
<div>
- <h2>Adjust Timeframe</h2>
<button className="Btn Route-btn" onClick={() => changeTimeframe()}
- disabled={current!=="" || props.isChanging}>Change Timeframe</button>
+ disabled={current!=="" || props.isChanging}>Adjust Timeframe</button>
</div>
<DateSelector side={"right"} name={"End Date"} className="Coord-select-right" clickedFunc={setCurrent}
changedFunc={setEndDate} disabled={current==='end' || props.isChanging} value={toValue(endDate)}></DateSelector>
diff --git a/react-frontend/src/components/Visualization.js b/react-frontend/src/components/Visualization.js
index d374738..96b2027 100644
--- a/react-frontend/src/components/Visualization.js
+++ b/react-frontend/src/components/Visualization.js
@@ -1,6 +1,5 @@
// JS module imports
-import { useCallback, useEffect, useMemo, useRef, useState } from "react";
-import uuid from 'react-uuid';
+import { useMemo, useState } from "react";
import Graph from 'vis-react';
// CSS imports
@@ -13,6 +12,8 @@ import '../css/Canvas.css';
* @returns {import("react").HtmlHTMLAttributes} The canvas to be retured.
*/
function Visualization(props) {
+ const [key, setKey] = useState(0);
+
const [graphState, setGraphState] = useState({
nodes: [],
edges: []
@@ -27,8 +28,7 @@ function Visualization(props) {
const events = {
selectNode: event => {
- console.log(event);
- //props.setSelectedId(event.nodes[0]);
+ props.setSelectedId(event.nodes[0])
}
}
@@ -95,12 +95,16 @@ function Visualization(props) {
}
// Hooks to update graph state when data changes
- useMemo(() => setGraphState({nodes: getNodes(), edges: getEdges()}), [props.data]);
+ useMemo(() => {
+ setKey(key => key + 1);
+ setGraphState({nodes: getNodes(), edges: getEdges()})
+ }, [JSON.stringify(props.data)]);
+
return (
<div className="Map-canvas">
<Graph
- key={uuid()}
+ key={key}
graph={graphState}
options={options}
events={events}>
diff --git a/react-frontend/src/components/WatchDogs.js b/react-frontend/src/components/WatchDogs.js
index e045d82..dfe47c8 100644
--- a/react-frontend/src/components/WatchDogs.js
+++ b/react-frontend/src/components/WatchDogs.js
@@ -26,7 +26,7 @@ function WatchDogs() {
});
// State for visualization data
const [data, setData] = useState([]);
- // State for selected person
+ // State for selectedId
const [selectedId, setSelectedId] = useState(-1);
const toEpochMilli = date => Date.parse(date);
@@ -77,7 +77,7 @@ function WatchDogs() {
<div className="Canvas-filler Canvas-filler-1"></div>
<div className="Canvas-filler Canvas-filler-2"></div>
<div className="Canvas-filler Canvas-filler-3"></div>
- <HubWidget setHasLoaded={setHasLoaded} data={data} setSelected={setSelectedId} selected={selectedId} dates={dates}></HubWidget>
+ <HubWidget setHasLoaded={setHasLoaded} data={data} dates={dates} selectedId={selectedId} setSelectedId={setSelectedId}></HubWidget>
<TimeSelector isChanging={isChanging} dates={dates} setDates={setDates}></TimeSelector>
<Visualization hasLoaded={hasLoaded} data={data.slice(0, 600)} setSelectedId={setSelectedId}></Visualization>
</div>
diff --git a/react-frontend/src/css/App.css b/react-frontend/src/css/App.css
index e39eb3e..1b8de5f 100644
--- a/react-frontend/src/css/App.css
+++ b/react-frontend/src/css/App.css
@@ -7,6 +7,7 @@
grid-template-columns: max-content auto max-content max-content;
background-color: #121212;
+
}
.App-logo {
diff --git a/react-frontend/src/css/CoordSelector.css b/react-frontend/src/css/CoordSelector.css
index 881be08..e1fde99 100644
--- a/react-frontend/src/css/CoordSelector.css
+++ b/react-frontend/src/css/CoordSelector.css
@@ -49,4 +49,8 @@
width: 90%;
}
+.Flex-coord {
+ margin: auto;
+}
+
diff --git a/react-frontend/src/css/InvesterInfo.css b/react-frontend/src/css/InvesterInfo.css
index 5385965..fcfb29c 100644
--- a/react-frontend/src/css/InvesterInfo.css
+++ b/react-frontend/src/css/InvesterInfo.css
@@ -2,11 +2,11 @@
display: flex;
flex-direction: row;
justify-content: space-evenly;
- margin-bottom: 10px;
margin-right: 10px;
margin-left: 10px;
border-bottom: solid 1px white;
margin-top: 0px;
+ padding-bottom: 20px;
}
/* div {
@@ -25,16 +25,26 @@
.Chosen-user {
background-color: #333333;
color: lightgreen;
- width: 350px;
+ width: 25vw;
border-radius: 10px;
}
+.Stock-row {
+ display: flex;
+ justify-content: space-evenly;
+ color: white;
+ margin-bottom: 5px;
+}
+
.tableHeader {
display: flex;
flex-direction: row;
justify-content: left;
margin-right: 10px;
margin-left: 10px;
+ font-size: 120%;
+ padding: 5px;
+ color: lightgreen;
}
.symbol-row {
diff --git a/react-frontend/src/css/UserCheckin.css b/react-frontend/src/css/UserCheckin.css
index 141cc01..389bca6 100644
--- a/react-frontend/src/css/UserCheckin.css
+++ b/react-frontend/src/css/UserCheckin.css
@@ -20,7 +20,7 @@ ul {
z-index: 10;
background-color: #333333;
border-radius: 20px;
- margin: 5px;
+ margin: 5px 5px 5px 0;
}
.Coord-ex {
@@ -30,22 +30,28 @@ ul {
text-align: center;
}
+.Chosen-user > h3, .Checkins > h3 {
+ display: flex;
+ justify-content: space-between;
+ height: 5vh;
+ padding: 0 30px;
+}
+
.Chosen-user > h2, .Checkins > h2 {
display: flex;
- justify-content: space-evenly;
+ justify-content: center;
height: 5vh;
- padding: 0 10px;
+ padding: 0 30px;
}
.Checkin-list {
padding: 0 20px;
- height: 86vh;
+ height: 85vh;
overflow-y: scroll;
- cursor: default;
}
.User-checkin-list {
- height: 80vh;
+ height: 75vh;
overflow-y: scroll;
list-style-position: inside;
@@ -79,7 +85,7 @@ ul {
.Img-btn {
background-color: #424242;
border-radius: 50%;
- margin-right: 10px;
+ margin-left: auto;
}
.Img-btn:hover {
@@ -91,4 +97,18 @@ ul {
cursor: pointer;
text-decoration: underline;
color: lightgreen;
+}
+
+/* CSS borrowed from W3 Schools */
+input[type=text] {
+ width: 80%;
+ padding: 12px 20px;
+ box-sizing: border-box;
+ font-size: 80%;
+ background-color: lightgoldenrodyellow;
+ border-radius: 2;
+}
+
+.Title {
+ margin-top: 20px;
} \ No newline at end of file
diff --git a/src/main/java/edu/brown/cs/student/term/Main.java b/src/main/java/edu/brown/cs/student/term/Main.java
index d6948cd..6ba2393 100644
--- a/src/main/java/edu/brown/cs/student/term/Main.java
+++ b/src/main/java/edu/brown/cs/student/term/Main.java
@@ -178,6 +178,7 @@ public final class Main {
@Override
public Object handle(Request request, Response response) throws Exception {
JSONObject req = new JSONObject(request.body());
+ System.err.println("LOG: Call to /profit with " + req.toMap());
Integer holder_id = req.getInt("selectedId");
Date startPeriod = new Date(req.getLong("startTime"));
Date endPeriod = new Date(req.getLong("endTime"));
@@ -196,6 +197,7 @@ public final class Main {
res.put("percentGain", 100 * (gains / profit.getMoneyInput()));
res.put("SP500", (1 + sp500PercentGain) * profit.getMoneyInput());
res.put("percentSP500", 100 * sp500PercentGain);
+ System.err.println("LOG: Returning to GUI " + res);
return GSON.toJson(res);
}
@@ -213,7 +215,6 @@ public final class Main {
List<Trade> trades = db.getAllTradesByHolder(holder_id, startPeriod, endPeriod);
return GSON.toJson(trades);
-
}
}
diff --git a/src/main/java/edu/brown/cs/student/term/profit/StockHolding.java b/src/main/java/edu/brown/cs/student/term/profit/StockHolding.java
index 5edb5f7..dd57ce1 100644
--- a/src/main/java/edu/brown/cs/student/term/profit/StockHolding.java
+++ b/src/main/java/edu/brown/cs/student/term/profit/StockHolding.java
@@ -1,5 +1,7 @@
package edu.brown.cs.student.term.profit;
+import java.util.Objects;
+
/**
* class to map holding info for JSON.
*/
@@ -46,4 +48,37 @@ public class StockHolding {
public int getShares() {
return shares;
}
+
+ public String getTicker() {
+ return ticker;
+ }
+
+ @Override
+ public String toString() {
+ return "StockHolding{" +
+ "ticker='" + ticker + '\'' +
+ ", realizedGain=" + realizedGain +
+ ", unrealizedGain=" + unrealizedGain +
+ ", shares=" + shares +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ StockHolding that = (StockHolding) o;
+ return shares == that.shares && Objects.equals(ticker, that.ticker) &&
+ Objects.equals(realizedGain, that.realizedGain) &&
+ Objects.equals(unrealizedGain, that.unrealizedGain);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ticker, realizedGain, unrealizedGain, shares);
+ }
} \ No newline at end of file