FEATURE: Optionally show local time for user in card (#9527)

FEATURE: Optionally show local time for user in card (#9527)

This adds a site setting (default off) to optionally show a user’s local time and timezone in their user card. For example, I live in Brisbane, and if at 3:30PM my time I were to open a user who lives in California’s card I would see 22:30 (PST).

diff --git a/app/assets/javascripts/discourse/app/components/user-card-contents.js b/app/assets/javascripts/discourse/app/components/user-card-contents.js
index 655c97f..2feb813 100644
--- a/app/assets/javascripts/discourse/app/components/user-card-contents.js
+++ b/app/assets/javascripts/discourse/app/components/user-card-contents.js
@@ -38,7 +38,12 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
   showMoreBadges: gt("moreBadgesCount", 0),
   showDelete: and("viewingAdmin", "showName", "user.canBeDeleted"),
   linkWebsite: not("user.isBasic"),
-  hasLocationOrWebsite: or("user.location", "user.website_name"),
+
+  @discourseComputed("user")
+  hasLocaleOrWebsite(user) {
+    return user.location || user.website_name || this.userTimezone;
+  },
+
   isSuspendedOrHasBio: or("user.suspend_reason", "user.bio_excerpt"),
   showCheckEmail: and("user.staged", "canCheckEmails"),
 
@@ -52,6 +57,8 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
     "siteSettings.allow_featured_topic_on_user_profiles"
   ),
 
+  showUserLocalTime: setting("display_local_time_in_user_card"),
+
   @discourseComputed("user.staff")
   staff: isStaff => (isStaff ? "staff" : ""),
 
@@ -63,6 +70,17 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
     return prioritizeNameInUx(name, this.siteSettings);
   },
 
+  @discourseComputed("user")
+  userTimezone(user) {
+    return user.resolvedTimezone();
+  },
+
+  @discourseComputed()
+  formattedUserLocalTime() {
+    const timezone = this.userTimezone;
+    return moment.tz(timezone).format(I18n.t("dates.time_with_zone"));
+  },
+
   @discourseComputed("username")
   usernameClass: username => (username ? `user-card-${username}` : ""),
 
diff --git a/app/assets/javascripts/discourse/app/models/user.js b/app/assets/javascripts/discourse/app/models/user.js
index 9fff14f..dc118c0 100644
--- a/app/assets/javascripts/discourse/app/models/user.js
+++ b/app/assets/javascripts/discourse/app/models/user.js
@@ -597,6 +597,11 @@ const User = RestModel.extend({
         json.user.card_badge = Badge.create(json.user.card_badge);
       }
 
+      if (!json.user._timezone) {
+        json.user._timezone = json.user.timezone;
+        delete json.user.timezone;
+      }
+
       user.setProperties(json.user);
       return user;
     });
diff --git a/app/assets/javascripts/discourse/app/templates/components/user-card-contents.hbs b/app/assets/javascripts/discourse/app/templates/components/user-card-contents.hbs
index 3be60e8..3148fc9 100644
--- a/app/assets/javascripts/discourse/app/templates/components/user-card-contents.hbs
+++ b/app/assets/javascripts/discourse/app/templates/components/user-card-contents.hbs
@@ -149,15 +149,9 @@
         </div>
       {{/if}}
 
