// Copyright 2017-2021 @polkadot/react-query authors & contributors // SPDX-License-Identifier: Apache-2.0 import BN from 'bn.js'; import React, { useEffect, useState } from 'react'; import styled from 'styled-components'; import { bnToBn } from '@polkadot/util'; type Ticker = (now: number) => void; interface Props { children?: React.ReactNode; className?: string; value?: BN | Date | number; } const TICK_TIMEOUT = 100; const tickers = new Map(); let lastNow = Date.now(); let lastId = 0; function tick (): void { lastNow = Date.now(); for (const ticker of tickers.values()) { ticker(lastNow); } setTimeout(tick, TICK_TIMEOUT); } function formatValue (value: number, type = 's', withDecimal = false): React.ReactNode { const [pre, post] = value.toFixed(1).split('.'); const before = pre.split('').map((d, index) => (
{d}
)); return withDecimal ? <>{before}.
{post}
{type} : <>{before} s; } function getDisplayValue (now = 0, value: BN | Date | number = 0): React.ReactNode { const tsValue = ( value && (value as Date).getTime ? (value as Date).getTime() : bnToBn(value as number).toNumber() ) || 0; let display = formatValue(0, 's', true); if (now && tsValue) { const elapsed = Math.max(Math.abs(now - tsValue), 0) / 1000; if (elapsed < 15) { display = formatValue(elapsed, 's', true); } else if (elapsed < 60) { display = formatValue(elapsed); } else if (elapsed < 3600) { display = formatValue(elapsed, 'min'); } else { display = formatValue(elapsed / 3600, 'hr'); } } return display; } tick(); function Elapsed ({ children, className = '', value }: Props): React.ReactElement { const [now, setNow] = useState(lastNow); useEffect((): () => void => { const id = lastId++; tickers.set(id, setNow); return (): void => { tickers.delete(id); }; }, []); return (
{getDisplayValue(now, value)}{children}
); } export default React.memo(styled(Elapsed)` .digit { display: inline-block; width: 1ch; } `);