Commit 49f1acb5 authored by Brendan Wong's avatar Brendan Wong Committed by GitHub

fix: displays price when not updated on TDP (#7068)

* Update PriceChart.tsx

* simplify deltaarrow function

* update text coloring

* increase gap a bit more

* rename tags

* restyling of information

* fix import issue

* Update src/components/Tokens/TokenDetails/PriceChart.tsx
Co-authored-by: default avatarJordan Frankfurt <jordanwfrankfurt@gmail.com>

* unit testing!

---------
Co-authored-by: default avatarJordan Frankfurt <jordanwfrankfurt@gmail.com>
parent a97005e2
import { TimePeriod } from 'graphql/data/util'
import { render } from 'test-utils/render'
import { PriceChart } from './PriceChart'
jest.mock('components/Charts/AnimatedInLineChart', () => ({
__esModule: true,
default: jest.fn(() => null),
}))
jest.mock('components/Charts/FadeInLineChart', () => ({
__esModule: true,
default: jest.fn(() => null),
}))
describe('PriceChart', () => {
it('renders correctly with all prices filled', () => {
const mockPrices = Array.from({ length: 13 }, (_, i) => ({
value: 1,
timestamp: i * 3600,
}))
const { asFragment } = render(
<PriceChart prices={mockPrices} width={780} height={436} timePeriod={TimePeriod.HOUR} />
)
expect(asFragment()).toMatchSnapshot()
expect(asFragment().textContent).toContain('$1.00')
expect(asFragment().textContent).toContain('0.00%')
})
it('renders correctly with some prices filled', () => {
const mockPrices = Array.from({ length: 13 }, (_, i) => ({
value: i < 10 ? 1 : 0,
timestamp: i * 3600,
}))
const { asFragment } = render(
<PriceChart prices={mockPrices} width={780} height={436} timePeriod={TimePeriod.HOUR} />
)
expect(asFragment()).toMatchSnapshot()
expect(asFragment().textContent).toContain('$1.00')
expect(asFragment().textContent).toContain('0.00%')
})
it('renders correctly with no prices filled', () => {
const { asFragment } = render(<PriceChart prices={[]} width={780} height={436} timePeriod={TimePeriod.HOUR} />)
expect(asFragment()).toMatchSnapshot()
expect(asFragment().textContent).toContain('Price Unavailable')
})
})
...@@ -6,12 +6,13 @@ import { GlyphCircle } from '@visx/glyph' ...@@ -6,12 +6,13 @@ import { GlyphCircle } from '@visx/glyph'
import { Line } from '@visx/shape' import { Line } from '@visx/shape'
import AnimatedInLineChart from 'components/Charts/AnimatedInLineChart' import AnimatedInLineChart from 'components/Charts/AnimatedInLineChart'
import FadedInLineChart from 'components/Charts/FadeInLineChart' import FadedInLineChart from 'components/Charts/FadeInLineChart'
import { MouseoverTooltip } from 'components/Tooltip'
import { bisect, curveCardinal, NumberValue, scaleLinear, timeDay, timeHour, timeMinute, timeMonth } from 'd3' import { bisect, curveCardinal, NumberValue, scaleLinear, timeDay, timeHour, timeMinute, timeMonth } from 'd3'
import { PricePoint } from 'graphql/data/util' import { PricePoint } from 'graphql/data/util'
import { TimePeriod } from 'graphql/data/util' import { TimePeriod } from 'graphql/data/util'
import { useActiveLocale } from 'hooks/useActiveLocale' import { useActiveLocale } from 'hooks/useActiveLocale'
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react' import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
import { ArrowDownRight, ArrowUpRight, TrendingUp } from 'react-feather' import { ArrowDownRight, ArrowUpRight, Info, TrendingUp } from 'react-feather'
import styled, { useTheme } from 'styled-components' import styled, { useTheme } from 'styled-components'
import { ThemedText } from 'theme' import { ThemedText } from 'theme'
import { textFadeIn } from 'theme/styles' import { textFadeIn } from 'theme/styles'
...@@ -41,18 +42,33 @@ const StyledDownArrow = styled(ArrowDownRight)` ...@@ -41,18 +42,33 @@ const StyledDownArrow = styled(ArrowDownRight)`
color: ${({ theme }) => theme.accentFailure}; color: ${({ theme }) => theme.accentFailure};
` `
const DefaultUpArrow = styled(ArrowUpRight)`
color: ${({ theme }) => theme.textTertiary};
`
const DefaultDownArrow = styled(ArrowDownRight)`
color: ${({ theme }) => theme.textTertiary};
`
function calculateDelta(start: number, current: number) { function calculateDelta(start: number, current: number) {
return (current / start - 1) * 100 return (current / start - 1) * 100
} }
export function getDeltaArrow(delta: number | null | undefined, iconSize = 20) { export function getDeltaArrow(delta: number | null | undefined, iconSize = 20, styled = true) {
// Null-check not including zero // Null-check not including zero
if (delta === null || delta === undefined) { if (delta === null || delta === undefined) {
return null return null
} else if (Math.sign(delta) < 0) { } else if (Math.sign(delta) < 0) {
return <StyledDownArrow size={iconSize} key="arrow-down" aria-label="down" /> return styled ? (
<StyledDownArrow size={iconSize} key="arrow-down" aria-label="down" />
) : (
<DefaultDownArrow size={iconSize} key="arrow-down" aria-label="down" />
)
} }
return <StyledUpArrow size={iconSize} key="arrow-up" aria-label="up" /> return styled ? (
<StyledUpArrow size={iconSize} key="arrow-up" aria-label="up" />
) : (
<DefaultUpArrow size={iconSize} key="arrow-up" aria-label="up" />
)
} }
export function formatDelta(delta: number | null | undefined) { export function formatDelta(delta: number | null | undefined) {
...@@ -84,6 +100,10 @@ const MissingPrice = styled(TokenPrice)` ...@@ -84,6 +100,10 @@ const MissingPrice = styled(TokenPrice)`
color: ${({ theme }) => theme.textTertiary}; color: ${({ theme }) => theme.textTertiary};
` `
const OutdatedContainer = styled.div`
color: ${({ theme }) => theme.textSecondary};
`
const DeltaContainer = styled.div` const DeltaContainer = styled.div`
height: 16px; height: 16px;
display: flex; display: flex;
...@@ -95,6 +115,13 @@ export const ArrowCell = styled.div` ...@@ -95,6 +115,13 @@ export const ArrowCell = styled.div`
display: flex; display: flex;
` `
const OutdatedPriceContainer = styled.div`
display: flex;
gap: 6px;
font-size: 24px;
line-height: 44px;
`
function fixChart(prices: PricePoint[] | undefined | null) { function fixChart(prices: PricePoint[] | undefined | null) {
if (!prices) return { prices: null, blanks: [] } if (!prices) return { prices: null, blanks: [] }
...@@ -148,6 +175,34 @@ export function PriceChart({ width, height, prices: originalPrices, timePeriod } ...@@ -148,6 +175,34 @@ export function PriceChart({ width, height, prices: originalPrices, timePeriod }
) )
) : null ) : null
const tooltipMessage = (
<>
<Trans>This price may not be up-to-date due to low trading volume.</Trans>
</>
)
//get the last non-zero price point
const lastPrice = useMemo(() => {
if (!prices) return DATA_EMPTY
for (let i = prices.length - 1; i >= 0; i--) {
if (prices[i].value !== 0) return prices[i]
}
return DATA_EMPTY
}, [prices])
//get the first non-zero price point
const firstPrice = useMemo(() => {
if (!prices) return DATA_EMPTY
for (let i = 0; i < prices.length; i++) {
if (prices[i].value !== 0) return prices[i]
}
return DATA_EMPTY
}, [prices])
const totalDelta = calculateDelta(firstPrice.value, lastPrice.value)
const formattedTotalDelta = formatDelta(totalDelta)
const defaultArrow = getDeltaArrow(totalDelta, 20, false)
// first price point on the x-axis of the current time period's chart // first price point on the x-axis of the current time period's chart
const startingPrice = originalPrices?.[0] ?? DATA_EMPTY const startingPrice = originalPrices?.[0] ?? DATA_EMPTY
// last price point on the x-axis of the current time period's chart // last price point on the x-axis of the current time period's chart
...@@ -302,6 +357,19 @@ export function PriceChart({ width, height, prices: originalPrices, timePeriod } ...@@ -302,6 +357,19 @@ export function PriceChart({ width, height, prices: originalPrices, timePeriod }
<ArrowCell>{arrow}</ArrowCell> <ArrowCell>{arrow}</ArrowCell>
</DeltaContainer> </DeltaContainer>
</> </>
) : lastPrice.value ? (
<OutdatedContainer>
<OutdatedPriceContainer>
<TokenPrice>{formatUSDPrice(lastPrice.value)}</TokenPrice>
<MouseoverTooltip text={tooltipMessage}>
<Info size={16} />
</MouseoverTooltip>
</OutdatedPriceContainer>
<DeltaContainer>
{formattedTotalDelta}
<ArrowCell>{defaultArrow}</ArrowCell>
</DeltaContainer>
</OutdatedContainer>
) : ( ) : (
<> <>
<MissingPrice>Price Unavailable</MissingPrice> <MissingPrice>Price Unavailable</MissingPrice>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment