add halving to price carousel

This commit is contained in:
keyan 2024-04-16 17:58:26 -05:00
parent a0f3e338a8
commit 058f88da49
4 changed files with 92 additions and 29 deletions

View File

@ -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 (
<BlockHeightContext.Provider value={value}>
{children}

View File

@ -1,18 +1,53 @@
import Countdown from 'react-countdown'
export default function SimpleCountdown ({ className, onComplete, date }) {
export default function SimpleCountdown (props) {
return (
<span className={className}>
<Countdown
date={date}
renderer={props => <span className='text-monospace' suppressHydrationWarning> {props.formatted.minutes}:{props.formatted.seconds}</span>}
onComplete={onComplete}
<CountdownShared
{...props} formatter={props => {
return (
<>
{props.formatted.minutes}:{props.formatted.seconds}
</>
)
}}
/>
</span>
)
}
export function LongCountdown ({ className, onComplete, date }) {
export function LongCountdown (props) {
return (
<CountdownShared
{...props} formatter={props => {
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 (
<CountdownShared
{...props} formatter={props => {
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 (
<span className={className}>
<Countdown
@ -20,9 +55,7 @@ export function LongCountdown ({ className, onComplete, date }) {
renderer={props => {
return (
<span suppressHydrationWarning>
{props.formatted.days && `${props.formatted.days} days `}
{props.formatted.minutes && `${props.formatted.minutes} minutes `}
{props.formatted.seconds && `${props.formatted.seconds} seconds `}
{formatter(props)}
</span>
)
}}

View File

@ -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 (
<div className={compClassName} onClick={handleClick} variant='link'>
{fixedDecimal(100000000 / price, 0) + ` sats/${fiatSymbol}`}
@ -95,6 +98,7 @@ export default function Price ({ className }) {
}
if (asSats === 'blockHeight') {
if (blockHeight <= 0) return null
return (
<div className={compClassName} onClick={handleClick} variant='link'>
{blockHeight}
@ -102,7 +106,17 @@ export default function Price ({ className }) {
)
}
if (asSats === 'halving') {
if (!halving) return null
return (
<div className={compClassName} onClick={handleClick} variant='link'>
<CompactLongCountdown date={halving} />
</div>
)
}
if (asSats === 'chainFee') {
if (chainFee <= 0) return null
return (
<div className={compClassName} onClick={handleClick} variant='link'>
{chainFee} sat/vB
@ -111,6 +125,7 @@ export default function Price ({ className }) {
}
if (asSats === 'fiat') {
if (!price || price < 0) return null
return (
<div className={compClassName} onClick={handleClick} variant='link'>
{fiatSymbol + fixedDecimal(price, 0)}

View File

@ -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: () => <GrowthPieChartSkeleton />
@ -77,15 +77,12 @@ export function RewardLine ({ total, time }) {
{numWithUnits(total)} in rewards
</span>
{time &&
<Countdown
<small style={{ whiteSpace: 'nowrap' }}>
<CompactLongCountdown
className='text-monospace'
date={time}
renderer={props =>
<small className='text-monospace' suppressHydrationWarning style={{ whiteSpace: 'nowrap' }}>
{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}`}
/>
</small>}
/>}
</>
)
}