]> cat aescling's git repositories - mastodon.git/blob - app/javascript/mastodon/components/relative_timestamp.js
Restore vanilla components
[mastodon.git] / app / javascript / mastodon / components / relative_timestamp.js
1 import React from 'react';
2 import { injectIntl, defineMessages } from 'react-intl';
3 import PropTypes from 'prop-types';
4
5 const messages = defineMessages({
6 just_now: { id: 'relative_time.just_now', defaultMessage: 'now' },
7 seconds: { id: 'relative_time.seconds', defaultMessage: '{number}s' },
8 minutes: { id: 'relative_time.minutes', defaultMessage: '{number}m' },
9 hours: { id: 'relative_time.hours', defaultMessage: '{number}h' },
10 days: { id: 'relative_time.days', defaultMessage: '{number}d' },
11 });
12
13 const dateFormatOptions = {
14 hour12: false,
15 year: 'numeric',
16 month: 'short',
17 day: '2-digit',
18 hour: '2-digit',
19 minute: '2-digit',
20 };
21
22 const shortDateFormatOptions = {
23 month: 'numeric',
24 day: 'numeric',
25 };
26
27 const SECOND = 1000;
28 const MINUTE = 1000 * 60;
29 const HOUR = 1000 * 60 * 60;
30 const DAY = 1000 * 60 * 60 * 24;
31
32 const MAX_DELAY = 2147483647;
33
34 const selectUnits = delta => {
35 const absDelta = Math.abs(delta);
36
37 if (absDelta < MINUTE) {
38 return 'second';
39 } else if (absDelta < HOUR) {
40 return 'minute';
41 } else if (absDelta < DAY) {
42 return 'hour';
43 }
44
45 return 'day';
46 };
47
48 const getUnitDelay = units => {
49 switch (units) {
50 case 'second':
51 return SECOND;
52 case 'minute':
53 return MINUTE;
54 case 'hour':
55 return HOUR;
56 case 'day':
57 return DAY;
58 default:
59 return MAX_DELAY;
60 }
61 };
62
63 @injectIntl
64 export default class RelativeTimestamp extends React.Component {
65
66 static propTypes = {
67 intl: PropTypes.object.isRequired,
68 timestamp: PropTypes.string.isRequired,
69 };
70
71 state = {
72 now: this.props.intl.now(),
73 };
74
75 shouldComponentUpdate (nextProps, nextState) {
76 // As of right now the locale doesn't change without a new page load,
77 // but we might as well check in case that ever changes.
78 return this.props.timestamp !== nextProps.timestamp ||
79 this.props.intl.locale !== nextProps.intl.locale ||
80 this.state.now !== nextState.now;
81 }
82
83 componentWillReceiveProps (nextProps) {
84 if (this.props.timestamp !== nextProps.timestamp) {
85 this.setState({ now: this.props.intl.now() });
86 }
87 }
88
89 componentDidMount () {
90 this._scheduleNextUpdate(this.props, this.state);
91 }
92
93 componentWillUpdate (nextProps, nextState) {
94 this._scheduleNextUpdate(nextProps, nextState);
95 }
96
97 componentWillUnmount () {
98 clearTimeout(this._timer);
99 }
100
101 _scheduleNextUpdate (props, state) {
102 clearTimeout(this._timer);
103
104 const { timestamp } = props;
105 const delta = (new Date(timestamp)).getTime() - state.now;
106 const unitDelay = getUnitDelay(selectUnits(delta));
107 const unitRemainder = Math.abs(delta % unitDelay);
108 const updateInterval = 1000 * 10;
109 const delay = delta < 0 ? Math.max(updateInterval, unitDelay - unitRemainder) : Math.max(updateInterval, unitRemainder);
110
111 this._timer = setTimeout(() => {
112 this.setState({ now: this.props.intl.now() });
113 }, delay);
114 }
115
116 render () {
117 const { timestamp, intl } = this.props;
118
119 const date = new Date(timestamp);
120 const delta = this.state.now - date.getTime();
121
122 let relativeTime;
123
124 if (delta < 10 * SECOND) {
125 relativeTime = intl.formatMessage(messages.just_now);
126 } else if (delta < 3 * DAY) {
127 if (delta < MINUTE) {
128 relativeTime = intl.formatMessage(messages.seconds, { number: Math.floor(delta / SECOND) });
129 } else if (delta < HOUR) {
130 relativeTime = intl.formatMessage(messages.minutes, { number: Math.floor(delta / MINUTE) });
131 } else if (delta < DAY) {
132 relativeTime = intl.formatMessage(messages.hours, { number: Math.floor(delta / HOUR) });
133 } else {
134 relativeTime = intl.formatMessage(messages.days, { number: Math.floor(delta / DAY) });
135 }
136 } else {
137 relativeTime = intl.formatDate(date, shortDateFormatOptions);
138 }
139
140 return (
141 <time dateTime={timestamp} title={intl.formatDate(date, dateFormatOptions)}>
142 {relativeTime}
143 </time>
144 );
145 }
146
147 }
This page took 0.104555 seconds and 4 git commands to generate.