aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Miller <danjm.com@gmail.com>2018-10-11 00:06:38 +0800
committerDan Miller <danjm.com@gmail.com>2018-12-04 11:36:05 +0800
commitcd32c58fb4bcd731d8a83d354c9b01a38c8df219 (patch)
tree7dc056bb06c71b2a691eccfbbcaf726bd60a98ed
parenta2bbf504b891a63f32070961118ec1ae6fa5fdd8 (diff)
downloadtangerine-wallet-browser-cd32c58fb4bcd731d8a83d354c9b01a38c8df219.tar
tangerine-wallet-browser-cd32c58fb4bcd731d8a83d354c9b01a38c8df219.tar.gz
tangerine-wallet-browser-cd32c58fb4bcd731d8a83d354c9b01a38c8df219.tar.bz2
tangerine-wallet-browser-cd32c58fb4bcd731d8a83d354c9b01a38c8df219.tar.lz
tangerine-wallet-browser-cd32c58fb4bcd731d8a83d354c9b01a38c8df219.tar.xz
tangerine-wallet-browser-cd32c58fb4bcd731d8a83d354c9b01a38c8df219.tar.zst
tangerine-wallet-browser-cd32c58fb4bcd731d8a83d354c9b01a38c8df219.zip
Complete integration of gas chart with redux.
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js2
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js3
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js31
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js2
-rw-r--r--ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js16
-rw-r--r--ui/app/components/gas-customization/gas-price-chart/gas-price-chart.component.js94
-rw-r--r--ui/app/components/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js11
-rw-r--r--ui/app/ducks/gas.duck.js2
-rw-r--r--ui/app/selectors/custom-gas.js1
9 files changed, 148 insertions, 14 deletions
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js
index 44aba358c..4dd18ce2b 100644
--- a/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js
+++ b/ui/app/components/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js
@@ -97,7 +97,7 @@ export default class AdvancedTabContent extends Component {
updateCustomGasLimit
) }
<div className="advanced-tab__fee-chart__title">Live Gas Price Predictions</div>
- <GasPriceChart {...gasChartProps} />
+ <GasPriceChart {...gasChartProps} updateCustomGasPrice={updateCustomGasPrice} />
<div className="advanced-tab__fee-chart__speed-buttons">
<span>Slower</span>
<span>Faster</span>
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js
index de14e1b38..8f23b22e0 100644
--- a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js
+++ b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js
@@ -47,6 +47,7 @@ export default class GasModalPageContainer extends Component {
customGasLimit,
newTotalFiat,
gasChartProps,
+ currentTimeEstimate,
}) {
const { transactionFee } = this.props
return (
@@ -55,7 +56,7 @@ export default class GasModalPageContainer extends Component {
updateCustomGasLimit={convertThenUpdateCustomGasLimit}
customGasPrice={customGasPrice}
customGasLimit={customGasLimit}
- timeRemaining="1 min 31 sec"
+ timeRemaining={currentTimeEstimate}
transactionFee={transactionFee}
totalFee={newTotalFiat}
gasChartProps={gasChartProps}
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
index 84eae1880..3a62d21cc 100644
--- a/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
+++ b/ui/app/components/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js
@@ -10,6 +10,7 @@ import {
setCustomGasPrice,
setCustomGasLimit,
resetCustomData,
+ setCustomTimeEstimate,
} from '../../../ducks/gas.duck'
import {
hideGasButtonGroup,
@@ -29,6 +30,7 @@ import {
getBasicGasEstimateLoadingStatus,
getAveragePriceEstimateInHexWEI,
getDefaultActiveButtonIndex,
+ formatTimeEstimate,
} from '../../../selectors/custom-gas'
import {
formatCurrency,
@@ -65,20 +67,24 @@ const mapStateToProps = state => {
const hideBasic = state.appState.modal.modalState.props.hideBasic
+ const customGasPrice = calcCustomGasPrice(customModalGasPriceInHex)
+
return {
hideBasic,
isConfirm: isConfirm(state),
customModalGasPriceInHex,
customModalGasLimitInHex,
- customGasPrice: calcCustomGasPrice(customModalGasPriceInHex),
+ customGasPrice,
customGasLimit: calcCustomGasLimit(customModalGasLimitInHex),
newTotalFiat,
+ currentTimeEstimate: getRenderableTimeEstimate(customGasPrice, state.gas.priceAndTimeEstimates),
gasPriceButtonGroupProps: {
buttonDataLoading,
defaultActiveButtonIndex: getDefaultActiveButtonIndex(gasButtonInfo, customModalGasPriceInHex),
gasButtonInfo,
},
gasChartProps: {
+ currentPrice: customGasPrice,
priceAndTimeEstimates: state.gas.priceAndTimeEstimates,
},
infoRowProps: {
@@ -111,6 +117,7 @@ const mapDispatchToProps = dispatch => {
return dispatch(updateGasAndCalculate({ gasLimit, gasPrice }))
},
hideGasButtonGroup: () => dispatch(hideGasButtonGroup()),
+ setCustomTimeEstimate: (timeEstimateInSeconds) => dispatch(setCustomTimeEstimate(timeEstimateInSeconds)),
}
}
@@ -181,3 +188,25 @@ function addHexWEIsToRenderableFiat (aHexWEI, bHexWEI, convertedCurrency, conver
partialRight(formatCurrency, [convertedCurrency]),
)(aHexWEI, bHexWEI)
}
+
+function getRenderableTimeEstimate (currentGasPrice, priceAndTimeEstimates) {
+ const gasPrices = priceAndTimeEstimates.map(({ gasprice }) => gasprice)
+ const estimatedTimes = priceAndTimeEstimates.map(({ expectedTime }) => expectedTime)
+
+ const closestLowerValueIndex = gasPrices.findIndex((e, i, a) => {
+ return e <= currentGasPrice && a[i + 1] >= currentGasPrice
+ })
+ const closestHigherValueIndex = gasPrices.findIndex((e, i, a) => {
+ return e > currentGasPrice
+ })
+
+ const closestLowerValue = gasPrices[closestLowerValueIndex]
+ const closestHigherValue = gasPrices[closestHigherValueIndex]
+ const estimatedClosestLowerTimeEstimate = estimatedTimes[closestLowerValueIndex]
+ const estimatedClosestHigherTimeEstimate = estimatedTimes[closestHigherValueIndex]
+
+ const slope = (estimatedClosestHigherTimeEstimate - estimatedClosestLowerTimeEstimate) / (closestHigherValue - closestLowerValue)
+ const newTimeEstimate = -1 * (slope * (closestHigherValue - currentGasPrice) - estimatedClosestHigherTimeEstimate)
+
+ return formatTimeEstimate(newTimeEstimate)
+}
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js
index bb1a28136..61871f5f3 100644
--- a/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js
+++ b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-component.test.js
@@ -65,6 +65,7 @@ describe('GasModalPageContainer Component', function () {
customGasLimit={54321}
gasPriceButtonGroupProps={mockGasPriceButtonGroupProps}
infoRowProps={mockInfoRowProps}
+ currentTimeEstimate={'1 min 31 sec'}
customGasPriceInHex={'mockCustomGasPriceInHex'}
customGasLimitInHex={'mockCustomGasLimitInHex'}
/>, { context: { t: (str1, str2) => str2 ? str1 + str2 : str1 } })
@@ -199,6 +200,7 @@ describe('GasModalPageContainer Component', function () {
customGasPrice: 123,
customGasLimit: 456,
newTotalFiat: '$0.30',
+ currentTimeEstimate: '1 min 31 sec',
})
const advancedTabContentProps = renderAdvancedTabContentResult.props
assert.equal(advancedTabContentProps.updateCustomGasPrice(), 'mockConvertThenUpdateCustomGasPrice')
diff --git a/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
index c16a07b76..3f3be8d0c 100644
--- a/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
+++ b/ui/app/components/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js
@@ -75,7 +75,12 @@ describe('gas-modal-page-container container', () => {
limit: 'aaaaaaaa',
price: 'ffffffff',
},
- priceAndTimeEstimates: 'mockPriceAndTimeEstimates',
+ priceAndTimeEstimates: [
+ { gasprice: 3, expectedTime: '31' },
+ { gasprice: 4, expectedTime: '62' },
+ { gasprice: 5, expectedTime: '93' },
+ { gasprice: 6, expectedTime: '124' },
+ ],
},
confirmTransaction: {
txData: {
@@ -93,11 +98,18 @@ describe('gas-modal-page-container container', () => {
isConfirm: true,
customGasPrice: 4.294967295,
customGasLimit: 2863311530,
+ currentTimeEstimate: '~1 min 11 sec',
newTotalFiat: '637.41',
customModalGasLimitInHex: 'aaaaaaaa',
customModalGasPriceInHex: 'ffffffff',
gasChartProps: {
- priceAndTimeEstimates: 'mockPriceAndTimeEstimates',
+ 'currentPrice': 4.294967295,
+ priceAndTimeEstimates: [
+ { gasprice: 3, expectedTime: '31' },
+ { gasprice: 4, expectedTime: '62' },
+ { gasprice: 5, expectedTime: '93' },
+ { gasprice: 6, expectedTime: '124' },
+ ],
},
gasPriceButtonGroupProps: {
buttonDataLoading: 'mockBasicGasEstimateLoadingStatus:4',
diff --git a/ui/app/components/gas-customization/gas-price-chart/gas-price-chart.component.js b/ui/app/components/gas-customization/gas-price-chart/gas-price-chart.component.js
index 85893f771..69bbd12f6 100644
--- a/ui/app/components/gas-customization/gas-price-chart/gas-price-chart.component.js
+++ b/ui/app/components/gas-customization/gas-price-chart/gas-price-chart.component.js
@@ -35,6 +35,43 @@ function appendOrUpdateCircle ({ circle, data, itemIndex, cx, cy, cssId, appendO
}
}
+function setSelectedCircle ({ chart, gasPrices, currentPrice, chartXStart, chartWidth }) {
+ const numberOfValues = chart.internal.data.xs.data1.length
+ const closestLowerValueIndex = gasPrices.findIndex((e, i, a) => {
+ return e <= currentPrice && a[i + 1] >= currentPrice
+ })
+ const closestHigherValueIndex = gasPrices.findIndex((e, i, a) => {
+ return e > currentPrice
+ })
+ const closestHigherValue = gasPrices[closestHigherValueIndex]
+ const closestLowerValue = gasPrices[closestLowerValueIndex]
+
+ if (closestHigherValue && closestLowerValue) {
+ const closestLowerCircle = d3.select(`.c3-circle-${closestLowerValueIndex}`)
+ const closestHigherCircle = d3.select(`.c3-circle-${closestHigherValueIndex}`)
+ const { x: lowerX, y: lowerY } = closestLowerCircle.node().getBoundingClientRect()
+ const { x: higherX, y: higherY } = closestHigherCircle.node().getBoundingClientRect()
+ const currentX = lowerX + (higherX - lowerX) * (currentPrice - closestLowerValue) / (closestHigherValue - closestLowerValue)
+ const slope = (higherY - lowerY) / (higherX - lowerX)
+ const newTimeEstimate = -1 * (slope * (higherX - currentX) - higherY)
+ chart.internal.selectPointB({
+ x: currentX,
+ value: newTimeEstimate,
+ id: 'data1',
+ index: numberOfValues,
+ name: 'data1',
+ }, numberOfValues)
+ } else {
+ const setCircle = d3.select('#set-circle')
+ if (!setCircle.empty()) {
+ setCircle.remove()
+ }
+ d3.select('.c3-tooltip-container').style('display', 'none !important')
+ chart.internal.hideXGridFocus()
+ return
+ }
+}
+
export default class GasPriceChart extends Component {
static contextTypes = {
t: PropTypes.func,
@@ -42,12 +79,15 @@ export default class GasPriceChart extends Component {
static propTypes = {
priceAndTimeEstimates: PropTypes.array,
+ currentPrice: PropTypes.number,
+ updateCustomGasPrice: PropTypes.func,
}
- renderChart (priceAndTimeEstimates) {
+ renderChart (currentPrice, priceAndTimeEstimates, updateCustomGasPrice) {
const gasPrices = priceAndTimeEstimates.map(({ gasprice }) => gasprice)
const gasPricesMax = gasPrices[gasPrices.length - 1] + 1
const estimatedTimes = priceAndTimeEstimates.map(({ expectedTime }) => expectedTime)
+
const estimatedTimesMax = estimatedTimes[0]
const chart = c3.generate({
size: {
@@ -187,6 +227,28 @@ export default class GasPriceChart extends Component {
})
}
+ chart.internal.selectPointB = function (data, itemIndex = (data.index || 0)) {
+ const { x: chartXStart, y: chartYStart } = d3.select('.c3-areas-data1')
+ .node()
+ .getBoundingClientRect()
+
+ d3.select('#set-circle').remove()
+
+ const circle = this.main
+ .select('.' + 'c3-selected-circles' + this.getTargetSelectorSuffix(data.id))
+ .selectAll('.' + 'c3-selected-circle' + '-' + itemIndex)
+
+ appendOrUpdateCircle.bind(this)({
+ circle,
+ data,
+ itemIndex,
+ cx: () => data.x - chartXStart + 11,
+ cy: () => data.value - chartYStart + 10,
+ cssId: 'set-circle',
+ appendOnly: true,
+ })
+ }
+
chart.internal.overlayPoint = function (data, itemIndex) {
const circle = this.main
.select('.' + 'c3-selected-circles' + this.getTargetSelectorSuffix(data.id))
@@ -238,13 +300,13 @@ export default class GasPriceChart extends Component {
setTimeout(function () {
setTickPosition('y', 0, -5, 8)
- setTickPosition('y', 1, -3)
- setTickPosition('x', 0, 3, 20)
- setTickPosition('x', 1, 3, -10)
+ setTickPosition('y', 1, -3, -5)
+ setTickPosition('x', 0, 3, 15)
+ setTickPosition('x', 1, 3, -8)
// TODO: Confirm the below constants work with all data sets and screen sizes
d3.select('.c3-axis-x-label').attr('transform', 'translate(0,-15)')
- d3.select('.c3-axis-y-label').attr('transform', 'translate(32, 2) rotate(-90)')
+ d3.select('.c3-axis-y-label').attr('transform', 'translate(52, 2) rotate(-90)')
d3.select('.c3-xgrid-focus line').attr('y2', 98)
d3.select('.c3-chart').on('mouseout', () => {
@@ -262,6 +324,7 @@ export default class GasPriceChart extends Component {
const overlayedCircle = d3.select('#overlayed-circle')
const numberOfValues = chart.internal.data.xs.data1.length
const { x: circleX, y: circleY } = overlayedCircle.node().getBoundingClientRect()
+ const { x: xData } = overlayedCircle.datum()
chart.internal.selectPoint({
x: circleX - chartXStart,
value: circleY - 1.5,
@@ -269,13 +332,15 @@ export default class GasPriceChart extends Component {
index: numberOfValues,
name: 'data1',
}, numberOfValues)
+ updateCustomGasPrice(xData)
})
+ setSelectedCircle({ chart, gasPrices, currentPrice, chartXStart, chartWidth })
+
d3.select('.c3-chart').on('mousemove', function () {
const chartMouseXPos = d3.event.clientX - chartXStart
const posPercentile = chartMouseXPos / chartWidth
-
const currentPosValue = (gasPrices[gasPrices.length - 1] - gasPrices[0]) * posPercentile + gasPrices[0]
const closestLowerValueIndex = gasPrices.findIndex((e, i, a) => {
return e <= currentPosValue && a[i + 1] >= currentPosValue
@@ -326,11 +391,26 @@ export default class GasPriceChart extends Component {
})
}, 0)
+ this.chart = chart
+ }
+ componentDidUpdate (prevProps) {
+ if (prevProps.currentPrice !== this.props.currentPrice) {
+ const chartRect = d3.select('.c3-areas-data1')
+ const { x: chartXStart, width: chartWidth } = chartRect.node().getBoundingClientRect()
+ setSelectedCircle({
+ chart: this.chart,
+ currentPrice: this.props.currentPrice,
+ gasPrices: this.props.priceAndTimeEstimates.map(({ gasprice }) => gasprice),
+ chartXStart,
+ chartWidth,
+ })
+ }
}
componentDidMount () {
- this.renderChart(this.props.priceAndTimeEstimates)
+ const { currentPrice, priceAndTimeEstimates, updateCustomGasPrice } = this.props
+ this.renderChart(currentPrice, priceAndTimeEstimates, updateCustomGasPrice)
}
render () {
diff --git a/ui/app/components/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js b/ui/app/components/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js
index ae98659cc..48b8a6525 100644
--- a/ui/app/components/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js
+++ b/ui/app/components/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js
@@ -10,6 +10,9 @@ const mockSelectReturn = {
node: () => ({
getBoundingClientRect: () => ({ x: 123, y: 321, width: 400 }),
}),
+ empty: sinon.spy(),
+ remove: sinon.spy(),
+ style: sinon.spy(),
select: d3.select,
attr: sinon.spy(),
on: sinon.spy(),
@@ -17,11 +20,17 @@ const mockSelectReturn = {
const GasPriceChart = proxyquire('../gas-price-chart.component.js', {
'c3': {
- generate: function () {
+ generate: function ({ data: { columns } }) {
return {
internal: {
showTooltip: () => {},
showXGridFocus: () => {},
+ hideXGridFocus: () => {},
+ data: {
+ xs: {
+ [columns[1][0]]: columns[1].slice(1),
+ },
+ },
},
}
},
diff --git a/ui/app/ducks/gas.duck.js b/ui/app/ducks/gas.duck.js
index 35e26544a..2dcec91de 100644
--- a/ui/app/ducks/gas.duck.js
+++ b/ui/app/ducks/gas.duck.js
@@ -212,7 +212,7 @@ export function fetchGasEstimates (blockTime) {
const estimatedPricesAndTimes = r.map(({ expectedTime, expectedWait, gasprice }) => ({ expectedTime, expectedWait, gasprice }))
const estimatedTimeWithUniquePrices = uniqBy(({ expectedTime }) => expectedTime, estimatedPricesAndTimes)
const timeMappedToSeconds = estimatedTimeWithUniquePrices.map(({ expectedWait, gasprice }) => {
- const expectedTime = (new BigNumber(expectedWait)).times(Number(blockTime), 10).div(60, 10).toString(10)
+ const expectedTime = (new BigNumber(expectedWait)).times(Number(blockTime), 10).toString(10)
return {
expectedTime,
expectedWait,
diff --git a/ui/app/selectors/custom-gas.js b/ui/app/selectors/custom-gas.js
index d5a3972df..abc8ba191 100644
--- a/ui/app/selectors/custom-gas.js
+++ b/ui/app/selectors/custom-gas.js
@@ -31,6 +31,7 @@ const selectors = {
getAveragePriceEstimateInHexWEI,
getDefaultActiveButtonIndex,
priceEstimateToWei,
+ formatTimeEstimate,
}
module.exports = selectors