-      {{#if this.hasLocationOrWebsite}}
+      {{#if this.hasLocaleOrWebsite}}
         <div class="card-row">
           <div class="location-and-website">
-            {{#if this.user.location}}
-              <span class="location">
-                {{d-icon "map-marker-alt"}}
-                <span>{{this.user.location}}</span>
-              </span>
-            {{/if}}
             {{#if this.user.website_name}}
               <span class="website-name">
                 {{d-icon "globe"}}
@@ -170,6 +164,18 @@
                 {{/if}}
               </span>
             {{/if}}
+            {{#if this.user.location}}
+              <span class="location">
+                {{d-icon "map-marker-alt"}}
+                <span>{{this.user.location}}</span>
+              </span>
+            {{/if}}
+            {{#if showUserLocalTime}}
+              <span class="local-time">
+                {{d-icon "far-clock"}}
+                <span>{{this.formattedUserLocalTime}}</span>
+              </span>
+            {{/if}}
             {{plugin-outlet name="user-card-location-and-website" args=(hash user=this.user)}}
           </div>
         </div>
diff --git a/app/assets/stylesheets/common/components/user-card.scss b/app/assets/stylesheets/common/components/user-card.scss
index c5dad5d..92ca3a5 100644
--- a/app/assets/stylesheets/common/components/user-card.scss
+++ b/app/assets/stylesheets/common/components/user-card.scss
@@ -212,7 +212,9 @@ $avatar_margin: -50px; // negative margin makes avatars extend above cards
       @include ellipsis;
       color: $primary;
     }
-    .location {
+    .location,
+    .local-time,
+    .website-name {
       margin-right: 0.5em;
     }
     .website-name a {
diff --git a/app/serializers/user_card_serializer.rb b/app/serializers/user_card_serializer.rb
index 6b7f59c..c453dff 100644
--- a/app/serializers/user_card_serializer.rb
+++ b/app/serializers/user_card_serializer.rb
@@ -60,7 +60,8 @@ class UserCardSerializer < BasicUserSerializer
              :primary_group_flair_url,
              :primary_group_flair_bg_color,
              :primary_group_flair_color,
-             :featured_topic
+             :featured_topic,
+             :timezone
 
   untrusted_attributes :bio_excerpt,
                        :website,
@@ -194,6 +195,14 @@ class UserCardSerializer < BasicUserSerializer
     object.user_profile.featured_topic
   end
 
+  def include_timezone?
+    SiteSetting.display_local_time_in_user_card?
+  end
+
+  def timezone
+    object.user_option.timezone
+  end
+
   def card_background_upload_url
     object.card_background_upload&.url
   end
diff --git a/config/locales/client.ar.yml b/config/locales/client.ar.yml
index d2551f3..dd74199 100644
--- a/config/locales/client.ar.yml
+++ b/config/locales/client.ar.yml
@@ -31,6 +31,7 @@ ar:
         millions: "{{number}} مليون"
     dates:
       time: "h:mm a"
+      time_with_zone: "h:mm a (z)"
       time_short_day: "ddd, HH:mm"
       timeline_date: "MMM YYYY"
       long_no_year_no_time: "D MMM"
diff --git a/config/locales/client.be.yml b/config/locales/client.be.yml
index c9c33e1..67247ae 100644
--- a/config/locales/client.be.yml
+++ b/config/locales/client.be.yml
@@ -25,6 +25,7 @@ be:
         millions: "{{number}}M"
     dates:
       time: "HH:mm"
+      time_with_zone: "HH:mm (z)"
       long_no_year_no_time: "D MMM"
       long_with_year_no_time: "D МММ, YYYY"
       long_date_with_year_without_time: "D MMM YYYY"
diff --git a/config/locales/client.bg.yml b/config/locales/client.bg.yml
index 298f6fc..addc3fd 100644
--- a/config/locales/client.bg.yml
+++ b/config/locales/client.bg.yml
@@ -27,6 +27,7 @@ bg:
         millions: "{{number}}M "
     dates:
       time: "HH:mm"
+      time_with_zone: "HH:mm (z)"
       time_short_day: "ddd, HH:mm"
       timeline_date: "MMM YYYY"
       long_no_year_no_time: "D MMM"
diff --git a/config/locales/client.bs_BA.yml b/config/locales/client.bs_BA.yml
index e99e72d..93e103c 100644
--- a/config/locales/client.bs_BA.yml
+++ b/config/locales/client.bs_BA.yml
@@ -28,6 +28,7 @@ bs_BA:
         millions: "{{number}} miliona"
     dates:
       time: "HH: mm"
+      time_with_zone: "HH: mm (z)"
       timeline_date: "MMM YYYY"
       long_no_year_no_time: "MMM D"
       full_no_year_no_time: "MMMM Do"
diff --git a/config/locales/client.ca.yml b/config/locales/client.ca.yml
index d3c05e3..80f47fb 100644
--- a/config/locales/client.ca.yml
+++ b/config/locales/client.ca.yml
@@ -27,6 +27,7 @@ ca:
         millions: "{{number}}M"
     dates:
       time: "h:mm a"
+      time_with_zone: "h:mm (z)"
       timeline_date: "MMM YYYY"
       long_no_year_no_time: "MMM D"
       full_no_year_no_time: "MMMM Do"
diff --git a/config/locales/client.cs.yml b/config/locales/client.cs.yml
index 84c4b40..1faece6 100644
--- a/config/locales/client.cs.yml
+++ b/config/locales/client.cs.yml
@@ -29,6 +29,7 @@ cs:
         millions: "{{number}}M"
     dates:
       time: "H:mm"
+      time_with_zone: "H:mm (z)"
       timeline_date: "MMM YYYY"
       long_no_year_no_time: "D. MMMM"
       full_no_year_no_time: "D. MMMM"

[... diff too long, it was truncated ...]

GitHub sha: bb4e965a

1 Like

This commit appears in #9527 which was approved by eviltrout. It was merged by martin.

This commit has been mentioned on Discourse Meta. There might be relevant details there:

https://meta.discourse.org/t/over-zealous-hiding-of-plugin-outlet/153721/1