diff --git a/README.md b/README.md index d4c7606a..e4d53aeb 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,21 @@ ## CryptoCompare -This is a project built for Learn Code Utrecht. +This is a project built for [Learn Code Utrecht](https://github.com/learncodeutrecht/LearnCodeUtrecht). For questions on Front End, ask [Susan](https://github.com/sepuckett86/). To run on your local computer: + Install [Node](https://nodejs.org/en/). + Clone this repository. -Navigate to main directory in your CLI. -First install necessary dependencies: + +Navigate to main directory `CryptoCurrencyFrontend` in your CLI. + +Install necessary dependencies: `npm install` -Then run a development build: + +Run a development build: `npm start` ## All content below is auto-generated upon building a new React App. diff --git a/src/App.css b/src/App.css new file mode 100644 index 00000000..5a29c04c --- /dev/null +++ b/src/App.css @@ -0,0 +1,37 @@ +.App { + text-align: center; + font-family: 'Montserrat', sans-serif; + +} + +.App-logo { + animation: App-logo-spin infinite 20s linear; + height: 80px; +} + +.App-header { + /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#7d7e7d+0,0e0e0e+100;Black+3D */ + background: rgb(125,126,125); /* Old browsers */ + background: -moz-linear-gradient(-45deg, rgba(125,126,125,1) 0%, rgba(14,14,14,1) 100%); /* FF3.6-15 */ + background: -webkit-linear-gradient(-45deg, rgba(125,126,125,1) 0%,rgba(14,14,14,1) 100%); /* Chrome10-25,Safari5.1-6 */ + background: linear-gradient(135deg, rgba(125,126,125,1) 0%,rgba(14,14,14,1) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#7d7e7d', endColorstr='#0e0e0e',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ + height: 100px; + padding: 20px; + color: white; + font-family: 'Gugi', cursive; +} + +.App-title { + font-size: 2.5em; +} + +.App-intro { + font-size: large; + font-family: 'Montserrat', sans-serif; +} + +@keyframes App-logo-spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} diff --git a/src/Components/App/App.js b/src/App.js similarity index 91% rename from src/Components/App/App.js rename to src/App.js index aa073b0f..c0021b3f 100644 --- a/src/Components/App/App.js +++ b/src/App.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import './App.css'; -import Compare from '../Compare/Compare'; +import Compare from './Scenes/Compare/Compare'; export class App extends Component { displayName: 'App'; @@ -19,8 +19,9 @@ export class App extends Component {
CryptoCompare

+
- Pick two options + Pick two cryptocurrencies:

