add halving to price carousel
This commit is contained in:
parent
a0f3e338a8
commit
058f88da49
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
</span>
|
||||
<CountdownShared
|
||||
{...props} formatter={props => {
|
||||
return (
|
||||
<>
|
||||
{props.formatted.minutes}:{props.formatted.seconds}
|
||||
</>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
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>
|
||||
)
|
||||
}}
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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
|
||||
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>}
|
||||
/>}
|
||||
<small style={{ whiteSpace: 'nowrap' }}>
|
||||
<CompactLongCountdown
|
||||
className='text-monospace'
|
||||
date={time}
|
||||
/>
|
||||
</small>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue