Repair scale of the graph. Add trigger and prognosis functionality

front
TBS093A 2020-01-17 18:38:14 +01:00
parent 721d05a42c
commit 360e725b21
11 changed files with 281 additions and 96 deletions

View File

@ -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 (
<div className='exchangePrognosisDiv'>
<input
placeholder='Write the amount to exchange forecast'
onChange={ () => checkNewPrognosis() }
ref={ inputPrognosis }>
</input>
<p>Forecast: { Number((exchange.prognosis.price_forecast).toFixed(2)) } PLN</p>
<p>Percent: { Number((exchange.prognosis.percent_of_difference).toFixed(3)) } %</p>
<p>Course on payment: { exchange.prognosis.course_on_payment } PLN</p>
<p>AVG: { Number((exchange.prognosis.svg_of_all).toFixed(2)) }</p>
<p>Date: { exchange.prognosis.date_of_transaction }</p>
</div>
)
}
const mapStateToProps = state => ({
user: state.user,
exchange: state.exchange
})
const mapDispatchToProps = dispatch => ({
checkPrognosis: exchange => dispatch( checkPrognosis(exchange) )
})
export default connect(mapStateToProps,mapDispatchToProps)(ExchangePrognosis)

View File

@ -1,22 +1,54 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { connect } from 'react-redux' 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' import '../../styles/indexExchange.scss'
const ExchangeTriggerAdd = ({ const ExchangeTriggerAdd = ({
user, user,
exchange, getChart, getUserTriggers, getUserNotifications, getUserTransactions, exchange, getChart, getUserTriggers, getUserNotifications, getUserTransactions, addTrigger,
mousePosition }) => { 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 ( return (
<div className='exchangeTriggerDativeY' <div className='exchangeTriggerDiv'>
style={ { marginTop: mousePosition.y + 'px' } }> <form onSubmit={ addNewTrigger }>
<p>Trigger value: { triggerValue } </p>
<button>
Add Trigger
</button>
</form>
<p>{ user.login } Triggers:</p>
<p>{ message }</p>
<div className='triggerItemList'>
{ exchange.userTriggers
.sort( (a, b) => b.id - a.id )
.map( (trigger, key) => (
<div key={ key } className='triggerItem'><p>{ key }. Value: { trigger.course_values_for_trigger } PLN, Date: { trigger.date_of_trigger }, Status { trigger.status === 1 ? 'Enabled' : 'Disabled' }</p></div>
) ) }
</div>
</div> </div>
) )
} }
@ -27,10 +59,8 @@ const mapStateToProps = state => ({
}) })
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
getChart: exchange => dispatch( getChart(exchange) ),
getUserTriggers: exchange => dispatch( getUserTriggers(exchange) ), getUserTriggers: exchange => dispatch( getUserTriggers(exchange) ),
getUserNotifications: exchange => dispatch( getUserNotifications(exchange) ), addTrigger: exchange => dispatch( addTrigger(exchange) )
getUserTransactions: exchange => dispatch( getUserTransactions(exchange) )
}) })
export default connect(mapStateToProps,mapDispatchToProps)(ExchangeTriggerAdd) export default connect(mapStateToProps,mapDispatchToProps)(ExchangeTriggerAdd)

View File

