From c01e9f791f8f37b7df107e461b0aeaa960e0a89f Mon Sep 17 00:00:00 2001 From: Matthew Birtch Date: Wed, 21 Jan 2026 16:43:33 -0500 Subject: [PATCH 1/2] [MM-67189] loading screen fixes - move measureAndReport, reduce minimum time, fix z-index issue (#34947) * move measureAndReport out of setTimeOut and reduce minimum time * fix z-index issue where system console header shows on top --------- Co-authored-by: Mattermost Build --- .../initial_loading_screen.css | 8 +++---- .../initial_loading_screen_class.ts | 21 ++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/webapp/channels/src/components/initial_loading_screen/initial_loading_screen.css b/webapp/channels/src/components/initial_loading_screen/initial_loading_screen.css index 7f6ac955e57..030f2ffb043 100644 --- a/webapp/channels/src/components/initial_loading_screen/initial_loading_screen.css +++ b/webapp/channels/src/components/initial_loading_screen/initial_loading_screen.css @@ -13,7 +13,7 @@ body { --gradient-center-color: #FFF; --gradient-edge-color: rgba(255, 255, 255, 0); position: absolute; - z-index: 100; + z-index: 1000; top: 0px; bottom: 0px; display: flex; @@ -68,9 +68,9 @@ body { .LoadingAnimation { --fade-duration: 150ms; --colour: #1E325C; - --animation-initial-delay: 750ms; - --animation-start-duration: 750ms; - --animation-end-duration: 600ms; + --animation-initial-delay: 50ms; + --animation-start-duration: 400ms; + --animation-end-duration: 500ms; --animation-spinner-speed: 500ms; --animation-spinner-mask-stroke-length: 169.6; --ease-in-cubic: cubic-bezier(0.32, 0, 0.67, 0); diff --git a/webapp/channels/src/components/initial_loading_screen/initial_loading_screen_class.ts b/webapp/channels/src/components/initial_loading_screen/initial_loading_screen_class.ts index b437776e55b..c5c52565b02 100644 --- a/webapp/channels/src/components/initial_loading_screen/initial_loading_screen_class.ts +++ b/webapp/channels/src/components/initial_loading_screen/initial_loading_screen_class.ts @@ -8,7 +8,7 @@ const ANIMATION_CLASS_FOR_MATTERMOST_LOGO_HIDE = 'LoadingAnimation__compass-shri const ANIMATION_CLASS_FOR_COMPLETE_LOADER_HIDE = 'LoadingAnimation__shrink'; const DESTROY_DELAY_AFTER_ANIMATION_END = 1000; -const MINIMUM_LOADING_TIME = 2000; // Minimum time to show the loading screen (in ms) +const MINIMUM_LOADING_TIME = 1000; // Minimum time to show the loading screen (in ms) const LOADING_CLASS_FOR_SCREEN = 'LoadingScreen'; const LOADING_COMPLETE_CLASS_FOR_SCREEN = 'LoadingScreen LoadingScreen--loaded'; @@ -123,6 +123,16 @@ export class InitialLoadingScreenClass { return; } + // Measure the actual load time before any artificial delays + measureAndReport({ + name: Measure.SplashScreen, + startMark: 0, + canFail: false, + labels: { + page_type: pageType, + }, + }); + // Calculate how long the loading screen has been visible const elapsedTime = this.startTime ? Date.now() - this.startTime : 0; const remainingTime = Math.max(0, MINIMUM_LOADING_TIME - elapsedTime); @@ -137,15 +147,6 @@ export class InitialLoadingScreenClass { this.loadingScreenElement.className = LOADING_COMPLETE_CLASS_FOR_SCREEN; this.loadingAnimationElement.className = LOADING_COMPLETE_CLASS_FOR_ANIMATION; - - measureAndReport({ - name: Measure.SplashScreen, - startMark: 0, - canFail: false, - labels: { - page_type: pageType, - }, - }); }, remainingTime); } } From fcd3ebcb314960cb176a10b57b0b306cdc32690a Mon Sep 17 00:00:00 2001 From: boristrbrt <97885032+Boruus@users.noreply.github.com> Date: Thu, 22 Jan 2026 00:24:59 +0100 Subject: [PATCH 2/2] =?UTF-8?q?fix(scheduled):=20enhance=20timezone=20form?= =?UTF-8?q?atting=20by=20incorporating=20user=20loc=E2=80=A6=20(#34305)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(scheduled): enhance timezone formatting by incorporating user locale in scheduled time display * fix: lint issue * fix: add jsdocs and unit test --- .../core_menu_options.test.tsx | 32 +++++++++++++++++++ .../send_post_options/core_menu_options.tsx | 23 +++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.test.tsx b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.test.tsx index 2352686a460..63658edd521 100644 --- a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.test.tsx +++ b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.test.tsx @@ -179,4 +179,36 @@ describe('CoreMenuOptions Component', () => { // Check the trailing element is NOT rendered in the component as this is a bot expect(screen.queryByText(/John Doe/)).toBeNull(); }); + + it('should format teammate time according to user locale', () => { + setMockDate(2); // Tuesday + + const stateWithFrenchLocale = { + ...initialState, + entities: { + ...initialState.entities, + users: { + ...initialState.entities.users, + profiles: { + currentUserId: { + locale: 'fr', + }, + }, + }, + }, + }; + + mockedUseTimePostBoxIndicator.mockReturnValue({ + ...defaultUseTimePostBoxIndicatorReturnValue, + isDM: true, + isSelfDM: false, + isBot: false, + }); + + renderComponent(stateWithFrenchLocale); + + // Verify French format (no AM/PM) + const timeTexts = screen.getAllByText(/\d{2}:\d{2}(?!\s*[AP]M)/); + expect(timeTexts.length).toBeGreaterThan(0); + }); }); diff --git a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.tsx b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.tsx index 95f869bb531..d55e5e7409d 100644 --- a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.tsx +++ b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.tsx @@ -4,6 +4,9 @@ import {DateTime} from 'luxon'; import React, {memo, useCallback} from 'react'; import {FormattedMessage} from 'react-intl'; +import {useSelector} from 'react-redux'; + +import {getCurrentLocale} from 'selectors/i18n'; import useTimePostBoxIndicator from 'components/advanced_text_editor/use_post_box_indicator'; import * as Menu from 'components/menu'; @@ -17,10 +20,23 @@ type Props = { channelId: string; } -function getScheduledTimeInTeammateTimezone(userCurrentTimestamp: number, teammateTimezoneString: string): string { +/** + * Formats a timestamp in the teammate's timezone using the current user's locale. + * @param userCurrentTimestamp - Timestamp in milliseconds (UTC) + * @param teammateTimezoneString - IANA timezone string (e.g., "America/New_York") + * @param userLocale - User's locale code (e.g., "fr", "en", "de") + * @returns Formatted time string respecting the user's locale + * @example + * // US locale: "8:00 AM" + * // French locale: "08:00" + * getScheduledTimeInTeammateTimezone(1635768000000, 'Europe/Paris', 'fr') + */ +function getScheduledTimeInTeammateTimezone(userCurrentTimestamp: number, teammateTimezoneString: string, userLocale: string): string { const scheduledTimeUTC = DateTime.fromMillis(userCurrentTimestamp, {zone: 'utc'}); const teammateScheduledTime = scheduledTimeUTC.setZone(teammateTimezoneString); - const formattedTime = teammateScheduledTime.toFormat('h:mm a'); + const formattedTime = teammateScheduledTime. + setLocale(userLocale). + toLocaleString(DateTime.TIME_SIMPLE); return formattedTime; } @@ -41,6 +57,7 @@ function CoreMenuOptions({handleOnSelect, channelId}: Props) { isBot, } = useTimePostBoxIndicator(channelId); + const locale = useSelector(getCurrentLocale); const now = DateTime.now().setZone(userCurrentTimezone); const tomorrow9amTime = DateTime.now(). setZone(userCurrentTimezone). @@ -66,7 +83,7 @@ function CoreMenuOptions({handleOnSelect, channelId}: Props) { if (isDM && !isBot && !isSelfDM) { const teammateTimezoneString = teammateTimezone.useAutomaticTimezone ? teammateTimezone.automaticTimezone : teammateTimezone.manualTimezone || 'UTC'; - const scheduledTimeInTeammateTimezone = getScheduledTimeInTeammateTimezone(tomorrow9amTime, teammateTimezoneString); + const scheduledTimeInTeammateTimezone = getScheduledTimeInTeammateTimezone(tomorrow9amTime, teammateTimezoneString, locale); const teammateTimeDisplay = (