From 360e725b215dcf8719e1e5e3e441f3cfc2a55360 Mon Sep 17 00:00:00 2001 From: TBS093A Date: Fri, 17 Jan 2020 18:38:14 +0100 Subject: [PATCH] Repair scale of the graph. Add trigger and prognosis functionality --- src/components/exchange/exchangePrognosis.js | 48 +++++++++++ src/components/exchange/exchangeTriggerAdd.js | 50 +++++++++--- src/components/exchange/indexExchange.js | 50 +++++++----- src/components/index.js | 28 ------- src/components/indexForm.js | 28 ------- src/components/useInterval.js | 20 +++++ src/stores/exchange/duck/actions.js | 10 +++ src/stores/exchange/duck/operations.js | 52 +++++++++--- src/stores/exchange/duck/reducers.js | 8 +- src/stores/exchange/duck/types.js | 4 + src/styles/indexExchange.scss | 79 +++++++++++++++++++ 11 files changed, 281 insertions(+), 96 deletions(-) create mode 100644 src/components/exchange/exchangePrognosis.js delete mode 100644 src/components/index.js delete mode 100644 src/components/indexForm.js create mode 100644 src/components/useInterval.js diff --git a/src/components/exchange/exchangePrognosis.js b/src/components/exchange/exchangePrognosis.js new file mode 100644 index 0000000..6bb2f06 --- /dev/null +++ b/src/components/exchange/exchangePrognosis.js @@ -0,0 +1,48 @@ +import React, { useState, useEffect } from 'react' +import { connect } from 'react-redux' + +import { checkPrognosis } from '../../stores/exchange/duck/operations' + +import '../../styles/indexExchange.scss' + +const ExchangePrognosis = ({ + user, + exchange, checkPrognosis }) => { + + const inputPrognosis = React.createRef() + + const checkNewPrognosis = () => { + if ( inputPrognosis.current.value > 0 ) { + let prognosis = { + price: inputPrognosis.current.value, + } + checkPrognosis( prognosis ) + } + } + + return ( +
+ checkNewPrognosis() } + ref={ inputPrognosis }> + +

Forecast: { Number((exchange.prognosis.price_forecast).toFixed(2)) } PLN

+

Percent: { Number((exchange.prognosis.percent_of_difference).toFixed(3)) } %

+

Course on payment: { exchange.prognosis.course_on_payment } PLN

+

AVG: { Number((exchange.prognosis.svg_of_all).toFixed(2)) }

+

Date: { exchange.prognosis.date_of_transaction }

+
+ ) +} + +const mapStateToProps = state => ({ + user: state.user, + exchange: state.exchange +}) + +const mapDispatchToProps = dispatch => ({ + checkPrognosis: exchange => dispatch( checkPrognosis(exchange) ) +}) + +export default connect(mapStateToProps,mapDispatchToProps)(ExchangePrognosis) diff --git a/src/components/exchange/exchangeTriggerAdd.js b/src/components/exchange/exchangeTriggerAdd.js index aec9640..cb06edd 100644 --- a/src/components/exchange/exchangeTriggerAdd.js +++ b/src/components/exchange/exchangeTriggerAdd.js @@ -1,22 +1,54 @@ import React, { useState, useEffect } from 'react' import { connect } from 'react-redux' -import { getChart, getUserTriggers, getUserNotifications, getUserTransactions } from '../../stores/exchange/duck/operations' +import { getChart, getUserTriggers, getUserNotifications, getUserTransactions, addTrigger } from '../../stores/exchange/duck/operations' import '../../styles/indexExchange.scss' const ExchangeTriggerAdd = ({ user, - exchange, getChart, getUserTriggers, getUserNotifications, getUserTransactions, - mousePosition }) => { + exchange, getChart, getUserTriggers, getUserNotifications, getUserTransactions, addTrigger, + triggerValue }) => { - useEffect( () => { getUserTriggers(user) }, [] ) + useEffect( () => { getUserTriggers(user.id) }, [] ) + const [inputValue, setInputValue] = useState( triggerValue ) + const [message, setMessage] = useState('') + + const triggerValueAdd = React.createRef() + + const addNewTrigger = (event) => { + event.preventDefault() + if ( triggerValue !== 0 ) { + let newTrigger = { + user_id: user.id, + course_values_for_trigger: triggerValue, + token: user.token + } + addTrigger( newTrigger ) + setMessage('Trigger has been added') + } + else + setMessage('Trigger add error') + } return ( -
- +
+
+

Trigger value: { triggerValue } zł

+ +
+

{ user.login } Triggers:

+

{ message }

+
+ { exchange.userTriggers + .sort( (a, b) => b.id - a.id ) + .map( (trigger, key) => ( +

{ key }. Value: { trigger.course_values_for_trigger } PLN, Date: { trigger.date_of_trigger }, Status { trigger.status === 1 ? 'Enabled' : 'Disabled' }

+ ) ) } +
) } @@ -27,10 +59,8 @@ const mapStateToProps = state => ({ }) const mapDispatchToProps = dispatch => ({ - getChart: exchange => dispatch( getChart(exchange) ), getUserTriggers: exchange => dispatch( getUserTriggers(exchange) ), - getUserNotifications: exchange => dispatch( getUserNotifications(exchange) ), - getUserTransactions: exchange => dispatch( getUserTransactions(exchange) ) + addTrigger: exchange => dispatch( addTrigger(exchange) ) }) export default connect(mapStateToProps,mapDispatchToProps)(ExchangeTriggerAdd) diff --git a/src/components/exchange/indexExchange.js b/src/components/exchange/indexExchange.js index 0025ac8..0ed0fbc 100644 --- a/src/components/exchange/indexExchange.js +++ b/src/components/exchange/indexExchange.js @@ -3,7 +3,10 @@ import { connect } from 'react-redux' import { getChart, getUserTriggers, getUserNotifications, getUserTransactions } from '../../stores/exchange/duck/operations' +import { useInterval } from '../useInterval' + import ExchangeTriggerAdd from './exchangeTriggerAdd' +import ExchangePrognosis from './exchangePrognosis' import '../../styles/indexExchange.scss' @@ -11,12 +14,15 @@ const IndexExchange = ({ user, exchange, getChart, getUserTriggers, getUserNotifications, getUserTransactions }) => { - useEffect( () => { getChart() }, [] ) - useEffect( () => { getUserTriggers() }, [] ) + let fifteenMinuts = 1500000 + + useInterval( () => { + getChart() + }, fifteenMinuts ) const [candleInfo, setCandleInfo] = useState( { Open: 0, Close: 0, Min: 0, Max: 0, Vol: 0 } ) - const [mousePosition, setMousePosition] = useState( { x: 0, y: 0 } ) + const [triggerValue, setTriggerValue] = useState(0) const colorGreen = { background: 'green'//'rgba(0,93,0,1)', @@ -37,8 +43,8 @@ const IndexExchange = ({ } ) } - let pixelScale = ( exchange.candles.graphMax - exchange.candles.graphMin ) / 590 + let cursorValue = exchange.candles.graphMax - ( pixelScale * ( mousePosition.y - 175 ) ) const getMousePosition = (event) => { setMousePosition( { x: event.pageX, y: event.pageY } ) @@ -50,12 +56,13 @@ const IndexExchange = ({
-1 ? 'exchangeChartUser' : 'exchangeChartGuest' }>
getMousePosition(event) } + onClick={ () => setTriggerValue( parseInt(cursorValue) ) } style={ { width: exchange.candles.candlesCount * 15 + 'px' } }> { user.id > -1 ? (
-

{ ( exchange.candles.graphMax - ( pixelScale * ( mousePosition.y - 175 ) ) ) }

+

{ parseInt(cursorValue) } PLN

@@ -71,12 +78,12 @@ const IndexExchange = ({ let highValue = candle.Open > candle.Close ? candle.Open : candle.Close let lowValue = candle.Open < candle.Close ? candle.Open : candle.Close - let scaleProperties = 8 + let scaleProperties = 10 - let chartScaleY = (exchange.candles.graphMax - candle.Max) / scaleProperties + let chartScaleY = (exchange.candles.graphMax - candle.Max) / pixelScale let onePercentScaleY = 100 / chartScaleY - let difference = (( highValue - lowValue ) / onePercentScaleY ) / scaleProperties + let difference = ( highValue - lowValue ) / pixelScale if ( parseInt(difference) === 0 ) difference = 1 @@ -93,26 +100,22 @@ const IndexExchange = ({ style={ { paddingTop: chartScaleY + 'px' } }>
+ style={ { height: parseInt( (candle.Max - highValue ) / pixelScale ) + 'px', background: color }}>
-
-
+ style={ { height: parseInt( ( lowValue - candle.Min ) / pixelScale ) + 'px', background: color }}>
+ style={ { height: candle.Volume / 1.5 + 'px' } }>
@@ -125,13 +128,22 @@ const IndexExchange = ({
-1 ? 'exchangeInterface' : 'exchangeEmptySpace' }>
-

Open: { candleInfo.Open },

-

Close: { candleInfo.Close },

-

Max: { candleInfo.Max },

-

Min: { candleInfo.Min },

+

Open: { candleInfo.Open } PLN,

+

Close: { candleInfo.Close } PLN,

+

Max: { candleInfo.Max } PLN,

+

Min: { candleInfo.Min } PLN,

Volume: { candleInfo.Vol },

Date: { candleInfo.Date }

+ { user.id > -1 ? ( +
+ + +
+ ) : ( +
+ ) + }
) diff --git a/src/components/index.js b/src/components/index.js deleted file mode 100644 index ab85c78..0000000 --- a/src/components/index.js +++ /dev/null @@ -1,28 +0,0 @@ -import React, { useEffect } from 'react'; -import { connect } from 'react-redux'; -import { getSubjectsThread } from '../stores/subjects/duck/operations' - -import '../styles/index.scss' - -const Index = ({subjects, getSubjectsThread}) =>{ - - useEffect( () => { getSubjectsThread() }, []) - - return -} - - // do odczytu globalnego state'a - -const mapStateToProps = state => ({ - subjects: state.subjects -}) - - // do modyfikacji globalnego state'a - -const mapDispatchToProps = dispatch => ({ - getSubjectsThread: () => dispatch( getSubjectsThread() ) -}) - -export default connect(mapStateToProps, mapDispatchToProps)(Index) diff --git a/src/components/indexForm.js b/src/components/indexForm.js deleted file mode 100644 index ac43755..0000000 --- a/src/components/indexForm.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react' -import { connect } from 'react-redux' -import actions from '../stores/subjects/duck/actions' - -const IndexForm = (props) => { - - const subjectInput = React.createRef() - - const addSubject = (event) => { - event.preventDefault() - props.add(subjectInput.current.value) - - subjectInput.current.value = '' - } - - return ( -
- - -
- ) -} - -const mapDispatchToProps = dispatch => ({ - add: subject => dispatch(actions.add(subject)) -}) - -export default connect(null, mapDispatchToProps)(IndexForm) diff --git a/src/components/useInterval.js b/src/components/useInterval.js new file mode 100644 index 0000000..d15ade0 --- /dev/null +++ b/src/components/useInterval.js @@ -0,0 +1,20 @@ +import React, { useState, useEffect, useRef } from 'react'; + +export const useInterval = (callback, delay) => { + + const savedCallback = useRef(); + + useEffect(() => { + savedCallback.current = callback; + }, [callback]); + + useEffect(() => { + function tick() { + savedCallback.current(); + } + if (delay !== null) { + let id = setInterval(tick, delay); + return () => clearInterval(id); + } + }, [delay]); +} diff --git a/src/stores/exchange/duck/actions.js b/src/stores/exchange/duck/actions.js index 51a9698..0772058 100644 --- a/src/stores/exchange/duck/actions.js +++ b/src/stores/exchange/duck/actions.js @@ -16,6 +16,14 @@ const setTransactions = item => ({ type: types.GET_USER_TRANSACTIONS, item }) +const addNewTrigger = item => ({ + type: types.ADD_NEW_TRIGGER, item +}) + +const setNewPrognosis = item => ({ + type: types.NEW_PROGNOSIS, item +}) + const reset = item => ({ type: types.RESET, item }) @@ -25,5 +33,7 @@ export default { setTriggers, setNotifications, setTransactions, + addNewTrigger, + setNewPrognosis, reset } diff --git a/src/stores/exchange/duck/operations.js b/src/stores/exchange/duck/operations.js index a5cab4a..c88ca70 100644 --- a/src/stores/exchange/duck/operations.js +++ b/src/stores/exchange/duck/operations.js @@ -14,7 +14,7 @@ const fetchGetChart = async () => { const fetchGetUserTriggers = async (userID) => { const response = await fetch ( - 'http://localhost:8001/index/trigger/' + userID, { + 'http://localhost:8001/index/user/' + userID + '/trigger', { method: 'GET', credential: 'same-origin' }) @@ -44,26 +44,58 @@ const fetchGetUserNotifications = async (userID) => { return json } +const fetchAddTrigger = async (data) => { + fetch ( + 'http://localhost:8001/index/user/' + data.user_id + '/trigger', { + method: 'POST', + credential: 'same-origin', + body: JSON.stringify(data) + } + ) +} + +const fetchPrognosis = async (data) => { + const response = await fetch ( + 'http://localhost:8001/index/exchange/1800/prognosis/' + data.price, { + method: 'GET', + credential: 'same-origin' + } + ) + const json = response.json() + return json +} + export const getChart = () => async (dispatch) => { const chart = await fetchGetChart() dispatch(actions.setChart(chart)) } -export const getUserTriggers = () => +export const getUserTriggers = (userID) => async (dispatch) => { - const triggers = await fetchGetUserTriggers() - dispatch(actions.setUserTriggers(triggers)) + const triggers = await fetchGetUserTriggers(userID) + dispatch(actions.setTriggers(triggers)) } -export const getUserTransactions = () => +export const getUserTransactions = (userID) => async (dispatch) => { - const transactions = await fetchGetUserTransactions() - dispatch(actions.setUserTransactions(transactions)) + const transactions = await fetchGetUserTransactions(userID) + dispatch(actions.setTransactions(transactions)) } -export const getUserNotifications = () => +export const getUserNotifications = (userID) => async (dispatch) => { - const notifications = await fetchGetUserNotifications() - dispatch(actions.setUserNotifications(notifications)) + const notifications = await fetchGetUserNotifications(userID) + dispatch(actions.setNotifications(notifications)) + } + +export const addTrigger = (data) => + async (dispatch) => { + await fetchAddTrigger(data) + } + +export const checkPrognosis = (data) => + async (dispatch) => { + const prognosis = await fetchPrognosis(data) + dispatch(actions.setNewPrognosis(prognosis)) } diff --git a/src/stores/exchange/duck/reducers.js b/src/stores/exchange/duck/reducers.js index c9ef8e4..c3a61ab 100644 --- a/src/stores/exchange/duck/reducers.js +++ b/src/stores/exchange/duck/reducers.js @@ -4,7 +4,8 @@ const INITIAL_STATE = { candles: [], userTriggers: [], userNotifications: [], - userTransactions: [] + userTransactions: [], + prognosis: {} } const exchangeReducer = (state = INITIAL_STATE, action) => { @@ -29,6 +30,11 @@ const exchangeReducer = (state = INITIAL_STATE, action) => { ...state, userTransactions: action.item } + case types.NEW_PROGNOSIS: + return { + ...state, + prognosis: action.item + } case types.RESET: return { ...state, diff --git a/src/stores/exchange/duck/types.js b/src/stores/exchange/duck/types.js index 226e7d2..9c5d3ae 100644 --- a/src/stores/exchange/duck/types.js +++ b/src/stores/exchange/duck/types.js @@ -2,6 +2,8 @@ const GET_CANDLES_CHART = 'GET_CANDLES_CHART' const GET_USER_TRIGGERS = 'GET_USER_TRIGGERS' const GET_USER_NOTIFICATIONS = 'GET_USER_NOTIFICATIONS' const GET_USER_TRANSACTIONS = 'GET_USER_TRANSACTIONS' +const ADD_NEW_TRIGGER = 'ADD_NEW_TRIGGER' +const NEW_PROGNOSIS = 'NEW_PROGNOSIS' const RESET = 'RESET' export default { @@ -9,5 +11,7 @@ export default { GET_USER_TRIGGERS, GET_USER_NOTIFICATIONS, GET_USER_TRANSACTIONS, + ADD_NEW_TRIGGER, + NEW_PROGNOSIS, RESET } diff --git a/src/styles/indexExchange.scss b/src/styles/indexExchange.scss index 4fa0f9f..40cc920 100644 --- a/src/styles/indexExchange.scss +++ b/src/styles/indexExchange.scss @@ -140,3 +140,82 @@ background-color: rgba(117,82,29,1); transform: margin 700ms; } + +@mixin gapBetweenSectionsEx { + border-right: 2px dashed; + border-color: rgba(117,82,29,0.7); +} + +@mixin exchangeDivInterface { + width: 32%; + height: 160px; + padding-left: 10px; + padding-right: 10px; + float:left; + background: rgba(0,0,0,0.2); + overflow: hidden; + + @include gapBetweenSectionsEx +} + +.exchangeTriggerDiv { + @include exchangeDivInterface + + form { + width: 100%; + float: left; + display: flex; + + p { + padding-top: 10px; + width: 50%; + text-align: center; + } + button { + width: 50%; + } + } + + p { + float: left; + width: 50%; + height: 20px; + text-align: center; + } + .triggerItemList { + width: 100%; + height: 75px; + overflow-y: scroll; + + .triggerItem { + width: 100%; + height: 20px; + + p { + width: 100%; + } + } + } +} + +.exchangePrognosisDiv { + @include exchangeDivInterface + + input { + width: 100%; + float: left; + } + + p { + width: 50%; + height: 10px; + float: left; + padding-top: 10px; + text-align: center; + + &:last-of-type { + width: 100%; + } + } + +}