File: components/TimeAgo.js
/** @jsx React.DOM */
"use strict";
var React = require("react/addons");
var moment = require("moment");
var OverlayTrigger = require("react-bootstrap/OverlayTrigger");
var Tooltip = require("react-bootstrap/Tooltip");
// The app will have bunch of these mounted at once. To avoid each one randomly
// updating collect all the mounted instances here and update the time
// displays at once.
var mounted = [];
setInterval(function() {
mounted.forEach(function(c) {
c.forceUpdate();
});
}, 30*1000);
/**
* Render human readable time from the given date object
*
* @namespace components
* @class TimeAgo
* @constructor
* @param {Object} props
* @param {Date} props.date
*/
var TimeAgo = React.createClass({
propTypes: {
date: React.PropTypes.instanceOf(Date).isRequired,
},
componentDidMount: function() {
mounted.push(this);
},
componentWillUnmount: function() {
var i = mounted.indexOf(this);
if (i > -1) mounted.splice(i, 1);
},
/**
* Return true if the date given to this component is in future
*
* @method isInFuture
* @return {Boolean}
*/
isInFuture: function() {
return new Date().getTime() - this.props.date.getTime() < 0;
},
/**
* Return the date. If the date is in future just return the current time.
* Clock skews can put the date few seconds in the future which does not
* make any sense on timstamps. Future dates are considered as "now".
*
* @method getDate
* @return {Date}
*/
getDate: function() {
if (this.isInFuture()) return new Date();
return this.props.date;
},
render: function() {
var date = this.getDate();
var fromNow = moment(date).fromNow();
var formatted = moment(date).format("LLL");
return (
<OverlayTrigger placement="top" overlay={<Tooltip>{formatted}</Tooltip>}>
{this.transferPropsTo(<span className="TimeAgo" title={formatted}>{fromNow}</span>)}
</OverlayTrigger>
);
}
});
module.exports = TimeAgo;