From 68497bddf252e4a04f563dac97ec9b295f5a0a0e Mon Sep 17 00:00:00 2001 From: Bianca Nenciu Date: Tue, 19 Apr 2022 20:48:08 +0300 Subject: [PATCH] UX: Add title to read time stats from user page (#16501) The title attributes were added to explain the difference between "read time" and "recent read time" stats from user summary page. --- .../discourse/app/controllers/user-summary.js | 18 +++++- .../discourse/app/lib/formatter.js | 9 ++- .../app/templates/components/user-stat.hbs | 2 +- .../discourse/app/templates/user/summary.hbs | 4 +- .../discourse/tests/acceptance/user-test.js | 61 +++++++++++++++++++ config/locales/client.en.yml | 2 + 6 files changed, 88 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/discourse/app/controllers/user-summary.js b/app/assets/javascripts/discourse/app/controllers/user-summary.js index 1f950989f45..4be0c43caa4 100644 --- a/app/assets/javascripts/discourse/app/controllers/user-summary.js +++ b/app/assets/javascripts/discourse/app/controllers/user-summary.js @@ -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; }, }); diff --git a/app/assets/javascripts/discourse/app/lib/formatter.js b/app/assets/javascripts/discourse/app/lib/formatter.js index b8d8e7509fb..8ffb9239208 100644 --- a/app/assets/javascripts/discourse/app/lib/formatter.js +++ b/app/assets/javascripts/discourse/app/lib/formatter.js @@ -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); diff --git a/app/assets/javascripts/discourse/app/templates/components/user-stat.hbs b/app/assets/javascripts/discourse/app/templates/components/user-stat.hbs index 68cb27dad90..ab2efc05719 100644 --- a/app/assets/javascripts/discourse/app/templates/components/user-stat.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/user-stat.hbs @@ -1,4 +1,4 @@ - + {{#if this.isNumber}} {{number @value}} {{else if this.isDuration}} diff --git a/app/assets/javascripts/discourse/app/templates/user/summary.hbs b/app/assets/javascripts/discourse/app/templates/user/summary.hbs index 2bdb0cdc1b1..6b3ff21fe7a 100644 --- a/app/assets/javascripts/discourse/app/templates/user/summary.hbs +++ b/app/assets/javascripts/discourse/app/templates/user/summary.hbs @@ -8,11 +8,11 @@ {{user-stat value=model.days_visited label="user.summary.days_visited"}}
  • - {{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"}}
  • {{#if showRecentTimeRead}}
  • - {{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"}}
  • {{/if}}
  • diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-test.js index 9d522d3d939..214229c25ca 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-test.js @@ -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) { diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 0b974911de6..61e12ed2bb3 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -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"