{ + this.setState({ + data: data + }); + this.generateMenus(2); + } + ); + } + + // Method that returns data type you want + // data: {website: [{rate1: '', rate2:'', etc}, {}], website: [{}, {}], website: [{}, {}]} + // keys: rate1, rate2, pairing, date, currencies(ARRAY) + getData(dataType) { + const data = this.state.data; + // Declare empty variable for data to return at end of this method + let finalData; + + // Switch statement to handle different arguments and assign returnData + switch(dataType) { + case "currencies": + // Delare array of websites + // Example: [bitstamp, bittrex, kraken] + const websiteArray = Object.keys(data); + // Declare empty master array for currencies that will be filled by following code + let currencyArray = []; + // Cycle through each website + websiteArray.forEach(website => { + // Declare website value array + // Example: [{…}, {…}] + const websiteValueArray = data[website]; + // Cycle through each dataObject of website value array + websiteValueArray.forEach(dataObject => { + // Declare currencies for single dataObject + // Example: ["BCH", "BTC"] + const currencies = dataObject.currencies; + // Cycle through each currency + currencies.forEach(currency => { + // Check if currency is already in master currencyArray + // Only add it to currencyArray if it is not there already + if (!currencyArray.includes(currency)) { + currencyArray.push(currency) + } + }) + }) + }) + // At this point, currencyArray will be filled with all unique currencies + finalData = currencyArray; + break; + default: + finalData = data; + } + return finalData; +} + // Generates menu content based on data in this.state.data using getData method + generateMenus(numberOfMenus) { + let menus = []; + let currencies = this.getData("currencies"); + let startingId = 1; + for (let i = 0; i < numberOfMenus; i++) { + const newMenu = { + id: startingId, + items: currencies, + active: currencies[0], + key: `menu${startingId}` + }; + menus.push(newMenu); + startingId++; + + }; + this.setState({ + menus: menus + }) + } + + // Updates active menu item for display in menu + updateMenu(id, active) { + let menus = this.state.menus; + for (let i = 0; i < this.state.menus.length; i++) { + if (this.state.menus[i].id === id) { + menus[i].active = active; + this.setState({ + menus: menus + }) + } + } + } + + // Triggers a new result by updating the state of searchTerms + updateSearch() { + let searchTerms = [this.state.menus[0].active, this.state.menus[1].active]; + this.setState({ + searchTerms: searchTerms + }) + } + + render() { + + return ( + + + + ); + } +} + +export default AppContainer; diff --git a/src/Components/App/App.css b/src/Components/App/App.css deleted file mode 100644 index cb424269..00000000 --- a/src/Components/App/App.css +++ /dev/null @@ -1,31 +0,0 @@ -.App { - text-align: center; - font-family: 'Montserrat', sans-serif; -} - -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 80px; -} - -.App-header { - background-color: #222; - height: 100px; - padding: 20px; - color: white; - font-family: 'Gugi', cursive; -} - -.App-title { - font-size: 2.5em; -} - -.App-intro { - font-size: large; - font-family: 'Montserrat', sans-serif; -} - -@keyframes App-logo-spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } -} diff --git a/src/Components/Button/Button.css b/src/Components/Button/Button.css deleted file mode 100644 index 10949852..00000000 --- a/src/Components/Button/Button.css +++ /dev/null @@ -1,4 +0,0 @@ -button { - margin: 2%; - font-family: 'Montserrat', sans-serif; -} diff --git a/src/Components/Button/Button.js b/src/Components/Button/Button.js deleted file mode 100644 index 37fbe2ce..00000000 --- a/src/Components/Button/Button.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import './Button.css'; - -class Button extends React.Component { - constructor(props){ - super(props); - - this.handleClick = this.handleClick.bind(this); - } - handleClick() { - this.props.onClick(); - } - render() { - return( - - ) - } -} - -export default Button; diff --git a/src/Components/Graph/Graph.js b/src/Components/Graph/Graph.js deleted file mode 100644 index 4fd5b291..00000000 --- a/src/Components/Graph/Graph.js +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react'; -import './Graph.css'; -import * as d3 from 'd3'; - -class Graph extends React.Component { - constructor(props) { - super(props); - this.state = { - menu1: this.props.menu1.active, - menu2: this.props.menu2.active - } - - this.componentWillMount = this.componentWillMount.bind(this); - } - - componentWillMount() { - this.makeGraph(); - - } - - componentWillReceiveProps(nextProps) { - if (nextProps.menu1.active !== this.state.menu1.active && nextProps.menu2.active !== this.state.menu2.active) { - this.setState({ - menu1: nextProps.menu1.active, - menu2: nextProps.menu2.active - }) - this.makeGraph(); - } - else if (nextProps.menu1.active !== this.state.menu1.active) { - this.setState({ - menu1: nextProps.menu1.active - }) - this.makeGraph(); - } - else if (nextProps.menu2.active !== this.state.menu2.active) { - this.setState({ - menu2: nextProps.menu2.active - }) - this.makeGraph(); - } -} - - // Make array of data - makeDataArray() { - let data = []; - let menu1 = this.state.menu1; - let menu2 = this.state.menu2; - let results = this.props.results; - // Cycle through entire data set looking for a match - this.props.sites.forEach(site => { - for (let i = 0; i < results.length; i++) { - if (results[i].site === site) { - if (results[i].items.includes(menu1.active) - && results[i].items.includes(menu2.active)) { - data.push(results[i].result); - } - } - } - }) - - return data - } - - makeGraph() { - const data1 = this.makeDataArray(); - return d3.select(".graph") - .selectAll('div') - .data(data1) - .enter() - .append('div') - .style('width', function(d) { return d + 'px';}) - .text(function(d) { return d; }) - } - - render() { - return(
) - } -} - -export default Graph; diff --git a/src/Components/Result/Result.js b/src/Components/Result/Result.js deleted file mode 100644 index 7aa87ff0..00000000 --- a/src/Components/Result/Result.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import './Result.css'; - - -export class Result extends React.Component { - constructor(props) { - super(props); - this.handleClick = this.handleClick.bind(this); - } - - handleClick() { - this.props.updateSearch(); - this.props.updateShowResult(); - } - - render() { - return (
- -
-
- { this.props.showResult === true ? this.props.generateResult() - : null } -
-
) - } -} diff --git a/src/Containers/AppContainer.js b/src/Containers/AppContainer.js deleted file mode 100644 index 1994aee5..00000000 --- a/src/Containers/AppContainer.js +++ /dev/null @@ -1,114 +0,0 @@ -// This file contains the major data and needs to connect with the API. - -import React, { Component } from 'react'; -import { App } from '../Components/App/App'; - -class AppContainer extends Component { - constructor(props) { - super(props); - this.state = { - menus: [ - { - id: '1', - items: ['A', 'B', 'C'], - active: 'A', - key: 'menu1' - }, - { - id: '2', - items: ['A', 'B', 'C'], - active: 'A', - key: 'menu2' - } - ], - searchTerms: ['A', 'A'], - sites: ['Apples', 'Oranges', 'Bananas'], - results: [ - { - site: 'Bananas', - items: ['A', 'B'], - result: 85 - }, - { - site: 'Bananas', - items: ['A', 'C'], - result: 30 - }, - { - site: 'Bananas', - items: ['B', 'C'], - result: 56 - }, - { - site: 'Oranges', - items: ['A', 'B'], - result: 83 - }, - { - site: 'Oranges', - items: ['A', 'C'], - result: 35 - }, - { - site: 'Oranges', - items: ['B', 'C'], - result: 59 - }, - { - site: 'Apples', - items: ['A', 'B'], - result: 90 - }, - { - site: 'Apples', - items: ['A', 'C'], - result: 38 - }, - { - site: 'Apples', - items: ['B', 'C'], - result: 60 - }, - ] - } - - this.updateMenu = this.updateMenu.bind(this); - this.updateSearch = this.updateSearch.bind(this); - } - - // Updates active menu item for display in menu - updateMenu(id, active) { - let menus = this.state.menus; - for (let i=0; i - ); - } -} - -export default AppContainer; diff --git a/src/Containers/ResultContainer.js b/src/Containers/ResultContainer.js deleted file mode 100644 index cee366bc..00000000 --- a/src/Containers/ResultContainer.js +++ /dev/null @@ -1,94 +0,0 @@ -import React, { Component } from 'react'; -import { Result } from '../Components/Result/Result'; -import Graph from '../Components/Graph/Graph'; - -class ResultContainer extends Component { - constructor(props) { - super(props); - this.state = { - showResult: false - } - this.updateShowResult = this.updateShowResult.bind(this); - this.generateResult = this.generateResult.bind(this); - } - // Look up data for particular site - checkActive(site) { - // Define what user wants to compare - let menu1 = this.props.searchTerms[0]; - let menu2 = this.props.searchTerms[1]; - // Entire data set - let results = this.props.results; - // Cycle through entire data set looking for a match - for (let i = 0; i < results.length; i++) { - if (results[i].site === site) { - if (results[i].items.includes(menu1) - && results[i].items.includes(menu2)) { - return results[i].result; - } - } - } - } - - // Takes searchTerms and produces a table based on results - generateResult() { - let menu1 = this.props.searchTerms[0]; - let menu2 = this.props.searchTerms[1]; - - // Check if search terms are the same - if(menu1 === menu2) { - return

