diff --git a/components/block-height.js b/components/block-height.js index 9e7e5e8f..3e3a48cc 100644 --- a/components/block-height.js +++ b/components/block-height.js @@ -2,13 +2,17 @@ import { createContext, useContext, useMemo } from 'react' import { useQuery } from '@apollo/client' import { NORMAL_POLL_INTERVAL, SSR } from '@/lib/constants' import { BLOCK_HEIGHT } from '@/fragments/blockHeight' +import { datePivot } from '@/lib/time' export const BlockHeightContext = createContext({ - height: 0 + height: 0, + halving: null }) export const useBlockHeight = () => useContext(BlockHeightContext) +const HALVING_INTERVAL = 210000 + export const BlockHeightProvider = ({ blockHeight, children }) => { const { data } = useQuery(BLOCK_HEIGHT, { ...(SSR @@ -18,9 +22,23 @@ export const BlockHeightProvider = ({ blockHeight, children }) => { nextFetchPolicy: 'cache-and-network' }) }) - const value = useMemo(() => ({ - height: data?.blockHeight ?? blockHeight ?? 0 - }), [data?.blockHeight, blockHeight]) + const value = useMemo(() => { + if (!data?.blockHeight) { + return { + height: blockHeight ?? 0, + halving: null + } + } + + const remainingBlocks = HALVING_INTERVAL - (data.blockHeight % HALVING_INTERVAL) + const minutesUntilHalving = remainingBlocks * 10 + const halving = datePivot(new Date(), { minutes: minutesUntilHalving }) + + return { + height: data.blockHeight, + halving + } + }, [data?.blockHeight, blockHeight]) return ( {children} diff --git a/components/countdown.js b/components/countdown.js index 9afcaa64..cd4c48f5 100644 --- a/components/countdown.js +++ b/components/countdown.js @@ -1,18 +1,53 @@ import Countdown from 'react-countdown' -export default function SimpleCountdown ({ className, onComplete, date }) { +export default function SimpleCountdown (props) { return ( - - {props.formatted.minutes}:{props.formatted.seconds}} - onComplete={onComplete} - /> - + { + return ( + <> + {props.formatted.minutes}:{props.formatted.seconds} + + ) + }} + /> ) } -export function LongCountdown ({ className, onComplete, date }) { +export function LongCountdown (props) { + return ( + { + return ( + <> + {props.formatted.days && `${props.formatted.days} days `} + {props.formatted.hours && `${props.formatted.hours} hours `} + {props.formatted.minutes && `${props.formatted.minutes} minutes `} + {props.formatted.seconds && `${props.formatted.seconds} seconds `} + + ) + }} + /> + ) +} + +export function CompactLongCountdown (props) { + return ( + { + return ( + <> + {props.formatted.days + ? ` ${props.formatted.days}d ${props.formatted.hours}h ${props.formatted.minutes}m ${props.formatted.seconds}s` + : ` ${props.formatted.hours}:${props.formatted.minutes}:${props.formatted.seconds}`} + + ) + }} + /> + ) +} + +function CountdownShared ({ className, onComplete, date, formatter }) { return ( { return ( - {props.formatted.days && `${props.formatted.days} days `} - {props.formatted.minutes && `${props.formatted.minutes} minutes `} - {props.formatted.seconds && `${props.formatted.seconds} seconds `} + {formatter(props)} ) }} diff --git a/components/price.js b/components/price.js index 436d7e42..5299a736 100644 --- a/components/price.js +++ b/components/price.js @@ -7,6 +7,7 @@ import { CURRENCY_SYMBOLS } from '@/lib/currency' import { NORMAL_POLL_INTERVAL, SSR } from '@/lib/constants' import { useBlockHeight } from './block-height' import { useChainFee } from './chain-fee' +import { CompactLongCountdown } from './countdown' export const PriceContext = React.createContext({ price: null, @@ -50,11 +51,9 @@ export default function Price ({ className }) { }, []) const { price, fiatSymbol } = usePrice() - const { height: blockHeight } = useBlockHeight() + const { height: blockHeight, halving } = useBlockHeight() const { fee: chainFee } = useChainFee() - if (!price || price < 0 || blockHeight <= 0 || chainFee <= 0) return null - // Options: yep, 1btc, blockHeight, undefined // yep -> 1btc -> blockHeight -> chainFee -> undefined -> yep const handleClick = () => { @@ -68,6 +67,9 @@ export default function Price ({ className }) { window.localStorage.setItem('asSats', 'chainFee') setAsSats('chainFee') } else if (asSats === 'chainFee') { + window.localStorage.setItem('asSats', 'halving') + setAsSats('halving') + } else if (asSats === 'halving') { window.localStorage.removeItem('asSats') setAsSats('fiat') } else { @@ -79,6 +81,7 @@ export default function Price ({ className }) { const compClassName = (className || '') + ' text-reset pointer' if (asSats === 'yep') { + if (!price || price < 0) return null return (
{fixedDecimal(100000000 / price, 0) + ` sats/${fiatSymbol}`} @@ -95,6 +98,7 @@ export default function Price ({ className }) { } if (asSats === 'blockHeight') { + if (blockHeight <= 0) return null return (
{blockHeight} @@ -102,7 +106,17 @@ export default function Price ({ className }) { ) } + if (asSats === 'halving') { + if (!halving) return null + return ( +
+ +
+ ) + } + if (asSats === 'chainFee') { + if (chainFee <= 0) return null return (
{chainFee} sat/vB @@ -111,6 +125,7 @@ export default function Price ({ className }) { } if (asSats === 'fiat') { + if (!price || price < 0) return null return (
{fiatSymbol + fixedDecimal(price, 0)} diff --git a/pages/rewards/index.js b/pages/rewards/index.js index 6a44ea7c..021f397f 100644 --- a/pages/rewards/index.js +++ b/pages/rewards/index.js @@ -7,7 +7,6 @@ import Layout from '@/components/layout' import { useMutation, useQuery } from '@apollo/client' import Link from 'next/link' import { amountSchema } from '@/lib/validate' -import Countdown from 'react-countdown' import { numWithUnits } from '@/lib/format' import PageLoading from '@/components/page-loading' import { useShowModal } from '@/components/modal' @@ -21,6 +20,7 @@ import { proportions } from '@/lib/madness' import { useData } from '@/components/use-data' import { GrowthPieChartSkeleton } from '@/components/charts-skeletons' import { useMemo } from 'react' +import { CompactLongCountdown } from '@/components/countdown' const GrowthPieChart = dynamic(() => import('@/components/charts').then(mod => mod.GrowthPieChart), { loading: () => @@ -77,15 +77,12 @@ export function RewardLine ({ total, time }) { {numWithUnits(total)} in rewards {time && - - - {props.formatted.days - ? ` ${props.formatted.days}d ${props.formatted.hours}h ${props.formatted.minutes}m ${props.formatted.seconds}s` - : ` ${props.formatted.hours}:${props.formatted.minutes}:${props.formatted.seconds}`} - } - />} + + + } ) }