Browse Source

Countdown support `onFinish` (#14791)

* support onFinish

* clean up

* update test case
pull/14820/head
zombieJ 6 years ago
committed by GitHub
parent
commit
5ad9469434
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      components/statistic/Countdown.tsx
  2. 34
      components/statistic/__tests__/index.test.js
  3. 6
      components/statistic/demo/countdown.md
  4. 1
      components/statistic/index.en-US.md
  5. 1
      components/statistic/index.zh-CN.md

21
components/statistic/Countdown.tsx

@ -10,6 +10,11 @@ const REFRESH_INTERVAL = 1000 / 30;
interface CountdownProps extends StatisticProps { interface CountdownProps extends StatisticProps {
value?: countdownValueType; value?: countdownValueType;
format?: string; format?: string;
onFinish?: () => void;
}
function getTime(value?: countdownValueType) {
return interopDefault(moment)(value).valueOf();
} }
class Countdown extends React.Component<CountdownProps, {}> { class Countdown extends React.Component<CountdownProps, {}> {
@ -34,7 +39,7 @@ class Countdown extends React.Component<CountdownProps, {}> {
syncTimer = () => { syncTimer = () => {
const { value } = this.props; const { value } = this.props;
const timestamp = interopDefault(moment)(value).valueOf(); const timestamp = getTime(value);
if (timestamp >= Date.now()) { if (timestamp >= Date.now()) {
this.startTimer(); this.startTimer();
} else { } else {
@ -43,7 +48,7 @@ class Countdown extends React.Component<CountdownProps, {}> {
}; };
startTimer = () => { startTimer = () => {
if (this.countdownId !== undefined) return; if (this.countdownId) return;
this.countdownId = window.setInterval(() => { this.countdownId = window.setInterval(() => {
this.forceUpdate(); this.forceUpdate();
@ -51,8 +56,16 @@ class Countdown extends React.Component<CountdownProps, {}> {
}; };
stopTimer = () => { stopTimer = () => {
clearInterval(this.countdownId); const { onFinish, value } = this.props;
this.countdownId = undefined; if (this.countdownId) {
clearInterval(this.countdownId);
this.countdownId = undefined;
const timestamp = getTime(value);
if (onFinish && timestamp < Date.now()) {
onFinish();
}
}
}; };
formatCountdown = (value: countdownValueType, config: FormatConfig) => { formatCountdown = (value: countdownValueType, config: FormatConfig) => {

34
components/statistic/__tests__/index.test.js

@ -61,17 +61,47 @@ describe('Statistic', () => {
it('time going', async () => { it('time going', async () => {
const now = Date.now() + 1000; const now = Date.now() + 1000;
const wrapper = mount(<Statistic.Countdown value={now} />); const onFinish = jest.fn();
const wrapper = mount(<Statistic.Countdown value={now} onFinish={onFinish} />);
wrapper.update(); wrapper.update();
// setInterval should work // setInterval should work
const instance = wrapper.instance(); const instance = wrapper.instance();
expect(instance.countdownId).not.toBe(undefined); expect(instance.countdownId).not.toBe(undefined);
await delay(50); await delay(10);
wrapper.unmount(); wrapper.unmount();
expect(instance.countdownId).toBe(undefined); expect(instance.countdownId).toBe(undefined);
expect(onFinish).not.toBeCalled();
});
describe('time finished', () => {
it('not call if time already passed', () => {
const now = Date.now() - 1000;
const onFinish = jest.fn();
const wrapper = mount(<Statistic.Countdown value={now} onFinish={onFinish} />);
wrapper.update();
const instance = wrapper.instance();
expect(instance.countdownId).toBe(undefined);
expect(onFinish).not.toBeCalled();
});
it('called if finished', async () => {
jest.useFakeTimers();
const now = Date.now() + 10;
const onFinish = jest.fn();
const wrapper = mount(<Statistic.Countdown value={now} onFinish={onFinish} />);
wrapper.update();
MockDate.set(moment('2019-11-28 00:00:00'));
jest.runAllTimers();
expect(onFinish).toBeCalled();
jest.useFakeTimers();
});
}); });
}); });
}); });

6
components/statistic/demo/countdown.md

@ -19,10 +19,14 @@ import { Statistic, Row, Col } from 'antd';
const Countdown = Statistic.Countdown; const Countdown = Statistic.Countdown;
const deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; // Moment is also OK const deadline = Date.now() + 1000 * 60 * 60 * 24 * 2 + 1000 * 30; // Moment is also OK
function onFinish() {
console.log('finished!');
}
ReactDOM.render( ReactDOM.render(
<Row gutter={16}> <Row gutter={16}>
<Col span={12}> <Col span={12}>
<Countdown title="Countdown" value={deadline} /> <Countdown title="Countdown" value={deadline} onFinish={onFinish} />
</Col> </Col>
<Col span={12}> <Col span={12}>
<Countdown title="Million Seconds" value={deadline} format="HH:mm:ss:SSS" /> <Countdown title="Million Seconds" value={deadline} format="HH:mm:ss:SSS" />

1
components/statistic/index.en-US.md

@ -32,6 +32,7 @@ Display statistic number.
| Property | Description | Type | Default | | Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- | | -------- | ----------- | ---- | ------- |
| format | Format as [moment](http://momentjs.com/) | string | 'HH:mm:ss' | | format | Format as [moment](http://momentjs.com/) | string | 'HH:mm:ss' |
| onFinish | Trigger when time's up | () => void | - |
| prefix | prefix node of value | string \| ReactNode | - | | prefix | prefix node of value | string \| ReactNode | - |
| suffix | suffix node of value | string \| ReactNode | - | | suffix | suffix node of value | string \| ReactNode | - |
| title | Display title | string \| ReactNode | - | | title | Display title | string \| ReactNode | - |

1
components/statistic/index.zh-CN.md

@ -33,6 +33,7 @@ title: Statistic
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
| -------- | ----------- | ---- | ------- | | -------- | ----------- | ---- | ------- |
| format | 格式化倒计时展示,参考 [moment](http://momentjs.com/) | string | 'HH:mm:ss' | | format | 格式化倒计时展示,参考 [moment](http://momentjs.com/) | string | 'HH:mm:ss' |
| onFinish | 倒计时完成时触发 | () => void | - |
| prefix | 设置数值的前缀 | string \| ReactNode | - | | prefix | 设置数值的前缀 | string \| ReactNode | - |
| suffix | 设置数值的后缀 | string \| ReactNode | - | | suffix | 设置数值的后缀 | string \| ReactNode | - |
| title | 数值的标题 | string \| ReactNode | - | | title | 数值的标题 | string \| ReactNode | - |

Loading…
Cancel
Save