diff --git a/webapp/channels/package.json b/webapp/channels/package.json index 5156360006..d33b6e0d89 100644 --- a/webapp/channels/package.json +++ b/webapp/channels/package.json @@ -51,7 +51,7 @@ "localforage": "1.10.0", "localforage-observable": "2.1.1", "lodash": "4.17.21", - "luxon": "3.0.4", + "luxon": "3.3.0", "mark.js": "8.11.1", "marked": "github:mattermost/marked#2ef7f28cc7718e3f551c4ce9ea75fdd7580c2008", "memoize-one": "6.0.0", diff --git a/webapp/channels/src/components/profile_popover/profile_localtime.tsx b/webapp/channels/src/components/profile_popover/profile_localtime.tsx new file mode 100644 index 0000000000..dcb27a5ac9 --- /dev/null +++ b/webapp/channels/src/components/profile_popover/profile_localtime.tsx @@ -0,0 +1,99 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {DateTime, Duration} from 'luxon'; + +import {FormattedMessage} from 'react-intl'; + +import {UserTimezone} from '@mattermost/types/users'; +import Timestamp from 'components/timestamp'; +import {getUserCurrentTimezone} from 'mattermost-redux/utils/timezone_utils'; + +type ProfileTimezoneProps = { + profileUserTimezone?: UserTimezone; + currentUserTimezone: string | undefined; +} + +const returnTimeDiff = ( + currentUserTimezone: string | undefined | null, + profileUserTimezone: string, +) => { + if (!currentUserTimezone) { + return null; + } + const currentUserDate = DateTime.local().setZone(currentUserTimezone); + const profileUserDate = DateTime.local().setZone(profileUserTimezone); + + const offset = Duration.fromObject({ + hours: (profileUserDate.offset - currentUserDate.offset) / 60, + }); + + if (!offset.valueOf()) { + return undefined; + } + + const timeOffset = offset.toHuman({unitDisplay: 'short', signDisplay: 'never'}); + + return offset.valueOf() > 0 ? ( + + ) : ( + + ); +}; + +export const ProfileTimezone = ( + { + currentUserTimezone, + profileUserTimezone, + }: ProfileTimezoneProps, +) => { + const profileTimezone = getUserCurrentTimezone(profileUserTimezone) || 'UTC'; + const profileTimezoneShort = profileTimezone ? DateTime.now().setZone(profileTimezone).offsetNameShort : undefined; + + return ( +
+ + {profileTimezoneShort ? ( + + ) : ( + + )} + + + + + {' '} + {returnTimeDiff(currentUserTimezone, profileTimezone)} + + +
+ ); +}; diff --git a/webapp/channels/src/components/profile_popover/profile_popover.tsx b/webapp/channels/src/components/profile_popover/profile_popover.tsx index 44f860579f..286cf45bba 100644 --- a/webapp/channels/src/components/profile_popover/profile_popover.tsx +++ b/webapp/channels/src/components/profile_popover/profile_popover.tsx @@ -23,6 +23,8 @@ import {t} from 'utils/i18n'; import * as Utils from 'utils/utils'; import {shouldFocusMainTextbox} from 'utils/post_utils'; +import {ProfileTimezone} from './profile_localtime'; + import StatusIcon from 'components/status_icon'; import Timestamp from 'components/timestamp'; import UserSettingsModal from 'components/user_settings/modal'; @@ -574,27 +576,11 @@ class ProfilePopover extends React.PureComponent - - - - - , + />, ); } diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index 8d285dd78e..a22b676e6e 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -5255,7 +5255,10 @@ "user_groups_modal.viewGroup": "View Group", "user_list.notFound": "No users found", "user_profile.account.editProfile": "Edit Profile", + "user_profile.account.hoursAhead": "({timeOffset} ahead)", + "user_profile.account.hoursBehind": "({timeOffset} behind)", "user_profile.account.localTime": "Local Time", + "user_profile.account.localTimeWithTimezone": "Local Time ({timezone})", "user_profile.account.post_was_created": "This post was created by an integration from", "user_profile.add_user_to_channel": "Add to a Channel", "user_profile.add_user_to_channel.icon": "Add User to Channel Icon", diff --git a/webapp/package-lock.json b/webapp/package-lock.json index d4c2bb01ff..6cf657c836 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -3598,7 +3598,7 @@ "localforage": "1.10.0", "localforage-observable": "2.1.1", "lodash": "4.17.21", - "luxon": "3.0.4", + "luxon": "3.3.0", "mark.js": "8.11.1", "marked": "github:mattermost/marked#2ef7f28cc7718e3f551c4ce9ea75fdd7580c2008", "memoize-one": "6.0.0", @@ -24101,9 +24101,9 @@ } }, "node_modules/luxon": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", - "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz", + "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==", "engines": { "node": ">=12" } @@ -54303,9 +54303,9 @@ } }, "luxon": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", - "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz", + "integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==" }, "lz-string": { "version": "1.5.0", @@ -54521,7 +54521,7 @@ "localforage": "1.10.0", "localforage-observable": "2.1.1", "lodash": "4.17.21", - "luxon": "3.0.4", + "luxon": "3.3.0", "mark.js": "8.11.1", "marked": "github:mattermost/marked#2ef7f28cc7718e3f551c4ce9ea75fdd7580c2008", "memoize-one": "6.0.0",