UX: Add title to read time stats from user page ()

The title attributes were added to explain the difference between "read
time" and "recent read time" stats from user summary page.
This commit is contained in:
Bianca Nenciu 2022-04-19 20:48:08 +03:00 committed by GitHub
parent f55edd54fd
commit 68497bddf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 8 deletions
app/assets/javascripts/discourse
app
controllers
lib
templates
tests/acceptance
config/locales

@ -1,7 +1,7 @@
import Controller, { inject as controller } from "@ember/controller";
import { alias } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators";
import { durationTiny } from "discourse/lib/formatter";
import { duration } from "discourse/lib/formatter";
// should be kept in sync with 'UserSummary::MAX_BADGES'
const MAX_BADGES = 6;
@ -17,7 +17,12 @@ export default Controller.extend({
@discourseComputed("model.time_read")
timeRead(timeReadSeconds) {
return durationTiny(timeReadSeconds);
return duration(timeReadSeconds, { format: "tiny" });
},
@discourseComputed("model.time_read")
timeReadMedium(timeReadSeconds) {
return duration(timeReadSeconds, { format: "medium" });
},
@discourseComputed("model.time_read", "model.recent_time_read")
@ -28,7 +33,14 @@ export default Controller.extend({
@discourseComputed("model.recent_time_read")
recentTimeRead(recentTimeReadSeconds) {
return recentTimeReadSeconds > 0
? durationTiny(recentTimeReadSeconds)
? duration(recentTimeReadSeconds, { format: "tiny" })
: null;
},
@discourseComputed("model.recent_time_read")
recentTimeReadMedium(recentTimeReadSeconds) {
return recentTimeReadSeconds > 0
? duration(recentTimeReadSeconds, { format: "medium" })
: null;
},
});

@ -122,7 +122,7 @@ function wrapOn(dateStr) {
return I18n.t("dates.wrap_on", { date: dateStr });
}
export function durationTiny(distance, ageOpts) {
export function duration(distance, ageOpts) {
if (typeof distance !== "number") {
return "—";
}
@ -131,7 +131,8 @@ export function durationTiny(distance, ageOpts) {
const distanceInMinutes = dividedDistance < 1 ? 1 : dividedDistance;
const t = function (key, opts) {
const result = I18n.t("dates.tiny." + key, opts);
const format = (ageOpts && ageOpts.format) || "tiny";
const result = I18n.t("dates." + format + "." + key, opts);
return ageOpts && ageOpts.addAgo ? wrapAgo(result) : result;
};
@ -182,6 +183,10 @@ export function durationTiny(distance, ageOpts) {
return formatted;
}
export function durationTiny(distance, ageOpts) {
return duration(distance, Object.assign({ format: "tiny" }, ageOpts));
}
function relativeAgeTiny(date, ageOpts) {
const format = "tiny";
let distance = Math.round((new Date() - date) / 1000);

@ -1,4 +1,4 @@
<span class="value">
<span class="value" title={{this.rawTitle}}>
{{#if this.isNumber}}
{{number @value}}
{{else if this.isDuration}}

@ -8,11 +8,11 @@
{{user-stat value=model.days_visited label="user.summary.days_visited"}}
</li>
<li class="stats-time-read">
{{user-stat value=timeRead label="user.summary.time_read" type="string"}}
{{user-stat value=timeRead label="user.summary.time_read" rawTitle=(i18n "user.summary.time_read_title" duration=timeReadMedium) type="string"}}
</li>
{{#if showRecentTimeRead}}
<li class="stats-recent-read">
{{user-stat value=recentTimeRead label="user.summary.recent_time_read" type="string"}}
{{user-stat value=recentTimeRead label="user.summary.recent_time_read" rawTitle=(i18n "user.summary.recent_time_read_title" duration=recentTimeReadMedium) type="string"}}
</li>
{{/if}}
<li class="stats-topics-entered">

@ -13,6 +13,7 @@ import {
import { click, currentRouteName, visit } from "@ember/test-helpers";
import { cloneJSON } from "discourse-common/lib/object";
import { test } from "qunit";
import I18n from "I18n";
acceptance("User Routes", function (needs) {
needs.user();
@ -115,6 +116,66 @@ acceptance("User Routes", function (needs) {
});
});
acceptance("User Summary - Stats", function (needs) {
needs.pretender((server, helper) => {
server.get("/u/eviltrout/summary.json", () => {
return helper.response(200, {
user_summary: {
likes_given: 1,
likes_received: 2,
topics_entered: 3,
posts_read_count: 4,
days_visited: 5,
topic_count: 6,
post_count: 7,
time_read: 100000,
recent_time_read: 1000,
bookmark_count: 0,
can_see_summary_stats: true,
topic_ids: [1234],
replies: [{ topic_id: 1234 }],
links: [{ topic_id: 1234, url: "https://eviltrout.com" }],
most_replied_to_users: [{ id: 333 }],
most_liked_by_users: [{ id: 333 }],
most_liked_users: [{ id: 333 }],
badges: [{ badge_id: 444 }],
top_categories: [
{
id: 1,
name: "bug",
color: "e9dd00",
text_color: "000000",
slug: "bug",
read_restricted: false,
parent_category_id: null,
topic_count: 1,
post_count: 1,
},
],
},
badges: [{ id: 444, count: 1 }],
topics: [{ id: 1234, title: "cool title", slug: "cool-title" }],
});
});
});
test("Summary Read Times", async function (assert) {
await visit("/u/eviltrout/summary");
assert.equal(query(".stats-time-read span").textContent.trim(), "1d");
assert.equal(
query(".stats-time-read span").title,
I18n.t("user.summary.time_read_title", { duration: "1 day" })
);
assert.equal(query(".stats-recent-read span").textContent.trim(), "17m");
assert.equal(
query(".stats-recent-read span").title,
I18n.t("user.summary.recent_time_read_title", { duration: "17 mins" })
);
});
});
acceptance(
"User Routes - Periods in current user's username",
function (needs) {

@ -1681,7 +1681,9 @@ en:
title: "Summary"
stats: "Stats"
time_read: "read time"
time_read_title: "%{duration} (all time)"
recent_time_read: "recent read time"
recent_time_read_title: "%{duration} (in the last 60 days)"
topic_count:
one: "topic created"
other: "topics created"