Tom Kirkpatrick
6 years ago
6 changed files with 148 additions and 0 deletions
@ -0,0 +1,85 @@ |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
|
|||
import { FormattedMessage, FormattedRelative } from 'react-intl' |
|||
import { Text } from 'components/UI' |
|||
import messages from './messages' |
|||
|
|||
class Countdown extends React.Component { |
|||
state = { |
|||
isExpired: null, |
|||
timer: null |
|||
} |
|||
|
|||
static propTypes = { |
|||
colorActive: PropTypes.string, |
|||
colorExpired: PropTypes.string, |
|||
date: PropTypes.oneOfType([PropTypes.number, PropTypes.instanceOf(Date)]).isRequired, |
|||
countdownStyle: PropTypes.string, |
|||
countUpAfterExpire: PropTypes.bool, |
|||
updateInterval: PropTypes.number |
|||
} |
|||
|
|||
static defaultProps = { |
|||
colorActive: 'superGreen', |
|||
colorExpired: 'superRed', |
|||
countdownStyle: 'best fit', |
|||
countUpAfterExpire: true, |
|||
updateInterval: 1000 |
|||
} |
|||
|
|||
componentDidMount() { |
|||
let { date } = this.props |
|||
if (date instanceof Date) { |
|||
date = new Date(date) |
|||
} |
|||
|
|||
const expiresIn = date - Date.now() |
|||
if (expiresIn >= 0) { |
|||
this.setState({ isExpired: false }) |
|||
const timer = setInterval(() => this.setState({ isExpired: true }), expiresIn) |
|||
this.setState({ timer }) |
|||
} else { |
|||
this.setState({ isExpired: true }) |
|||
} |
|||
} |
|||
|
|||
componentWillUnmount() { |
|||
const { timer } = this.state |
|||
clearInterval(timer) |
|||
} |
|||
|
|||
render() { |
|||
const { |
|||
colorActive, |
|||
colorExpired, |
|||
countdownStyle, |
|||
countUpAfterExpire, |
|||
date, |
|||
updateInterval, |
|||
...rest |
|||
} = this.props |
|||
const { isExpired } = this.state |
|||
return ( |
|||
<Text color={isExpired ? colorExpired : colorActive} {...rest}> |
|||
{isExpired ? ( |
|||
<FormattedMessage {...messages.expired} /> |
|||
) : ( |
|||
<FormattedMessage {...messages.expires} /> |
|||
)} |
|||
{(!isExpired || (isExpired && countUpAfterExpire)) && ( |
|||
<React.Fragment> |
|||
{` `} |
|||
<FormattedRelative |
|||
value={new Date(date)} |
|||
updateInterval={updateInterval} |
|||
style={countdownStyle} |
|||
/> |
|||
</React.Fragment> |
|||
)} |
|||
</Text> |
|||
) |
|||
} |
|||
} |
|||
|
|||
export default Countdown |
@ -0,0 +1,30 @@ |
|||
import React from 'react' |
|||
import { storiesOf } from '@storybook/react' |
|||
import { Countdown } from 'components/UI' |
|||
|
|||
storiesOf('Components.Countdown', module).addWithChapters('Countdown', { |
|||
chapters: [ |
|||
{ |
|||
sections: [ |
|||
{ |
|||
title: 'Default', |
|||
sectionFn: () => <Countdown date={Date.now() + 5000} /> |
|||
}, |
|||
{ |
|||
title: 'Stop after expire', |
|||
sectionFn: () => <Countdown date={Date.now() + 5000} countUpAfterExpire={false} /> |
|||
}, |
|||
{ |
|||
title: 'Custom colors', |
|||
sectionFn: () => ( |
|||
<Countdown |
|||
date={Date.now() + 5000} |
|||
colorActive="lightningOrange" |
|||
colorExpired="yellow" |
|||
/> |
|||
) |
|||
} |
|||
] |
|||
} |
|||
] |
|||
}) |
@ -0,0 +1,11 @@ |
|||
import React from 'react' |
|||
import { shallow } from 'enzyme' |
|||
import toJSON from 'enzyme-to-json' |
|||
import { Countdown } from 'components/UI' |
|||
|
|||
describe('component.UI.Countdown', () => { |
|||
it('should render correctly with default props', () => { |
|||
const wrapper = shallow(<Countdown />) |
|||
expect(toJSON(wrapper)).toMatchSnapshot() |
|||
}) |
|||
}) |
@ -0,0 +1,19 @@ |
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
|||
|
|||
exports[`component.UI.Countdown should render correctly with default props 1`] = ` |
|||
<Text |
|||
color="superRed" |
|||
> |
|||
<FormattedMessage |
|||
defaultMessage="Expired" |
|||
id="components.UI.expired" |
|||
values={Object {}} |
|||
/> |
|||
|
|||
<FormattedRelative |
|||
style="best fit" |
|||
updateInterval={1000} |
|||
value={Date { NaN }} |
|||
/> |
|||
</Text> |
|||
`; |
Loading…
Reference in new issue