Skip to content

Commit

Permalink
feat(transations): initial charts
Browse files Browse the repository at this point in the history
  • Loading branch information
schnogz committed Feb 5, 2020
1 parent 4794e67 commit 7a4370d
Show file tree
Hide file tree
Showing 11 changed files with 407 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { actions } from 'data'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { getData } from './selectors'
import { Image, Text } from 'blockchain-info-components'
import { toUpper } from 'ramda'
import Chart from './template'
import React from 'react'
import styled from 'styled-components'

const ErrorWrapper = styled.div`
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 5px;
box-sizing: border-box;
`

const Loading = () => (
<Image name='chart-placeholder' width='450px' height='100px' />
)

export class CoinPerformanceContainer extends React.PureComponent {
componentDidMount () {
this.props.priceChartActions.initialized(toUpper(this.props.coin), '1week')
}

render () {
const { currencySymbol } = this.props

return this.props.data.cata({
Success: value => (
<Chart
currencySymbol={currencySymbol}
coin={value.coin}
time={value.time}
data={value.data}
/>
),
Failure: error => (
<ErrorWrapper>
<Text size='12px' weight={400} color='red600'>
{error}
</Text>
</ErrorWrapper>
),
Loading: () => <Loading />,
NotAsked: () => <Loading />
})
}
}

const mapStateToProps = (state, ownProps) => getData(state, ownProps)

const mapDispatchToProps = dispatch => ({
priceChartActions: bindActionCreators(actions.components.priceChart, dispatch)
})

