Move formatRelativeDate() to formatText util, add util tests
This commit is contained in:
@@ -2,26 +2,7 @@ import Component from '@glimmer/component';
|
|||||||
import { on } from '@ember/modifier';
|
import { on } from '@ember/modifier';
|
||||||
import { fn } from '@ember/helper';
|
import { fn } from '@ember/helper';
|
||||||
import or from 'ember-truth-helpers/helpers/or';
|
import or from 'ember-truth-helpers/helpers/or';
|
||||||
|
import formatRelativeDate from '../helpers/format-relative-date';
|
||||||
function formatRelativeDate(timestamp) {
|
|
||||||
if (!timestamp) return '';
|
|
||||||
const date = new Date(timestamp * 1000);
|
|
||||||
const now = new Date();
|
|
||||||
const diffMs = now - date;
|
|
||||||
const diffMin = Math.floor(diffMs / 60000);
|
|
||||||
const diffHr = Math.floor(diffMin / 60);
|
|
||||||
const diffDay = Math.floor(diffHr / 24);
|
|
||||||
|
|
||||||
if (diffMin < 1) return 'just now';
|
|
||||||
if (diffMin < 60) return `${diffMin} min ago`;
|
|
||||||
if (diffHr < 24) return `${diffHr} hr ago`;
|
|
||||||
if (diffDay < 7) return `${diffDay} day${diffDay === 1 ? '' : 's'} ago`;
|
|
||||||
return date.toLocaleDateString(undefined, {
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'short',
|
|
||||||
day: 'numeric',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class ContributionPhoto extends Component {
|
export default class ContributionPhoto extends Component {
|
||||||
get item() {
|
get item() {
|
||||||
@@ -44,10 +25,6 @@ export default class ContributionPhoto extends Component {
|
|||||||
return this.item?.placeNameLoading;
|
return this.item?.placeNameLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
get relativeDate() {
|
|
||||||
return formatRelativeDate(this.item?.createdAt);
|
|
||||||
}
|
|
||||||
|
|
||||||
get tags() {
|
get tags() {
|
||||||
// Collect unique tags across all photos in the contribution group
|
// Collect unique tags across all photos in the contribution group
|
||||||
const all = (this.item?.photos || []).flatMap((p) => p.tags || []);
|
const all = (this.item?.photos || []).flatMap((p) => p.tags || []);
|
||||||
@@ -86,7 +63,7 @@ export default class ContributionPhoto extends Component {
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="contribution-meta">
|
<div class="contribution-meta">
|
||||||
{{this.relativeDate}}
|
{{formatRelativeDate @item.createdAt}}
|
||||||
{{#if (gt this.item.photos.length 1)}}
|
{{#if (gt this.item.photos.length 1)}}
|
||||||
·
|
·
|
||||||
{{this.item.photos.length}}
|
{{this.item.photos.length}}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { helper } from '@ember/component/helper';
|
||||||
|
import { formatRelativeDate as format } from '../utils/format-text';
|
||||||
|
|
||||||
|
export default helper(function formatRelativeDate([timestamp]) {
|
||||||
|
return format(timestamp);
|
||||||
|
});
|
||||||
@@ -12,3 +12,23 @@ export function capitalize(text) {
|
|||||||
if (typeof text !== 'string' || !text) return '';
|
if (typeof text !== 'string' || !text) return '';
|
||||||
return text.charAt(0).toUpperCase() + text.slice(1);
|
return text.charAt(0).toUpperCase() + text.slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatRelativeDate(timestamp) {
|
||||||
|
if (!timestamp) return '';
|
||||||
|
const date = new Date(timestamp * 1000);
|
||||||
|
const now = new Date();
|
||||||
|
const diffMs = now - date;
|
||||||
|
const diffMin = Math.floor(diffMs / 60000);
|
||||||
|
const diffHr = Math.floor(diffMin / 60);
|
||||||
|
const diffDay = Math.floor(diffHr / 24);
|
||||||
|
|
||||||
|
if (diffMin < 1) return 'just now';
|
||||||
|
if (diffMin < 60) return `${diffMin} min ago`;
|
||||||
|
if (diffHr < 24) return `${diffHr} hr ago`;
|
||||||
|
if (diffDay < 7) return `${diffDay} day${diffDay === 1 ? '' : 's'} ago`;
|
||||||
|
return date.toLocaleDateString(undefined, {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { module, test } from 'qunit';
|
||||||
|
import {
|
||||||
|
formatRelativeDate,
|
||||||
|
humanizeOsmTag,
|
||||||
|
capitalize,
|
||||||
|
} from 'marco/utils/format-text';
|
||||||
|
|
||||||
|
module('Unit | Utility | format-text', function () {
|
||||||
|
test('humanizeOsmTag replaces underscores and dashes with spaces and title-cases', function (assert) {
|
||||||
|
assert.strictEqual(humanizeOsmTag('atm'), 'Atm');
|
||||||
|
assert.strictEqual(humanizeOsmTag('fast_food'), 'Fast Food');
|
||||||
|
assert.strictEqual(humanizeOsmTag('phone-repair'), 'Phone Repair');
|
||||||
|
assert.strictEqual(humanizeOsmTag(''), '');
|
||||||
|
assert.strictEqual(humanizeOsmTag(null), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('capitalize uppercases the first letter', function (assert) {
|
||||||
|
assert.strictEqual(capitalize('hello'), 'Hello');
|
||||||
|
assert.strictEqual(capitalize(''), '');
|
||||||
|
assert.strictEqual(capitalize(null), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('formatRelativeDate returns empty string for falsy timestamp', function (assert) {
|
||||||
|
assert.strictEqual(formatRelativeDate(null), '');
|
||||||
|
assert.strictEqual(formatRelativeDate(0), '');
|
||||||
|
assert.strictEqual(formatRelativeDate(undefined), '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('formatRelativeDate returns "just now" for timestamps within the last minute', function (assert) {
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
assert.strictEqual(formatRelativeDate(now), 'just now');
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 10), 'just now');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('formatRelativeDate returns "min ago" for timestamps within the last hour', function (assert) {
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 60), '1 min ago');
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 300), '5 min ago');
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 3599), '59 min ago');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('formatRelativeDate returns "hr ago" for timestamps within the last day', function (assert) {
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 3600), '1 hr ago');
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 7200), '2 hr ago');
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 86399), '23 hr ago');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('formatRelativeDate returns "day(s) ago" for timestamps within the last week', function (assert) {
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 86400), '1 day ago');
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 86400 * 2), '2 days ago');
|
||||||
|
assert.strictEqual(formatRelativeDate(now - 86400 * 6), '6 days ago');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('formatRelativeDate returns an absolute date for timestamps older than a week', function (assert) {
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
const oldTimestamp = now - 86400 * 30; // 30 days ago
|
||||||
|
const result = formatRelativeDate(oldTimestamp);
|
||||||
|
// The exact format depends on the locale, but it should contain a year
|
||||||
|
assert.ok(
|
||||||
|
result.includes(String(new Date().getFullYear())),
|
||||||
|
'Contains the year'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user