chore: 🤖 create relative date helper (#1276)

* chore: 🤖 create relative date helper

Create a relative date helper that outputs "time" ago format.

✅ Closes: ICU-5847

* Update addons/core/addon/helpers/relative-datetime-live.js

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>

* refactor: 💡 refactor test for relative-date-helper

refactor test for relative-datetime-live helper

✅ Closes: ICU-5847

Co-authored-by: Zhihe Li <zhihe.li@hashicorp.com>
This commit is contained in:
Devon AndersonandZhihe Li authored and GitHub committed 2022-08-26 12:22:24 -04:00
1 parent 3130831ae0
commit a3517e53a8
9 files changed
+118 -147

No files matched your search

@@ -1 +0,0 @@
{{this.formatted}}
@@ -1,103 +0,0 @@
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
const MILLISECOND = 1;
const SECOND = MILLISECOND * 1000;
const MINUTE = SECOND * 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;
const MONTH = DAY * 31;
const YEAR = MONTH * 12;
// common time intervals in milliseconds
const unitMappings = [
{
unit: 'second',
value: SECOND,
},
{
unit: 'minute',
value: MINUTE,
},
{
unit: 'hour',
value: HOUR,
},
{
unit: 'day',
value: DAY,
},
{
unit: 'month',
value: MONTH,
},
{
unit: 'year',
value: YEAR,
},
];
export default class RelativeDatetimeLiveComponent extends Component {
// =services
@service clockTick;
@service intl;
// =properties
/**
* The difference in milliseconds between the date argument and the
* current time.
* @type {number}
*/
get delta() {
return this.args.date.valueOf() - this.clockTick.now;
}
/**
* The greatest meaningful unit is the unit which delta is equal to or
* greater than. For example, the unit of a delta equivalent of 59 seconds is
* 'second' while 60 seconds is 'minute', 36 hours is 'day', etc.
* @type {object}
*/
get greatestMeaningfulUnit() {
return unitMappings.reduce((currentValue, previousValue) => {
return Math.abs(this.delta) >= previousValue.value
? previousValue
: currentValue;
}, unitMappings[0]);
}
/**
* The delta value scaled to the greatest meaningful unit. For example, if
* the delta is 1000 ms, the scaled value is 1, which corresponds to
* a GMU of 'second'. A delta of 60000 ms is also 1, corresponding to a GMU
* of 'minute'.
* @type {number}
*/
get scaledDelta() {
if (this.delta < 0) {
return Math.ceil(this.delta / this.greatestMeaningfulUnit.value);
}
return Math.floor(this.delta / this.greatestMeaningfulUnit.value);
}
/**
* A string representation of the greatest meaningful unit.
* @type {string}
*/
get unit() {
return this.greatestMeaningfulUnit.unit;
}
/**
* A localizd relative datetime. E.g. "30 seconds ago".
* @type {string}
*/
get formatted() {
return this.intl.formatRelative(this.scaledDelta, {
unit: this.unit,
numeric: 'auto',
});
}
}
@@ -1,9 +1,9 @@
{{#if this.lastRefreshed}}
<Rose::Toolbar::Info>
<RelativeDatetimeLive @date={{this.lastRefreshed}} />
{{relative-datetime-live this.lastRefreshed}}
</Rose::Toolbar::Info>
{{/if}}
<LoadingButton @onClick={{this.onClick}}>
{{t 'actions.refresh'}}
</LoadingButton>
</LoadingButton>
@@ -0,0 +1,68 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
const MILLISECOND = 1;
const SECOND = MILLISECOND * 1000;
const MINUTE = SECOND * 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;
const MONTH = DAY * 31;
const YEAR = MONTH * 12;
const unitMappings = [
{
unit: 'second',
value: SECOND,
},
{
unit: 'minute',
value: MINUTE,
},
{
unit: 'hour',
value: HOUR,
},
{
unit: 'day',
value: DAY,
},
{
unit: 'month',
value: MONTH,
},
{
unit: 'year',
value: YEAR,
},
];
export default class extends Helper {
// =services
@service clockTick;
@service intl;
// =methods
compute([date]) {
const delta = date.valueOf() - this.clockTick.now;
console.log(delta);
const greatestMeaningfulUnit = unitMappings.reduce(
(currentValue, previousValue) => {
return Math.abs(delta) >= previousValue.value
? previousValue
: currentValue;
},
unitMappings[0]
);
const scaledDelta =
delta < 0
? Math.ceil(delta / greatestMeaningfulUnit.value)
: Math.floor(delta / greatestMeaningfulUnit.value);
const unit = greatestMeaningfulUnit.unit;
return this.intl.formatRelative(scaledDelta, {
unit,
numeric: 'auto',
});
}
}
@@ -1 +0,0 @@
export { default } from 'core/components/relative-datetime-live';
@@ -0,0 +1 @@
export { default } from 'core/helpers/relative-datetime-live';
@@ -1,3 +1,2 @@
<h2 id="title">Welcome to Ember</h2>
<RelativeDatetimeLive @date={{this.now}} />
<p>{{relative-datetime-live this.now}}</p>
@@ -1,38 +0,0 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | relative-datetime-live', function (hooks) {
setupRenderingTest(hooks);
test('it renders a relative datetime', async function (assert) {
assert.expect(6);
const now = Date.now();
this.date = now - 10 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 seconds ago');
this.date = now - 10 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 minutes ago');
this.date = now - 10 * 60 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 hours ago');
this.date = now - 10 * 24 * 60 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 days ago');
this.date = now - 10 * 31 * 24 * 60 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 months ago');
this.date = now - 10 * 12 * 31 * 24 * 60 * 60 * 1000;
await render(hbs`<RelativeDatetimeLive @date={{this.date}} />`);
assert.dom(this.element).hasText('10 years ago');
});
});
@@ -0,0 +1,46 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Helper | relative-datetime-live', function (hooks) {
setupRenderingTest(hooks);
test('it renders relative date in "time" ago format', async function (assert) {
assert.expect(8);
const now = Date.now();
this.date = now - 30 * 1000;
await render(hbs`{{relative-datetime-live this.date}}`);
assert.dom(this.element).hasText('30 seconds ago');
this.date = now - 30 * 60 * 1000;
await render(hbs`{{relative-datetime-live this.date}}`);
assert.dom(this.element).hasText('30 minutes ago');
this.date = now - 23 * 60 * 60 * 1000;
await render(hbs`{{relative-datetime-live this.date}}`);
assert.dom(this.element).hasText('23 hours ago');
this.date = now - 23 * 24 * 60 * 60 * 1000;
await render(hbs`{{relative-datetime-live this.date}}`);
assert.dom(this.element).hasText('23 days ago');
this.date = now - 8 * 31 * 24 * 60 * 60 * 1000;
await render(hbs`{{relative-datetime-live this.date}}`);
assert.dom(this.element).hasText('8 months ago');
this.date = now - 23 * 12 * 31 * 24 * 60 * 60 * 1000;
await render(hbs`{{relative-datetime-live this.date}}`);
assert.dom(this.element).hasText('23 years ago');
this.date = now + 8 * 31 * 24 * 60 * 60 * 1000;
await render(hbs`{{relative-datetime-live this.date}}`);
assert.dom(this.element).hasText('in 7 months');
this.date = now + 23 * 12 * 31 * 24 * 60 * 60 * 1000;
await render(hbs`{{relative-datetime-live this.date}}`);
assert.dom(this.element).hasText('in 22 years');
});
});