1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
2// See the LICENCE file in the repository root for full licence text.
3
4import { computed, makeObservable } from 'mobx';
5import { observer } from 'mobx-react';
6import * as moment from 'moment';
7import * as React from 'react';
8import { trans } from 'utils/lang';
9
10const bn = 'countdown-timer';
11const secondsPerDay = 60 * 60 * 24;
12const secondsPerHour = 60 * 60;
13
14interface Props {
15 deadline: string;
16}
17
18@observer
19export default class CountdownTimer extends React.Component<Props> {
20 private timer?: number;
21
22 @computed
23 private get deadline() {
24 return moment(this.props.deadline).valueOf();
25 }
26
27 private get diff() {
28 return Math.max(this.deadline - (new Date()).valueOf(), 0) / 1000;
29 }
30
31 constructor(props: Props) {
32 super(props);
33
34 makeObservable(this);
35 }
36
37 componentWillUnmount() {
38 window.clearTimeout(this.timer);
39 }
40
41 render() {
42 const diff = this.diff;
43 const fields = {
44 days: Math.floor(diff / (secondsPerDay)),
45 hours: Math.floor((diff / (secondsPerHour)) % 24),
46 minutes: Math.floor((diff / 60) % 60),
47 seconds: Math.floor(diff % 60),
48 };
49 if (diff !== 0) {
50 this.setTimeout();
51 }
52
53 return (
54 <div className={bn}>
55 <div className={`${bn}__header`}>{`${trans('common.time.remaining')}:`}</div>
56 {Object.entries(fields).map(([field, value]) => (
57 <div key={field} className={`${bn}__field`}>
58 <div className={`${bn}__digit`}>
59 {value < 10 ? `0${value}` : value}
60 </div>
61 <div className={`${bn}__label`}>{trans(`common.countdown.${field}`)}</div>
62 </div>
63 ))}
64 </div>
65 );
66 }
67
68 private setTimeout() {
69 this.timer = window.setTimeout(() => this.forceUpdate(), 1000);
70 }
71}