Pick two different options

- - // Return table and graph in two columns - } else { - return ( -
-

Comparing {menu1} + {menu2}:

-
-
- - - - - - - - - { - this.props.sites.map(site => { - return - - - - }) - } - -
SiteResult
{site}

{this.checkActive(site)}

-
-
- -
- {/*Graph goes here*/} -
-
-
) - } - } - - updateShowResult() { - this.setState({ - showResult: true - }) - } - - render() { - return ; - } - - -} - -export default ResultContainer; diff --git a/src/Components/Compare/Compare.css b/src/Scenes/Compare/Compare.css similarity index 100% rename from src/Components/Compare/Compare.css rename to src/Scenes/Compare/Compare.css diff --git a/src/Components/Compare/Compare.js b/src/Scenes/Compare/Compare.js similarity index 87% rename from src/Components/Compare/Compare.js rename to src/Scenes/Compare/Compare.js index c94048a0..18e6e458 100644 --- a/src/Components/Compare/Compare.js +++ b/src/Scenes/Compare/Compare.js @@ -1,8 +1,8 @@ import React from 'react'; import './Compare.css'; -import Menu from '../Menu/Menu'; -import ResultContainer from '../../Containers/ResultContainer'; +import Menu from './Components/Menu/Menu'; +import ResultContainer from './Components/Result/ResultContainer'; class Compare extends React.Component { @@ -25,6 +25,7 @@ class Compare extends React.Component { return (
) + } +} + +export default Graph; diff --git a/src/Components/Menu/Menu.css b/src/Scenes/Compare/Components/Menu/Menu.css similarity index 100% rename from src/Components/Menu/Menu.css rename to src/Scenes/Compare/Components/Menu/Menu.css diff --git a/src/Components/Menu/Menu.js b/src/Scenes/Compare/Components/Menu/Menu.js similarity index 86% rename from src/Components/Menu/Menu.js rename to src/Scenes/Compare/Components/Menu/Menu.js index 1c396344..d28f95e0 100644 --- a/src/Components/Menu/Menu.js +++ b/src/Scenes/Compare/Components/Menu/Menu.js @@ -4,19 +4,11 @@ import './Menu.css'; class Menu extends React.Component { constructor(props) { super(props); - - this.state = { - activeName: this.props.active - } this.handleClick = this.handleClick.bind(this); } handleClick(event) { - this.setState({ - activeName: event.target.name - }); this.props.updateMenu(this.props.menuID, event.target.name); - } render() { @@ -24,7 +16,7 @@ class Menu extends React.Component {
{ diff --git a/src/Components/Result/Result.css b/src/Scenes/Compare/Components/Result/Result.css similarity index 100% rename from src/Components/Result/Result.css rename to src/Scenes/Compare/Components/Result/Result.css diff --git a/src/Scenes/Compare/Components/Result/Result.js b/src/Scenes/Compare/Components/Result/Result.js new file mode 100644 index 00000000..a1167ba9 --- /dev/null +++ b/src/Scenes/Compare/Components/Result/Result.js @@ -0,0 +1,70 @@ +import React from 'react'; +import './Result.css'; +import Graph from '../Graph/Graph'; + + +export class Result extends React.Component { + constructor(props) { + super(props); + this.handleClick = this.handleClick.bind(this); + } + + handleClick() { + this.props.updateSearch(); + this.props.updateShowResult(); + } + + render() { + let result; + let term1 = this.props.searchTerms[0]; + let term2 = this.props.searchTerms[1]; + if (term1 === term2) { + result = (

Pick two different options

) + } else { + result = (
+

Comparing {term1} + {term2}:

+
+
+ + + + + + + + + + { + this.props.sites.map((site, i) => { + return + + + + + }) + } + +
SiteBidAsk
{site}

{this.props.dataArray[i]}

+

{this.props.dataArray[i]}

+
+
+ +
+ +
+
+
) + } + return (
+ +
+
+ { this.props.showResult === true ? result + : null } + +
+
) + } +} diff --git a/src/Scenes/Compare/Components/Result/ResultContainer.js b/src/Scenes/Compare/Components/Result/ResultContainer.js new file mode 100644 index 00000000..8739f823 --- /dev/null +++ b/src/Scenes/Compare/Components/Result/ResultContainer.js @@ -0,0 +1,70 @@ +import React, { Component } from 'react'; +import { Result } from './Result'; + +class ResultContainer extends Component { + constructor(props) { + super(props); + this.state = { + showResult: false, + dataArray: [] + } + this.updateShowResult = this.updateShowResult.bind(this); + this.setDataArray = this.setDataArray.bind(this); + } + + componentWillReceiveProps(nextProps) { + this.setDataArray(); + } + + // Generate data to display + // Takes searchTerms and returns single values for each site + // Array returned is in same order as sites array + generateDataArray() { + let dataArray = []; + const term1 = this.props.searchTerms[0]; + const term2 = this.props.searchTerms[1]; + const sites = this.props.sites; + const results = this.props.results; + sites.forEach(site => { + // Examine each result in results for site and term match + // Add match to dataArray + for (let i = 0; i < results.length; i++) { + if (results[i].site === site && results[i].items.includes(term1) === true && results[i].items.includes(term2) === true) { + dataArray.push(results[i].result); + } + } + } + ) + return dataArray; + } + + setDataArray() { + let dataArray = this.generateDataArray(); + this.setState({ + dataArray: dataArray + }) + } + + updateShowResult() { + this.setState({ + showResult: true + }) + } + + render() { + return ; + } + + +} + +export default ResultContainer; diff --git a/src/Utils/Crypto.js b/src/Utils/Crypto.js new file mode 100644 index 00000000..eb8f974a --- /dev/null +++ b/src/Utils/Crypto.js @@ -0,0 +1,21 @@ +import 'whatwg-fetch'; + +const Crypto = {}; +const baseUrl = 'http://206.189.12.80:8000/test_view/'; +// const starApi = 'https://swapi.co/api/people/1/' + +Crypto.getData = () => { + const url = `${baseUrl}`; + + return fetch(url).then(response => { + if (!response.ok) { + return new Promise(resolve => resolve([])); + } + return response.json().then(jsonResponse => { + console.log(jsonResponse); + return jsonResponse; + }); + }); +}; + +export default Crypto; diff --git a/src/index.css b/src/index.css index b4cc7250..511c0776 100644 --- a/src/index.css +++ b/src/index.css @@ -2,4 +2,10 @@ body { margin: 0; padding: 0; font-family: sans-serif; + /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#f7f7f7+7,ffffff+43,ffffff+52,ffffff+62,f7f7f7+91 */ +background: rgb(247,247,247); /* Old browsers */ +background: -moz-linear-gradient(left, rgba(247,247,247,1) 7%, rgba(255,255,255,1) 43%, rgba(255,255,255,1) 52%, rgba(255,255,255,1) 62%, rgba(247,247,247,1) 91%); /* FF3.6-15 */ +background: -webkit-linear-gradient(left, rgba(247,247,247,1) 7%,rgba(255,255,255,1) 43%,rgba(255,255,255,1) 52%,rgba(255,255,255,1) 62%,rgba(247,247,247,1) 91%); /* Chrome10-25,Safari5.1-6 */ +background: linear-gradient(to right, rgba(247,247,247,1) 7%,rgba(255,255,255,1) 43%,rgba(255,255,255,1) 52%,rgba(255,255,255,1) 62%,rgba(247,247,247,1) 91%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ +filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f7f7f7', endColorstr='#f7f7f7',GradientType=1 ); /* IE6-9 */ } diff --git a/src/index.js b/src/index.js index 23f8547f..59ee6724 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; -import AppContainer from './Containers/AppContainer'; +import AppContainer from './AppContainer'; import registerServiceWorker from './registerServiceWorker'; ReactDOM.render(, document.getElementById('root'));