import * as React from 'react'; import './Tile.css'; import { timestamp, Types } from '../common'; interface AgoProps { when: Types.Timestamp; justTime?: boolean; } interface AgoState { now: Types.Timestamp; } const tickers = new Map void>(); function tick() { const now = timestamp(); for (const ticker of tickers.values()) { ticker(now); } setTimeout(tick, 100); } tick(); export class Ago extends React.Component { public static timeDiff = 0 as Types.Milliseconds; public state: AgoState; private agoStr: string; constructor(props: AgoProps) { super(props); this.state = { now: (timestamp() - Ago.timeDiff) as Types.Timestamp, }; this.agoStr = this.stringify(props.when, this.state.now); } public shouldComponentUpdate(nextProps: AgoProps, nextState: AgoState) { const nextAgoStr = this.stringify(nextProps.when, nextState.now); if (this.agoStr !== nextAgoStr) { this.agoStr = nextAgoStr; return true; } return false; } public componentDidMount() { tickers.set(this, (now) => { this.setState({ now: (now - Ago.timeDiff) as Types.Timestamp, }); }); } public componentWillUnmount() { tickers.delete(this); } public render() { if (this.props.when === 0) { return -; } return ( {this.agoStr} ); } private stringify(when: number, now: number): string { const ago = Math.max(now - when, 0) / 1000; let agoStr: string; if (ago < 10) { agoStr = `${ago.toFixed(1)}s`; } else if (ago < 60) { agoStr = `${ago | 0}s`; } else if (ago < 3600) { agoStr = `${(ago / 60) | 0}m`; } else if (ago < 3600 * 24) { agoStr = `${(ago / 3600) | 0}h`; } else { agoStr = `${(ago / (3600 * 24)) | 0}d`; } if (this.props.justTime !== true) { agoStr += ' ago'; } return agoStr; } }