Commit 6e68889c authored by tom's avatar tom

new data format and update times

parent 64fc9610
...@@ -5,10 +5,24 @@ export const base: HomeStats = { ...@@ -5,10 +5,24 @@ export const base: HomeStats = {
coin_price: '0.00199678', coin_price: '0.00199678',
coin_price_change_percentage: -7.42, coin_price_change_percentage: -7.42,
gas_prices: { gas_prices: {
average: 48.0, average: {
fast: 67.5, fiat_price: '1.01',
slow: 48.0, price: 20.41,
time: 12283,
},
fast: {
fiat_price: '1.26',
price: 25.47,
time: 9321,
},
slow: {
fiat_price: '0.97',
price: 19.55,
time: 24543,
},
}, },
gas_price_updated_at: '2022-11-11T11:09:49.051171Z',
gas_prices_update_in: 300000,
gas_used_today: '4108680603', gas_used_today: '4108680603',
market_cap: '330809.96443288102524', market_cap: '330809.96443288102524',
network_utilization_percentage: 1.55372064, network_utilization_percentage: 1.55372064,
......
...@@ -5,10 +5,24 @@ export const HOMEPAGE_STATS: HomeStats = { ...@@ -5,10 +5,24 @@ export const HOMEPAGE_STATS: HomeStats = {
coin_price: '1807.68', coin_price: '1807.68',
coin_price_change_percentage: 42, coin_price_change_percentage: 42,
gas_prices: { gas_prices: {
average: 0.1, average: {
fast: 0.11, fiat_price: '1.01',
slow: 0.1, price: 20.41,
time: 12283,
},
fast: {
fiat_price: '1.26',
price: 25.47,
time: 9321,
},
slow: {
fiat_price: '0.97',
price: 19.55,
time: 24543,
},
}, },
gas_price_updated_at: '2022-11-11T11:09:49.051171Z',
gas_prices_update_in: 300000,
gas_used_today: '0', gas_used_today: '0',
market_cap: '0', market_cap: '0',
network_utilization_percentage: 22.56, network_utilization_percentage: 22.56,
......
...@@ -9,6 +9,8 @@ export type HomeStats = { ...@@ -9,6 +9,8 @@ export type HomeStats = {
transactions_today: string; transactions_today: string;
gas_used_today: string; gas_used_today: string;
gas_prices: GasPrices | null; gas_prices: GasPrices | null;
gas_price_updated_at: string | null;
gas_prices_update_in: number;
static_gas_price: string | null; static_gas_price: string | null;
market_cap: string; market_cap: string;
network_utilization_percentage: number; network_utilization_percentage: number;
...@@ -17,9 +19,15 @@ export type HomeStats = { ...@@ -17,9 +19,15 @@ export type HomeStats = {
} }
export type GasPrices = { export type GasPrices = {
average: number | null; average: GasPriceInfo | null;
fast: number | null; fast: GasPriceInfo | null;
slow: number | null; slow: GasPriceInfo | null;
}
export interface GasPriceInfo {
fiat_price: string | null;
price: number | null;
time: number | null;
} }
export type Counters = { export type Counters = {
......
...@@ -51,7 +51,7 @@ const Stats = () => { ...@@ -51,7 +51,7 @@ const Stats = () => {
!data.gas_prices && itemsCount--; !data.gas_prices && itemsCount--;
data.rootstock_locked_btc && itemsCount++; data.rootstock_locked_btc && itemsCount++;
const isOdd = Boolean(itemsCount % 2); const isOdd = Boolean(itemsCount % 2);
const gasLabel = hasGasTracker && data.gas_prices ? <GasInfoTooltipContent gasPrices={ data.gas_prices }/> : null; const gasLabel = hasGasTracker && data.gas_prices ? <GasInfoTooltipContent data={ data }/> : null;
content = ( content = (
<> <>
...@@ -98,7 +98,10 @@ const Stats = () => { ...@@ -98,7 +98,10 @@ const Stats = () => {
<StatsItem <StatsItem
icon="gas" icon="gas"
title="Gas tracker" title="Gas tracker"
value={ data.gas_prices.average !== null ? `${ Number(data.gas_prices.average).toLocaleString() } Gwei` : 'N/A' } value={ data.gas_prices.average && data.gas_prices.average.price !== null ?
`${ Number(data.gas_prices.average.price).toLocaleString() } Gwei` :
'N/A'
}
_last={ isOdd ? lastItemTouchStyle : undefined } _last={ isOdd ? lastItemTouchStyle : undefined }
tooltipLabel={ gasLabel } tooltipLabel={ gasLabel }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
......
import { GridItem, chakra, useColorModeValue } from '@chakra-ui/react';
import React from 'react';
import type { GasPriceInfo } from 'types/api/stats';
import { asymp, space } from 'lib/html-entities';
interface Props {
name: string;
info: GasPriceInfo | null;
}
const GasInfoRow = ({ name, info }: Props) => {
const labelColor = useColorModeValue('blue.100', 'blue.600');
const content = (() => {
if (!info || info.price === null) {
return 'N/A';
}
return (
<>
<span>{ info.price } Gwei</span>
{ info.time && (
<chakra.span color="text_secondary">
{ space }per tx { asymp } { (info.time / 1000).toLocaleString(undefined, { maximumFractionDigits: 1 }) }s
</chakra.span>
) }
</>
);
})();
return (
<>
<GridItem color={ labelColor }>{ name }</GridItem>
<GridItem textAlign="right">{ content }</GridItem>
</>
);
};
export default React.memo(GasInfoRow);
import { Grid, GridItem, useColorModeValue } from '@chakra-ui/react'; import { Grid, GridItem } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { GasPrices } from 'types/api/stats'; import type { HomeStats } from 'types/api/stats';
const GasInfoTooltipContent = ({ gasPrices }: {gasPrices: GasPrices}) => { import dayjs from 'lib/date/dayjs';
const nameStyleProps = {
color: useColorModeValue('blue.100', 'blue.600'), import GasInfoRow from './GasInfoRow';
}; import GasInfoUpdateTimer from './GasInfoUpdateTimer';
interface Props {
data: HomeStats;
}
const GasInfoTooltipContent = ({ data }: Props) => {
if (!data.gas_prices) {
return null;
}
return ( return (
<Grid templateColumns="repeat(2, max-content)" rowGap={ 2 } columnGap={ 4 } padding={ 4 } fontSize="xs"> <Grid templateColumns="repeat(2, max-content)" rowGap={ 2 } columnGap={ 4 } padding={ 4 } fontSize="xs" lineHeight={ 4 }>
<GridItem { ...nameStyleProps }>Slow</GridItem> { data.gas_price_updated_at && (
<GridItem>{ gasPrices.slow !== null ? `${ gasPrices.slow } Gwei` : 'N/A' }</GridItem> <>
<GridItem { ...nameStyleProps }>Average</GridItem> <GridItem color="text_secondary">Last update</GridItem>
<GridItem>{ gasPrices.average !== null ? `${ gasPrices.average } Gwei` : 'N/A' }</GridItem> <GridItem color="text_secondary" display="flex" justifyContent="flex-end" columnGap={ 2 }>
<GridItem { ...nameStyleProps }>Fast</GridItem> { dayjs(data.gas_price_updated_at).format('MMM DD, HH:mm:ss') }
<GridItem>{ gasPrices.fast !== null ? `${ gasPrices.fast } Gwei` : 'N/A' }</GridItem> { data.gas_prices_update_in !== 0 &&
<GasInfoUpdateTimer startTime={ data.gas_price_updated_at } duration={ data.gas_prices_update_in }/> }
</GridItem>
</>
) }
<GasInfoRow name="Slow" info={ data.gas_prices.slow }/>
<GasInfoRow name="Average" info={ data.gas_prices.average }/>
<GasInfoRow name="Fast" info={ data.gas_prices.fast }/>
</Grid> </Grid>
); );
}; };
......
import { CircularProgress } from '@chakra-ui/react';
import React from 'react';
import { SECOND } from 'lib/consts';
import dayjs from 'lib/date/dayjs';
interface Props {
startTime: string;
duration: number;
}
const getValue = (startDate: dayjs.Dayjs, duration: number) => {
const now = dayjs();
const diff = now.diff(startDate, 'ms');
const value = diff / duration * 100;
if (value >= 99) {
return 99;
}
return value;
};
const GasInfoUpdateTimer = ({ startTime, duration }: Props) => {
const [ value, setValue ] = React.useState(getValue(dayjs(startTime), duration));
React.useEffect(() => {
const startDate = dayjs(startTime);
const intervalId = window.setInterval(() => {
const nextValue = getValue(startDate, duration);
setValue(nextValue);
if (nextValue === 99) {
window.clearInterval(intervalId);
}
}, SECOND);
return () => {
window.clearInterval(intervalId);
};
}, [ startTime, duration ]);
return <CircularProgress value={ value } trackColor="whiteAlpha.100" size={ 4 }/>;
};
export default React.memo(GasInfoUpdateTimer);
...@@ -3,6 +3,8 @@ import React from 'react'; ...@@ -3,6 +3,8 @@ import React from 'react';
import config from 'configs/app'; import config from 'configs/app';
import useApiQuery from 'lib/api/useApiQuery'; import useApiQuery from 'lib/api/useApiQuery';
import { SECOND } from 'lib/consts';
import dayjs from 'lib/date/dayjs';
import { HOMEPAGE_STATS } from 'stubs/stats'; import { HOMEPAGE_STATS } from 'stubs/stats';
import GasInfoTooltipContent from 'ui/shared/GasInfoTooltipContent/GasInfoTooltipContent'; import GasInfoTooltipContent from 'ui/shared/GasInfoTooltipContent/GasInfoTooltipContent';
import TextSeparator from 'ui/shared/TextSeparator'; import TextSeparator from 'ui/shared/TextSeparator';
...@@ -16,7 +18,7 @@ const TopBarStats = () => { ...@@ -16,7 +18,7 @@ const TopBarStats = () => {
onToggle(); onToggle();
}, [ onToggle ]); }, [ onToggle ]);
const { data, isPlaceholderData, isError } = useApiQuery('homepage_stats', { const { data, isPlaceholderData, isError, refetch } = useApiQuery('homepage_stats', {
fetchParams: { fetchParams: {
headers: { headers: {
'updated-gas-oracle': 'true', 'updated-gas-oracle': 'true',
...@@ -28,6 +30,27 @@ const TopBarStats = () => { ...@@ -28,6 +30,27 @@ const TopBarStats = () => {
}, },
}); });
React.useEffect(() => {
if (isPlaceholderData || !data?.gas_price_updated_at) {
return;
}
const endDate = dayjs(data.gas_price_updated_at).add(data.gas_prices_update_in, 'ms');
const timeout = endDate.diff(dayjs(), 'ms');
if (timeout <= 0) {
return;
}
const timeoutId = window.setTimeout(() => {
refetch();
}, timeout + SECOND);
return () => {
window.clearTimeout(timeoutId);
};
}, [ isPlaceholderData, data?.gas_price_updated_at, data?.gas_prices_update_in, refetch ]);
if (isError) { if (isError) {
return <div/>; return <div/>;
} }
...@@ -59,7 +82,7 @@ const TopBarStats = () => { ...@@ -59,7 +82,7 @@ const TopBarStats = () => {
<chakra.span color="text_secondary">Gas </chakra.span> <chakra.span color="text_secondary">Gas </chakra.span>
<LightMode> <LightMode>
<Tooltip <Tooltip
label={ <GasInfoTooltipContent gasPrices={ data.gas_prices }/> } label={ <GasInfoTooltipContent data={ data }/> }
hasArrow={ false } hasArrow={ false }
borderRadius="md" borderRadius="md"
offset={ [ 0, 16 ] } offset={ [ 0, 16 ] }
...@@ -73,7 +96,7 @@ const TopBarStats = () => { ...@@ -73,7 +96,7 @@ const TopBarStats = () => {
onMouseEnter={ onOpen } onMouseEnter={ onOpen }
onMouseLeave={ onClose } onMouseLeave={ onClose }
> >
{ data.gas_prices.average } Gwei { data.gas_prices.average.price } Gwei
</Link> </Link>
</Tooltip> </Tooltip>
</LightMode> </LightMode>
......
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