@ -3,7 +3,10 @@ import { connect } from 'react-redux'
import { getChart, getUserTriggers, getUserNotifications, getUserTransactions } from '../../stores/exchange/duck/operations' import { getChart, getUserTriggers, getUserNotifications, getUserTransactions } from '../../stores/exchange/duck/operations'
import { useInterval } from '../useInterval'
import ExchangeTriggerAdd from './exchangeTriggerAdd' import ExchangeTriggerAdd from './exchangeTriggerAdd'
import ExchangePrognosis from './exchangePrognosis'
import '../../styles/indexExchange.scss' import '../../styles/indexExchange.scss'
@ -11,12 +14,15 @@ const IndexExchange = ({
user, user,
exchange, getChart, getUserTriggers, getUserNotifications, getUserTransactions }) => { exchange, getChart, getUserTriggers, getUserNotifications, getUserTransactions }) => {
useEffect( () => { getChart() }, [] ) let fifteenMinuts = 1500000
useEffect( () => { getUserTriggers() }, [] )
useInterval( () => {
getChart()
}, fifteenMinuts )
const [candleInfo, setCandleInfo] = useState( { Open: 0, Close: 0, Min: 0, Max: 0, Vol: 0 } ) const [candleInfo, setCandleInfo] = useState( { Open: 0, Close: 0, Min: 0, Max: 0, Vol: 0 } )
const [mousePosition, setMousePosition] = useState( { x: 0, y: 0 } ) const [mousePosition, setMousePosition] = useState( { x: 0, y: 0 } )
const [triggerValue, setTriggerValue] = useState(0)
const colorGreen = { const colorGreen = {
background: 'green'//'rgba(0,93,0,1)', background: 'green'//'rgba(0,93,0,1)',
@ -37,8 +43,8 @@ const IndexExchange = ({
} }
) )
} }
let pixelScale = ( exchange.candles.graphMax - exchange.candles.graphMin ) / 590 let pixelScale = ( exchange.candles.graphMax - exchange.candles.graphMin ) / 590
let cursorValue = exchange.candles.graphMax - ( pixelScale * ( mousePosition.y - 175 ) )
const getMousePosition = (event) => { const getMousePosition = (event) => {
setMousePosition( { x: event.pageX, y: event.pageY } ) setMousePosition( { x: event.pageX, y: event.pageY } )
@ -50,12 +56,13 @@ const IndexExchange = ({
<div className={ user.id > -1 ? 'exchangeChartUser' : 'exchangeChartGuest' }> <div className={ user.id > -1 ? 'exchangeChartUser' : 'exchangeChartGuest' }>
<div className='chart' <div className='chart'
onMouseOver={ event => getMousePosition(event) } onMouseOver={ event => getMousePosition(event) }
onClick={ () => setTriggerValue( parseInt(cursorValue) ) }
style={ { width: exchange.candles.candlesCount * 15 + 'px' } }> style={ { width: exchange.candles.candlesCount * 15 + 'px' } }>
{ user.id > -1 ? ( { user.id > -1 ? (
<div> <div>
<div className='exchangeTriggerDativeY' <div className='exchangeTriggerDativeY'
style={ { transform: 'translateY(' + (mousePosition.y - 175) + 'px)' } }> style={ { transform: 'translateY(' + (mousePosition.y - 175) + 'px)' } }>
<p>{ ( exchange.candles.graphMax - ( pixelScale * ( mousePosition.y - 175 ) ) ) }</p> <p>{ parseInt(cursorValue) } PLN</p>
</div> </div>
<div className='exchangeTriggerDativeX' <div className='exchangeTriggerDativeX'
style={ { transform: 'translateX(' + (mousePosition.x) + 'px)' } }> style={ { transform: 'translateX(' + (mousePosition.x) + 'px)' } }>
@ -71,12 +78,12 @@ const IndexExchange = ({
let highValue = candle.Open > candle.Close ? candle.Open : candle.Close let highValue = candle.Open > candle.Close ? candle.Open : candle.Close
let lowValue = 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 onePercentScaleY = 100 / chartScaleY
let difference = (( highValue - lowValue ) / onePercentScaleY ) / scaleProperties let difference = ( highValue - lowValue ) / pixelScale
if ( parseInt(difference) === 0 ) if ( parseInt(difference) === 0 )
difference = 1 difference = 1
@ -93,26 +100,22 @@ const IndexExchange = ({
style={ { paddingTop: chartScaleY + 'px' } }> style={ { paddingTop: chartScaleY + 'px' } }>
<div <div
className='candleMaxValue' className='candleMaxValue'
style={ { height: parseInt( (candle.Max - highValue ) / scaleProperties ) + 'px', background: color }}> style={ { height: parseInt( (candle.Max - highValue ) / pixelScale ) + 'px', background: color }}>
</div> </div>
<div <div
className='candleHigh' className='candleHigh'
style={{ height: parseInt( difference ) + 'px', background: color }}> style={{ height: parseInt( difference ) + 'px', background: color }}>
</div> </div>
<div
className='candleLow'
style={{ height: parseInt( difference ) + 'px', background: color }}>
</div>
<div <div
className='candleMinValue' className='candleMinValue'
style={ { height: parseInt( ( lowValue - candle.Min ) / scaleProperties ) + 'px', background: color }}> style={ { height: parseInt( ( lowValue - candle.Min ) / pixelScale ) + 'px', background: color }}>
</div> </div>
</div> </div>
</div> </div>
<div className='sectionVolumen'> <div className='sectionVolumen'>
<div className='volumen' <div className='volumen'
style={ { height: candle.Volume + 'px' } }> style={ { height: candle.Volume / 1.5 + 'px' } }>
</div> </div>
</div> </div>
@ -125,13 +128,22 @@ const IndexExchange = ({
</div> </div>
<div className={ user.id > -1 ? 'exchangeInterface' : 'exchangeEmptySpace' }> <div className={ user.id > -1 ? 'exchangeInterface' : 'exchangeEmptySpace' }>
<div className='candleInformation'> <div className='candleInformation'>
<p>Open: { candleInfo.Open },</p> <p>Open: { candleInfo.Open } PLN,</p>
<p>Close: { candleInfo.Close },</p> <p>Close: { candleInfo.Close } PLN,</p>
<p>Max: { candleInfo.Max },</p> <p>Max: { candleInfo.Max } PLN,</p>
<p>Min: { candleInfo.Min },</p> <p>Min: { candleInfo.Min } PLN,</p>
<p>Volume: { candleInfo.Vol },</p> <p>Volume: { candleInfo.Vol },</p>
<p>Date: { candleInfo.Date }</p> <p>Date: { candleInfo.Date }</p>
</div> </div>
{ user.id > -1 ? (
<div>
<ExchangeTriggerAdd triggerValue={ triggerValue } />
<ExchangePrognosis />
</div>
) : (
<div></div>
)
}
</div> </div>
</div> </div>
) )

View File

@ -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 <ul>
{subjects.list.map(subject => <li>{subject}</li>)}
</ul>
}
// 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)

View File

@ -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 (
<form onSubmit={addSubject}>
<input ref={subjectInput} />
<button type='submit'>Add Subject</button>
</form>
)
}
const mapDispatchToProps = dispatch => ({
add: subject => dispatch(actions.add(subject))
})
export default connect(null, mapDispatchToProps)(IndexForm)

View File

@ -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]);
}

View File

@ -16,6 +16,14 @@ const setTransactions = item => ({
type: types.GET_USER_TRANSACTIONS, 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 => ({ const reset = item => ({
type: types.RESET, item type: types.RESET, item
}) })
@ -25,5 +33,7 @@ export default {
setTriggers, setTriggers,
setNotifications, setNotifications,
setTransactions, setTransactions,
addNewTrigger,
setNewPrognosis,
reset reset
} }

View File

@ -14,7 +14,7 @@ const fetchGetChart = async () => {
const fetchGetUserTriggers = async (userID) => { const fetchGetUserTriggers = async (userID) => {
const response = await const response = await
fetch ( fetch (
'http://localhost:8001/index/trigger/' + userID, { 'http://localhost:8001/index/user/' + userID + '/trigger', {
method: 'GET', method: 'GET',
credential: 'same-origin' credential: 'same-origin'
}) })
@ -44,26 +44,58 @@ const fetchGetUserNotifications = async (userID) => {
return json 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 = () => export const getChart = () =>
async (dispatch) => { async (dispatch) => {
const chart = await fetchGetChart() const chart = await fetchGetChart()
dispatch(actions.setChart(chart)) dispatch(actions.setChart(chart))
} }
export const getUserTriggers = () => export const getUserTriggers = (userID) =>
async (dispatch) => { async (dispatch) => {
const triggers = await fetchGetUserTriggers() const triggers = await fetchGetUserTriggers(userID)
dispatch(actions.setUserTriggers(triggers)) dispatch(actions.setTriggers(triggers))
} }
export const getUserTransactions = () => export const getUserTransactions = (userID) =>
async (dispatch) => { async (dispatch) => {
const transactions = await fetchGetUserTransactions() const transactions = await fetchGetUserTransactions(userID)
dispatch(actions.setUserTransactions(transactions)) dispatch(actions.setTransactions(transactions))
} }
export const getUserNotifications = () => export const getUserNotifications = (userID) =>
async (dispatch) => { async (dispatch) => {
const notifications = await fetchGetUserNotifications() const notifications = await fetchGetUserNotifications(userID)
dispatch(actions.setUserNotifications(notifications)) 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))
} }

View File

@ -4,7 +4,8 @@ const INITIAL_STATE = {
candles: [], candles: [],
userTriggers: [], userTriggers: [],
userNotifications: [], userNotifications: [],
userTransactions: [] userTransactions: [],
prognosis: {}
} }
const exchangeReducer = (state = INITIAL_STATE, action) => { const exchangeReducer = (state = INITIAL_STATE, action) => {
@ -29,6 +30,11 @@ const exchangeReducer = (state = INITIAL_STATE, action) => {
...state, ...state,
userTransactions: action.item userTransactions: action.item
} }
case types.NEW_PROGNOSIS:
return {
...state,
prognosis: action.item
}
case types.RESET: case types.RESET:
return { return {
...state, ...state,

View File

@ -2,6 +2,8 @@ const GET_CANDLES_CHART = 'GET_CANDLES_CHART'
const GET_USER_TRIGGERS = 'GET_USER_TRIGGERS' const GET_USER_TRIGGERS = 'GET_USER_TRIGGERS'
const GET_USER_NOTIFICATIONS = 'GET_USER_NOTIFICATIONS' const GET_USER_NOTIFICATIONS = 'GET_USER_NOTIFICATIONS'
const GET_USER_TRANSACTIONS = 'GET_USER_TRANSACTIONS' const GET_USER_TRANSACTIONS = 'GET_USER_TRANSACTIONS'
const ADD_NEW_TRIGGER = 'ADD_NEW_TRIGGER'
const NEW_PROGNOSIS = 'NEW_PROGNOSIS'
const RESET = 'RESET' const RESET = 'RESET'
export default { export default {
@ -9,5 +11,7 @@ export default {
GET_USER_TRIGGERS, GET_USER_TRIGGERS,
GET_USER_NOTIFICATIONS, GET_USER_NOTIFICATIONS,
GET_USER_TRANSACTIONS, GET_USER_TRANSACTIONS,
ADD_NEW_TRIGGER,
NEW_PROGNOSIS,
RESET RESET
} }

View File

@ -140,3 +140,82 @@
background-color: rgba(117,82,29,1); background-color: rgba(117,82,29,1);
transform: margin 700ms; 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%;
}
}
}