Elapsed.tsx 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Copyright 2017-2020 @polkadot/react-query authors & contributors
  2. // This software may be modified and distributed under the terms
  3. // of the Apache-2.0 license. See the LICENSE file for details.
  4. import BN from 'bn.js';
  5. import React, { useEffect, useState } from 'react';
  6. import { bnToBn } from '@polkadot/util';
  7. type Ticker = (now: number) => void;
  8. interface Props {
  9. className?: string;
  10. value?: BN | Date | number;
  11. }
  12. const TICK_TIMEOUT = 100;
  13. const tickers = new Map<number, Ticker>();
  14. let lastNow = Date.now();
  15. let lastId = 0;
  16. function tick (): void {
  17. lastNow = Date.now();
  18. for (const ticker of tickers.values()) {
  19. ticker(lastNow);
  20. }
  21. setTimeout(tick, TICK_TIMEOUT);
  22. }
  23. function getDisplayValue (now = 0, value: BN | Date | number = 0): string {
  24. const tsValue = (
  25. value && (value as Date).getTime
  26. ? (value as Date).getTime()
  27. : bnToBn(value as number).toNumber()
  28. ) || 0;
  29. let display = '0.0 s';
  30. if (now && tsValue) {
  31. const elapsed = Math.max(Math.abs(now - tsValue), 0) / 1000;
  32. if (elapsed < 15) {
  33. display = `${elapsed.toFixed(1)} s`;
  34. } else if (elapsed < 60) {
  35. display = `${elapsed | 0} s`;
  36. } else if (elapsed < 3600) {
  37. display = `${elapsed / 60 | 0} min`;
  38. } else {
  39. display = `${elapsed / 3600 | 0} hr`;
  40. }
  41. }
  42. return display;
  43. }
  44. tick();
  45. function Elapsed ({ className = '', value }: Props): React.ReactElement<Props> {
  46. const [now, setNow] = useState(lastNow);
  47. useEffect((): () => void => {
  48. const id = lastId++;
  49. tickers.set(id, setNow);
  50. return (): void => {
  51. tickers.delete(id);
  52. };
  53. }, []);
  54. return (
  55. <div className={['ui--Elapsed', className].join(' ')}>
  56. {getDisplayValue(now, value)}
  57. </div>
  58. );
  59. }
  60. export default React.memo(Elapsed);