export default connect(
mapStateToProps,
mapDispatchToProps
)(CoinPerformanceContainer)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export const getConfig = (coin, currency, data) => ({
chart: {
height: 100,
type: 'line'
},
credits: {
enabled: false
},
legend: {
enabled: false
},
series: [
{
data: data
}
],
tooltip: {
enabled: false
},
title: {
text: null
},
yAxis: {
visible: false
},
xAxis: {
visible: false
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { createDeepEqualSelector } from 'services/ReselectHelper'
import { Exchange } from 'blockchain-wallet-v4/src'
import { lift, map } from 'ramda'
import { selectors } from 'data'

export const getData = createDeepEqualSelector(
[
selectors.core.settings.getCurrency,
selectors.core.data.misc.getPriceIndexSeries,
(state, ownProps) => ownProps.coin
],
(currencyR, priceIndexSeriesDataR, coin) => {
const currency = currencyR.getOrElse('USD')
const currencySymbol = Exchange.getSymbol(currency)

const transform = priceIndexSeriesData => ({
data: map(d => [d.timestamp * 1000, d.price], priceIndexSeriesData),
coin,
time: '1week'
})
return {
data: lift(transform)(priceIndexSeriesDataR),
currency,
currencySymbol
}
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { calculateInterval, calculateStart } from 'services/ChartService'
import { getConfig } from './model'
import PropTypes from 'prop-types'
import React, { useEffect, useState } from 'react'
import ReactHighcharts from 'react-highcharts'
import styled from 'styled-components'

const Wrapper = styled.div`
* {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif !important;
}
svg {
.highcharts-background {
fill: ${props => props.theme.white} !important;
}
}
.highcharts-tooltip span {
padding: 0 2px 2px 2px;
> span:first-child {
font-weight: 400;
}
}
.highcharts-container,
.highcharts-root {
overflow: visible !important;
}
`

const Chart = props => {
const { coin, time, data, currencySymbol } = props
const decimals = coin === 'XLM' ? 4 : 2
const start = calculateStart(coin, time)
const interval = calculateInterval(coin, time)
let config = getConfig(coin, currencySymbol, data, decimals, interval, start)

const [chartObj, setChartObj] = useState({
config,
start,
interval,
decimals
})

useEffect(() => {
config = getConfig(coin, currencySymbol, data, decimals, interval, start)
setChartObj({ config })
}, [])

return (
<Wrapper>
<ReactHighcharts config={chartObj.config} isPureConfig />
</Wrapper>
)
}

Chart.propTypes = {
currencySymbol: PropTypes.string.isRequired,
coin: PropTypes.string.isRequired,
time: PropTypes.string.isRequired,
data: PropTypes.array.isRequired
}

export default Chart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { connect } from 'react-redux'
import { getData } from './selectors'
import { SkeletonRectangle } from 'blockchain-info-components'
import CoinPrices from './template'
import React from 'react'
import styled from 'styled-components'

const LoadingWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
`

const Loading = () => (
<LoadingWrapper>
<SkeletonRectangle width='100px' height='20px' />
<SkeletonRectangle width='100px' height='16px' />
<SkeletonRectangle width='100px' height='16px' />
</LoadingWrapper>
)

class CoinPricesContainer extends React.PureComponent {
render () {
const { data } = this.props

return data.cata({
Success: value => <CoinPrices {...value} />,
Failure: () => <Loading />,
Loading: () => <Loading />,
NotAsked: () => <Loading />
})
}
}

const mapStateToProps = state => ({
data: getData(state)
})

export default connect(mapStateToProps)(CoinPricesContainer)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { createDeepEqualSelector } from 'services/ReselectHelper'
import { head, last, lift, prop } from 'ramda'
import { selectors } from 'data'

export const getData = createDeepEqualSelector(
[
selectors.core.data.misc.getPriceIndexSeries,
selectors.core.settings.getCurrency
],
(priceIndexSeriesR, currencyR) => {
const transform = (priceIndexSeries, currency) => {
const priceStart = prop('price', head(priceIndexSeries))
const priceCurrent = prop('price', last(priceIndexSeries))
const priceChange = priceCurrent - priceStart
const pricePercentageChange = (priceChange / priceStart) * 100
return {
currency,
priceChange,
pricePercentageChange,
priceCurrent
}
}

return lift(transform)(priceIndexSeriesR, currencyR)
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import * as Currency from 'blockchain-wallet-v4/src/exchange/currency'
import { Exchange } from 'blockchain-wallet-v4/src'
import { FormattedMessage } from 'react-intl'
import { Text } from 'blockchain-info-components'
import React from 'react'
import styled from 'styled-components'

const Wrapper = styled.div`
display: flex;
flex-direction: column;
`

const TitleText = styled(Text)`
font-weight: 500;
font-size: 16px;
line-height: 150%;
color: ${props => props.theme.grey400};
`
const PriceText = styled(Text)`
font-weight: 500;
font-size: 24px;
line-height: 135%;
color: ${props => props.theme.grey800};
margin: 5px 0;
`
const PriceChangeText = styled(Text)`
font-weight: 500;
font-size: 14px;
line-height: 20px;
color: ${props => props.theme.grey400};
`
const PriceChangeColoredText = styled.span`
font-weight: 600;
color: ${props =>
props.priceChange >= 0 ? props.theme.green400 : props.theme.red500};
`

const buildPercentageChange = (
currency,
priceChange,
pricePercentageChange
) => {
let priceFormatted
if (priceChange < 0) {
priceFormatted = `-${Exchange.getSymbol(currency)}${Currency.formatFiat(
priceChange
).substring(1)}`
} else {
priceFormatted =
Exchange.getSymbol(currency) + Currency.formatFiat(priceChange)
}
return `${priceFormatted} (${Currency.formatFiat(pricePercentageChange)}%)`
}

const CoinPrices = ({
currency,
priceChange,
pricePercentageChange,
priceCurrent
}) => {
return (
<Wrapper>
<TitleText>
<FormattedMessage
id='scenes.transactions.performance.prices.price'
defaultMessage='Current Price'
/>
</TitleText>
<PriceText>
{Exchange.getSymbol(currency)}
{Currency.formatFiat(priceCurrent)}
</PriceText>
<PriceChangeText>
<PriceChangeColoredText priceChange={priceChange}>
{buildPercentageChange(currency, priceChange, pricePercentageChange)}
</PriceChangeColoredText>{' '}
<FormattedMessage
id='scenes.transactions.performance.prices.week'
defaultMessage='this week'
/>
</PriceChangeText>
</Wrapper>
)
}

export default CoinPrices
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import CoinChart from './CoinChart'
import CoinPrices from './CoinPrices'
import PropTypes from 'prop-types'
import React from 'react'
import styled from 'styled-components'

const Wrapper = styled.div`
display: flex;
flex-direction: row;
align-content: space-between;
max-width: 1000px;
height: 120px;
max-height: 120px;
border: 1px solid ${props => props.theme.grey100};
border-radius: 4px;
& > :first-child {
flex-basis: 45%;
padding: 16px 20px;
margin-right: 35px;
}
& > :last-child {
flex-basis: 55%;
padding-right: 20px;
}
`

const CoinPerformanceContainer = ({ coin }) => (
<Wrapper>
<CoinPrices coin={coin} />
<CoinChart coin={coin} />
</Wrapper>
)

CoinPerformanceContainer.propTypes = {
coin: PropTypes.string.isRequired
}

export default CoinPerformanceContainer

0 comments on commit 7a4370d

Please sign in to comment.