diff --git a/src/App.js b/src/App.js
index cce40ce..bbf11ba 100644
--- a/src/App.js
+++ b/src/App.js
@@ -20,7 +20,10 @@ class App extends Component {
Christmas Eve is coming soon (Midnight of 23rd to 24th Dec, UTC time):
-
+
+
+ Countdown for 2 hours and 13 seconds, but showing just minutes and seconds:
+
);
}
diff --git a/src/Countdown.js b/src/Countdown.js
index b101841..4ed7c21 100644
--- a/src/Countdown.js
+++ b/src/Countdown.js
@@ -2,128 +2,216 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'
/**
- * Note :
+ * Note :
* If you're using react v 15.4 or less
- * You can directly import PropTypes from react instead.
+ * You can directly import PropTypes from react instead.
* Refer to this : https://reactjs.org/warnings/dont-call-proptypes.html
*/
-class Countdown extends Component {
- constructor(props) {
- super(props);
-
- this.state = {
- days: 0,
- hours: 0,
- min: 0,
- sec: 0,
- }
- }
-
- componentDidMount() {
- // update every second
- this.interval = setInterval(() => {
- const date = this.calculateCountdown(this.props.date);
- date ? this.setState(date) : this.stop();
- }, 1000);
- }
-
- componentWillUnmount() {
- this.stop();
- }
-
- calculateCountdown(endDate) {
- let diff = (Date.parse(new Date(endDate)) - Date.parse(new Date())) / 1000;
-
- // clear countdown when date is reached
- if (diff <= 0) return false;
-
- const timeLeft = {
- years: 0,
- days: 0,
- hours: 0,
- min: 0,
- sec: 0
- };
-
- // calculate time difference between now and expected date
- if (diff >= (365.25 * 86400)) { // 365.25 * 24 * 60 * 60
- timeLeft.years = Math.floor(diff / (365.25 * 86400));
- diff -= timeLeft.years * 365.25 * 86400;
- }
- if (diff >= 86400) { // 24 * 60 * 60
- timeLeft.days = Math.floor(diff / 86400);
- diff -= timeLeft.days * 86400;
- }
- if (diff >= 3600) { // 60 * 60
- timeLeft.hours = Math.floor(diff / 3600);
- diff -= timeLeft.hours * 3600;
- }
- if (diff >= 60) {
- timeLeft.min = Math.floor(diff / 60);
- diff -= timeLeft.min * 60;
- }
- timeLeft.sec = diff;
-
- return timeLeft;
- }
-
- stop() {
- clearInterval(this.interval);
- }
-
- addLeadingZeros(value) {
- value = String(value);
- while (value.length < 2) {
- value = '0' + value;
- }
- return value;
- }
-
- render() {
- const countDown = this.state;
-
- return (
-
-
-
- {this.addLeadingZeros(countDown.days)}
- {countDown.days === 1 ? 'Day' : 'Days'}
-
-
-
-
-
- {this.addLeadingZeros(countDown.hours)}
- Hours
-
-
-
-
-
-
- {this.addLeadingZeros(countDown.min)}
- Min
-
-
-
-
-
- {this.addLeadingZeros(countDown.sec)}
- Sec
-
-
-
- );
- }
-}
-
-Countdown.propTypes = {
- date: PropTypes.string.isRequired
-};
-
-Countdown.defaultProps = {
- date: new Date()
-};
-
-export default Countdown;
+ class Countdown extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ days: 0,
+ hours: 0,
+ min: 0,
+ sec: 0,
+ followDate: true,
+ timeToShow: {
+ days: 0,
+ hours: 0,
+ min: 0,
+ sec: 0,
+ },
+ }
+ }
+
+ componentDidMount() {
+ this.setState({ days: this.props.days,
+ hours: this.props.hours,
+ min: this.props.minutes,
+ sec: this.props.seconds });
+ if (this.props.days > 0
+ || this.props.hours > 0
+ || this.props.minutes > 0
+ || this.props.seconds > 0) {
+ this.setState({ followDate: false });
+ }
+
+ // update every second
+ this.interval = setInterval(() => {
+ const timeLeft = this.state.followDate ? this.calculateDateCountdown(this.props.date) : this.diminishSecondToCountdown(this.state);
+ if (timeLeft) {
+ const visualTimeLeft = this.adaptTimeToChosenComponents(timeLeft);
+ this.setState({ ...timeLeft, timeToShow: visualTimeLeft });
+ } else {
+ this.stop();
+ this.props.finishCallback();
+ }
+ }, 1000);
+ }
+
+ componentWillUnmount() {
+ this.stop();
+ }
+
+ adaptTimeToChosenComponents(time) {
+ let adaptedTime = { ...time }
+ if (!this.props.timeComponentsToShow.includes('days')) {
+ adaptedTime.hours += adaptedTime.days * 24;
+ adaptedTime.days = 0;
+ }
+ if (!this.props.timeComponentsToShow.includes('hours')) {
+ adaptedTime.min += adaptedTime.hours * 60;
+ adaptedTime.hours = 0;
+ }
+ if (!this.props.timeComponentsToShow.includes('minutes')) {
+ adaptedTime.sec += adaptedTime.min * 60;
+ adaptedTime.min = 0;
+ }
+ return adaptedTime
+ }
+
+ diminishSecondToCountdown(state) {
+ if (state.days === 0 && state.hours === 0 && state.min === 0 && state.sec === 0) {
+ return null;
+ }
+
+ const timeLeft = {
+ days: state.days,
+ hours: state.hours,
+ min: state.min,
+ sec: state.sec,
+ };
+ timeLeft.sec = timeLeft.sec - 1;
+ if (timeLeft.sec === -1) {
+ timeLeft.sec = 59;
+ timeLeft.min = timeLeft.min - 1;
+ }
+ if (timeLeft.min === -1) {
+ timeLeft.min = 59;
+ timeLeft.hours = timeLeft.hours - 1;
+ }
+ if (timeLeft.hours === -1) {
+ timeLeft.hours = 23;
+ timeLeft.days = timeLeft.days - 1;
+ }
+ return timeLeft;
+ }
+
+ calculateDateCountdown(endDate) {
+ let diff = (Date.parse(endDate) - Date.parse(new Date())) / 1000;
+
+ // clear countdown when date is reached
+ if (diff < 0) return null;
+
+ const timeLeft = {
+ years: 0,
+ days: 0,
+ hours: 0,
+ min: 0,
+ sec: 0,
+ millisec: 0,
+ };
+
+ // calculate time difference between now and expected date
+ if (diff >= (365.25 * 86400)) { // 365.25 * 24 * 60 * 60
+ timeLeft.years = Math.floor(diff / (365.25 * 86400));
+ diff -= timeLeft.years * 365.25 * 86400;
+ }
+ if (diff >= 86400) { // 24 * 60 * 60
+ timeLeft.days = Math.floor(diff / 86400);
+ diff -= timeLeft.days * 86400;
+ }
+ if (diff >= 3600) { // 60 * 60
+ timeLeft.hours = Math.floor(diff / 3600);
+ diff -= timeLeft.hours * 3600;
+ }
+ if (diff >= 60) {
+ timeLeft.min = Math.floor(diff / 60);
+ diff -= timeLeft.min * 60;
+ }
+ timeLeft.sec = diff;
+
+ return timeLeft;
+ }
+
+ stop() {
+ clearInterval(this.interval);
+ }
+
+ addLeadingZeros(value) {
+ value = String(value);
+ while (value.length < 2) {
+ value = '0' + value;
+ }
+ return value;
+ }
+
+ render() {
+ const countDown = this.state.timeToShow;
+ const timeComponentsToShow = this.props.timeComponentsToShow;
+ return (
+
+ { timeComponentsToShow.includes('days') && (
+
+
+ {this.addLeadingZeros(countDown.days)}
+ {countDown.days === 1 ? 'Day' : 'Days'}
+
+
+ )}
+
+ { timeComponentsToShow.includes('hours') && (
+
+
+ {this.addLeadingZeros(countDown.hours)}
+ Hours
+
+
+ )}
+
+ { timeComponentsToShow.includes('minutes') && (
+
+
+ {this.addLeadingZeros(countDown.min)}
+ Min
+
+
+ )}
+
+ { timeComponentsToShow.includes('seconds') && (
+
+
+ {this.addLeadingZeros(countDown.sec)}
+ Sec
+
+
+ )}
+
+ );
+ }
+ }
+
+ Countdown.propTypes = {
+ date: PropTypes.instanceOf(Date),
+ days: PropTypes.number,
+ hours: PropTypes.number,
+ minutes: PropTypes.number,
+ seconds: PropTypes.number,
+ timeComponentsToShow: PropTypes.arrayOf(PropTypes.oneOf(['days', 'hours', 'minutes', 'seconds'])),
+ finishCallback: PropTypes.func,
+ };
+
+ Countdown.defaultProps = {
+ date: new Date(),
+ days: 0,
+ hours: 0,
+ minutes: 0,
+ seconds: 0,
+ timeComponentsToShow: ['days', 'hours', 'minutes', 'seconds'],
+ finishCallback: () => void(0),
+ };
+
+ export default Countdown;