You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
2.2 KiB
96 lines
2.2 KiB
import * as React from 'react';
|
|
import Statistic, { StatisticProps } from './Statistic';
|
|
import { formatCountdown, countdownValueType, FormatConfig } from './utils';
|
|
import { cloneElement } from '../_util/reactNode';
|
|
|
|
const REFRESH_INTERVAL = 1000 / 30;
|
|
|
|
interface CountdownProps extends StatisticProps {
|
|
value?: countdownValueType;
|
|
format?: string;
|
|
onFinish?: () => void;
|
|
onChange?: (value?: countdownValueType) => void;
|
|
}
|
|
|
|
function getTime(value?: countdownValueType) {
|
|
return new Date(value as any).getTime();
|
|
}
|
|
|
|
class Countdown extends React.Component<CountdownProps, {}> {
|
|
static defaultProps: Partial<CountdownProps> = {
|
|
format: 'HH:mm:ss',
|
|
};
|
|
|
|
countdownId?: number;
|
|
|
|
componentDidMount() {
|
|
this.syncTimer();
|
|
}
|
|
|
|
componentDidUpdate() {
|
|
this.syncTimer();
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.stopTimer();
|
|
}
|
|
|
|
syncTimer = () => {
|
|
const { value } = this.props;
|
|
|
|
const timestamp = getTime(value);
|
|
if (timestamp >= Date.now()) {
|
|
this.startTimer();
|
|
} else {
|
|
this.stopTimer();
|
|
}
|
|
};
|
|
|
|
startTimer = () => {
|
|
if (this.countdownId) return;
|
|
|
|
const { onChange, value } = this.props;
|
|
const timestamp = getTime(value);
|
|
|
|
this.countdownId = window.setInterval(() => {
|
|
this.forceUpdate();
|
|
|
|
if (onChange && timestamp > Date.now()) {
|
|
onChange(timestamp - Date.now());
|
|
}
|
|
}, REFRESH_INTERVAL);
|
|
};
|
|
|
|
stopTimer = () => {
|
|
const { onFinish, value } = this.props;
|
|
if (this.countdownId) {
|
|
clearInterval(this.countdownId);
|
|
this.countdownId = undefined;
|
|
|
|
const timestamp = getTime(value);
|
|
if (onFinish && timestamp < Date.now()) {
|
|
onFinish();
|
|
}
|
|
}
|
|
};
|
|
|
|
formatCountdown = (value: countdownValueType, config: FormatConfig) => {
|
|
const { format } = this.props;
|
|
return formatCountdown(value, { ...config, format });
|
|
};
|
|
|
|
// Countdown do not need display the timestamp
|
|
// eslint-disable-next-line class-methods-use-this
|
|
valueRender = (node: React.ReactElement<HTMLDivElement>) =>
|
|
cloneElement(node, {
|
|
title: undefined,
|
|
});
|
|
|
|
render() {
|
|
return (
|
|
<Statistic valueRender={this.valueRender} {...this.props} formatter={this.formatCountdown} />
|
|
);
|
|
}
|
|
}
|
|
|
|
export default Countdown;
|
|
|