diff --git a/package.json b/package.json index e5681d9..e258f8e 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,17 @@ "version": "0.1.0", "private": true, "dependencies": { + "axios": "^0.19.0", + "bootstrap": "^4.3.1", + "node-sass": "^4.12.0", "react": "^16.9.0", "react-dom": "^16.9.0", - "react-scripts": "3.1.2" + "react-redux": "^7.1.1", + "react-scripts": "3.1.2", + "react-select": "^3.0.5", + "reactstrap": "^8.0.1", + "redux": "^4.0.4", + "redux-thunk": "^2.3.0" }, "scripts": { "start": "react-scripts start", diff --git a/public/favicon.ico b/public/favicon.ico index c2c86b8..9174edb 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html index a146b6f..b9db2ff 100644 --- a/public/index.html +++ b/public/index.html @@ -24,7 +24,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - React App + Crypto Currency Calculator diff --git a/src/App.css b/src/App.css deleted file mode 100644 index afc3885..0000000 --- a/src/App.css +++ /dev/null @@ -1,22 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #09d3ac; -} diff --git a/src/App.js b/src/App.js index ce9cbd2..e23fb5b 100644 --- a/src/App.js +++ b/src/App.js @@ -1,24 +1,11 @@ import React from 'react'; -import logo from './logo.svg'; -import './App.css'; +import './App.scss'; +import Currencies from './modules/calculator/components/Currencies'; function App() { return (
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
+
); } diff --git a/src/App.scss b/src/App.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/config/service/index.js b/src/config/service/index.js new file mode 100644 index 0000000..b545e49 --- /dev/null +++ b/src/config/service/index.js @@ -0,0 +1,2 @@ +export const API_BASE_PATH = "https://api.coinlore.com/api"; +export const CURRENCY_LIST_URL = "tickers/"; \ No newline at end of file diff --git a/src/helpers/apiService.js b/src/helpers/apiService.js new file mode 100644 index 0000000..8299d99 --- /dev/null +++ b/src/helpers/apiService.js @@ -0,0 +1,31 @@ +import axios from "axios"; +import {API_BASE_PATH} from '../config/service'; +export const WEB_REQUEST_TYPE = { POST: "POST", GET: "GET", DELETE: "DELETE", PUT: "PUT" }; +/** + * Method for handling all api call to the server + * @param method + * @param url + * @param params + */ +axios.interceptors.response.use((response) => { + return response; +}, error => { + return Promise.reject(error.response); +}); + +export const getApiService = ( method, url) => { + return axios({ + method: method, + url: url, + baseURL: API_BASE_PATH, + headers: { + "Content-Type": "application/json" + } + }) + .then(response => { + return response; + }) + .catch(error => { + throw JSON.stringify(error); + }); +}; \ No newline at end of file diff --git a/src/index.js b/src/index.js index 87d1be5..31ca4d3 100644 --- a/src/index.js +++ b/src/index.js @@ -1,10 +1,33 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import './index.css'; -import App from './App'; -import * as serviceWorker from './serviceWorker'; +import React from "react"; +import axios from "axios"; +import { API_BASE_PATH } from "./config/service"; +import ReactDOM from "react-dom"; +import ReduxThunk from "redux-thunk"; +import { Provider } from "react-redux"; +import "./index.css"; +import App from "./App"; +import * as serviceWorker from "./serviceWorker"; +import { createStore, applyMiddleware, compose } from "redux"; +import reducers from "./root-reducer"; +import "bootstrap/dist/css/bootstrap.min.css"; -ReactDOM.render(, document.getElementById('root')); +axios.defaults.baseURL = API_BASE_PATH; +axios.defaults.headers.common["Content-Type"] = "application/json"; + +const composeEnhancers = + typeof window === "object" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ + ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) + : compose; + +const enhancer = composeEnhancers(applyMiddleware(ReduxThunk)); +const store = createStore(reducers, enhancer); + +ReactDOM.render( + + + , + document.getElementById("root") +); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 2e5df0d..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/modules/calculator/actionTypes/currencies.js b/src/modules/calculator/actionTypes/currencies.js new file mode 100644 index 0000000..c8d1166 --- /dev/null +++ b/src/modules/calculator/actionTypes/currencies.js @@ -0,0 +1,3 @@ +export const GET_CURRENCY_LIST_REQUEST = "GET_CURRENCY_LIST_REQUEST"; +export const GET_CURRENCY_LIST_SUCCESS = "GET_CURRENCY_LIST_SUCCESS"; +export const GET_CURRENCY_LIST_FAILURE = "GET_CURRENCY_LIST_FAILURE"; \ No newline at end of file diff --git a/src/modules/calculator/actions/currencies.js b/src/modules/calculator/actions/currencies.js new file mode 100644 index 0000000..dbcc60f --- /dev/null +++ b/src/modules/calculator/actions/currencies.js @@ -0,0 +1,27 @@ +import { + GET_CURRENCY_LIST_REQUEST, + GET_CURRENCY_LIST_SUCCESS, + GET_CURRENCY_LIST_FAILURE +} from "../actionTypes/currencies"; + +import { getAllCurrencies } from "../services/currencies"; + +export const getCurrencies = () => dispatch => { + const params = "start=0&limit=30"; + dispatch({ + type: GET_CURRENCY_LIST_REQUEST + }); + getAllCurrencies(params) + .then(data => { + dispatch({ + type: GET_CURRENCY_LIST_SUCCESS, + payload: data.data + }); + }) + .catch(err => { + dispatch({ + type: GET_CURRENCY_LIST_FAILURE, + payload: err + }); + }); +}; diff --git a/src/modules/calculator/components/Calculator.js b/src/modules/calculator/components/Calculator.js new file mode 100644 index 0000000..fc175cd --- /dev/null +++ b/src/modules/calculator/components/Calculator.js @@ -0,0 +1,67 @@ +import React, { useEffect, useState, useRef } from "react"; +import { Badge, FormGroup, Label, Input, InputGroup } from "reactstrap"; + +function Calculator(props) { + + const [count, setCount] = useState(); + const [price, setPrice] = useState(); + + const {currency} = props; + + const handleCountChange = e => { + setCount(e.target.value); + const price = (e.target.value * currency.priceUSD).toFixed(2); + setPrice(price); + } + + const handlePriceChange = (e) => { + setPrice(e.target.value); + const count = (e.target.value / currency.priceUSD).toFixed(2); + setCount(count); + } + + const ref = useRef(); + + useEffect(() => { + setPrice((ref.current.props.value * currency.priceUSD).toFixed(2)); + }, [currency]); + + return ( + +
{currency.symbol} to USD Converter
+ + + + PRICE - ${currency.priceUSD} + + + + + + + + + + + +
+ ); + +} + +export default Calculator; \ No newline at end of file diff --git a/src/modules/calculator/components/Calculator.module.scss b/src/modules/calculator/components/Calculator.module.scss new file mode 100644 index 0000000..69b449c --- /dev/null +++ b/src/modules/calculator/components/Calculator.module.scss @@ -0,0 +1,7 @@ +.SelectBox { + width: 20em; +} + +.Container { + padding: 5em 10em; +} \ No newline at end of file diff --git a/src/modules/calculator/components/Currencies.js b/src/modules/calculator/components/Currencies.js new file mode 100644 index 0000000..5b9b506 --- /dev/null +++ b/src/modules/calculator/components/Currencies.js @@ -0,0 +1,89 @@ +import React, { useEffect, useState } from "react"; +import { connect } from "react-redux"; +import { getCurrencies } from "../actions/currencies"; +import { Row, Col, Badge } from "reactstrap"; +import Select from "react-select"; +import Calculator from "./Calculator"; +import s from "./Calculator.module.scss"; + +function Currencies(props) { + const { currencyList, isFetchingCurrencies } = props; + + const currencies = currencyList.map(currency => { + return { + value: currency.id, + label: currency.name, + priceUSD: currency.price_usd, + currentChange24Hours: currency.percent_change_24h, + symbol: currency.symbol + }; + }); + + const [currency, setCurrency] = useState(0); + + useEffect(() => { + if (!currencyList.length) { + props.getCurrencies(); + } + }); + + function handleChange(selectedOption) { + setCurrency(selectedOption); + } + + return ( +
+

Crypto Currency Calculator

+ + +