From 629c77c110042d5160f5218bee54f76b81c4dad2 Mon Sep 17 00:00:00 2001 From: Michael Foiani Date: Tue, 20 Apr 2021 03:37:05 -0400 Subject: Multiple state changes and efficiency fixes. --- react-frontend/src/components/Hub.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'react-frontend/src/components/Hub.js') diff --git a/react-frontend/src/components/Hub.js b/react-frontend/src/components/Hub.js index 8a3ac1c..94830fa 100644 --- a/react-frontend/src/components/Hub.js +++ b/react-frontend/src/components/Hub.js @@ -10,12 +10,24 @@ import '../css/UserCheckin.css'; * @returns {import('react').HtmlHTMLAttributes} A list element holding a checkin's info. */ function Hub(props) { - // State - toggled + const [isHover, setIsHover] = useState(false); + + const formatName = name => { + if (name.length > 12) { + return props.name.substring(0, 15) + '...'; + } + return props.name; + } return ( -
  • +
  • setIsHover(true)} + onMouseLeave = {() => setIsHover(false)}>
    - console.log(props.id)}>{props.name} + console.log(props.id)}>{isHover ? props.name : formatName(props.name)} {props.value.toFixed(3)}
  • ); -- cgit v1.2.3-70-g09d2 From c4f075343f557f278b1bacb4b92891e646f8fb2a Mon Sep 17 00:00:00 2001 From: Michael Foiani Date: Tue, 20 Apr 2021 07:55:53 -0400 Subject: Finished up the front end functionality. Some issues with the backend (small NaN issues), and some elements need a little more love (styling) before demo. --- .../public/assets/outline_cancel_white_18dp.png | Bin 0 -> 388 bytes .../public/assets/outline_close_white_18dp.png | Bin 0 -> 181 bytes .../public/assets/outline_minimize_white_18dp.png | Bin 0 -> 97 bytes .../public/assets/outline_search_white_18dp.png | Bin 0 -> 397 bytes .../public/assets/outline_tune_white_18dp.png | Bin 0 -> 171 bytes .../public/assets/round_arrow_back_white_18dp.png | Bin 0 -> 163 bytes .../public/assets/round_expand_less_white_18dp.png | Bin 0 -> 170 bytes .../public/assets/round_expand_more_white_18dp.png | Bin 0 -> 166 bytes .../public/round_arrow_back_white_18dp.png | Bin 163 -> 0 bytes react-frontend/src/components/Hub.js | 15 +-- react-frontend/src/components/HubList.js | 69 ++++++++----- react-frontend/src/components/HubSearch.js | 64 ------------ react-frontend/src/components/HubWidget.js | 69 +++++++++++-- react-frontend/src/components/InvestorInfo.js | 112 ++++++++++++++------- react-frontend/src/components/TimeSelector.js | 3 +- react-frontend/src/components/Visualization.js | 16 +-- react-frontend/src/components/WatchDogs.js | 4 +- react-frontend/src/css/App.css | 1 + react-frontend/src/css/CoordSelector.css | 4 + react-frontend/src/css/InvesterInfo.css | 14 ++- react-frontend/src/css/UserCheckin.css | 34 +++++-- src/main/java/edu/brown/cs/student/term/Main.java | 3 +- .../brown/cs/student/term/profit/StockHolding.java | 35 +++++++ 23 files changed, 281 insertions(+), 162 deletions(-) create mode 100644 react-frontend/public/assets/outline_cancel_white_18dp.png create mode 100644 react-frontend/public/assets/outline_close_white_18dp.png create mode 100644 react-frontend/public/assets/outline_minimize_white_18dp.png create mode 100644 react-frontend/public/assets/outline_search_white_18dp.png create mode 100644 react-frontend/public/assets/outline_tune_white_18dp.png create mode 100644 react-frontend/public/assets/round_arrow_back_white_18dp.png create mode 100644 react-frontend/public/assets/round_expand_less_white_18dp.png create mode 100644 react-frontend/public/assets/round_expand_more_white_18dp.png delete mode 100644 react-frontend/public/round_arrow_back_white_18dp.png delete mode 100644 react-frontend/src/components/HubSearch.js (limited to 'react-frontend/src/components/Hub.js') 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 Binary files /dev/null and b/react-frontend/public/assets/outline_cancel_white_18dp.png 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 Binary files /dev/null and b/react-frontend/public/assets/outline_close_white_18dp.png 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 Binary files /dev/null and b/react-frontend/public/assets/outline_minimize_white_18dp.png 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 Binary files /dev/null and b/react-frontend/public/assets/outline_search_white_18dp.png 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 Binary files /dev/null and b/react-frontend/public/assets/outline_tune_white_18dp.png differ diff --git a/react-frontend/public/assets/round_arrow_back_white_18dp.png b/react-frontend/public/assets/round_arrow_back_white_18dp.png new file mode 100644 index 0000000..bbaccda Binary files /dev/null and b/react-frontend/public/assets/round_arrow_back_white_18dp.png 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 Binary files /dev/null and b/react-frontend/public/assets/round_expand_less_white_18dp.png 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 Binary files /dev/null and b/react-frontend/public/assets/round_expand_more_white_18dp.png differ diff --git a/react-frontend/public/round_arrow_back_white_18dp.png b/react-frontend/public/round_arrow_back_white_18dp.png deleted file mode 100644 index bbaccda..0000000 Binary files a/react-frontend/public/round_arrow_back_white_18dp.png and /dev/null 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 ( -
  • setIsHover(true)} - onMouseLeave = {() => setIsHover(false)}> +
  • console.log(props.id)}>{isHover ? props.name : formatName(props.name)} + onMouseOver = {() => setIsHover(true)} + onMouseLeave = {() => setIsHover(false)} + onClick = {() => props.setSelectedId(props.id)}>{isHover || props.searching ? props.name : formatName(props.name)} {props.value.toFixed(3)}
  • ); 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( - - ) - ); - - setHubItems(hubs); - }; - // React hook that updates when the hubs are recalculated - useEffect(() => updateHubItems(), [props.data]); - - return ; + 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 => + ; + + /** + * 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 ; } 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 =>

    {hub.name}

    )) - } - - /** - * 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 ( -
    -
    -

    Search

    - setQueryString(e.target.value)}> -
      {displayedItems}
    ; -
    -
    - ); -} - -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 ( <>
    -

    Suspicion Ranks

    - +

    + + setQueryString(e.target.value)} placeholder="Search by name"> + setSearching(true)} src="assets/outline_search_white_18dp.png" alt="image"/> + setSearching(false)} src="assets/outline_cancel_white_18dp.png" alt="image"/> +

    +
    - +
    - ); } 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) => -
  • - {'('+coord[0].toFixed(6)}, {coord[1].toFixed(6)+')'} -
  • - );*/ const stockTable = () => { return ( -
    + <> +
  • Symbol
    Realized gain
    Unrealized gain
    -
  • + + {info.holdings.map(holding => +
  • +
    {holding.ticker}
    +
    {holding.realizedGain.toFixed(3)}
    +
    {holding.unrealizedGain.toFixed(3)}
    +
  • )} + ); }; - useEffect(() => getInfo(), [props.name, props.isSelected, props.personId]); + const followerList = () => + props.followers.map(follower =>
  • props.setSelectedId(follower.id)}>{follower.name}
  • ); + + // Hook that updates when selected has changed + useEffect(() => getInfo(), [props.selectedId]); return ( -