From ee4490654f21c3bf598985b6e89bb509340c51df Mon Sep 17 00:00:00 2001 From: Douglas Fabris <devfabris@gmail.com> Date: Thu, 16 Feb 2023 00:18:25 -0300 Subject: [PATCH] Chore: Refactor useThemeMode in favor of userPreferences (#28063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Júlia Jaeger Foresti <60678893+juliajforesti@users.noreply.github.com> --- .../meteor/app/lib/server/startup/settings.ts | 19 +++++++++++++++++ .../client/sidebar/header/UserDropdown.tsx | 6 +++--- .../preferences/PreferencesGlobalSection.tsx | 21 ++++++++++++++++--- .../rocketchat-i18n/i18n/en.i18n.json | 3 ++- .../ui-theming/src/hooks/useThemeMode.ts | 14 +++++++++---- .../v1/users/UsersSetPreferenceParamsPOST.ts | 5 +++++ .../methods/saveUserPreferences.ts | 1 + 7 files changed, 58 insertions(+), 11 deletions(-) diff --git a/apps/meteor/app/lib/server/startup/settings.ts b/apps/meteor/app/lib/server/startup/settings.ts index e8419471040..364c31741a8 100644 --- a/apps/meteor/app/lib/server/startup/settings.ts +++ b/apps/meteor/app/lib/server/startup/settings.ts @@ -375,6 +375,25 @@ settingsRegistry.addGroup('Accounts', function () { public: true, i18nLabel: 'Group_by_Type', }); + this.add('Accounts_Default_User_Preferences_themeAppearence', 'auto', { + type: 'select', + values: [ + { + key: 'auto', + i18nLabel: 'Theme_match_system', + }, + { + key: 'light', + i18nLabel: 'Theme_light', + }, + { + key: 'dark', + i18nLabel: 'Theme_dark', + }, + ], + public: true, + i18nLabel: 'Theme_Appearence', + }); this.add('Accounts_Default_User_Preferences_sidebarViewMode', 'medium', { type: 'select', values: [ diff --git a/apps/meteor/client/sidebar/header/UserDropdown.tsx b/apps/meteor/client/sidebar/header/UserDropdown.tsx index 6bb57cdccfc..ce74cf4945e 100644 --- a/apps/meteor/client/sidebar/header/UserDropdown.tsx +++ b/apps/meteor/client/sidebar/header/UserDropdown.tsx @@ -192,21 +192,21 @@ const UserDropdown = ({ user, onClose }: UserDropdownProps): ReactElement => { <OptionIcon name='sun' /> <OptionContent>{t('Theme_light')}</OptionContent> <OptionColumn> - <RadioButton checked={selectedTheme === 'light'} onChange={(): void => setTheme('light')} m='x4' /> + <RadioButton checked={selectedTheme === 'light'} onChange={setTheme('light')} m='x4' /> </OptionColumn> </Option> <Option> <OptionIcon name='moon' /> <OptionContent>{t('Theme_dark')}</OptionContent> <OptionColumn> - <RadioButton checked={selectedTheme === 'dark'} onChange={(): void => setTheme('dark')} m='x4' /> + <RadioButton checked={selectedTheme === 'dark'} onChange={setTheme('dark')} m='x4' /> </OptionColumn> </Option> <Option> <OptionIcon name='desktop' /> <OptionContent>{t('Theme_match_system')}</OptionContent> <OptionColumn> - <RadioButton checked={selectedTheme === 'auto'} onChange={(): void => setTheme('auto')} m='x4' /> + <RadioButton checked={selectedTheme === 'auto'} onChange={setTheme('auto')} m='x4' /> </OptionColumn> </Option> <OptionDivider /> diff --git a/apps/meteor/client/views/account/preferences/PreferencesGlobalSection.tsx b/apps/meteor/client/views/account/preferences/PreferencesGlobalSection.tsx index 7c2410deb9f..edc7e64b9dc 100644 --- a/apps/meteor/client/views/account/preferences/PreferencesGlobalSection.tsx +++ b/apps/meteor/client/views/account/preferences/PreferencesGlobalSection.tsx @@ -1,5 +1,5 @@ import type { SelectOption } from '@rocket.chat/fuselage'; -import { Accordion, Field, FieldGroup, MultiSelect } from '@rocket.chat/fuselage'; +import { Select, Accordion, Field, FieldGroup, MultiSelect } from '@rocket.chat/fuselage'; import { useUserPreference, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React, { useMemo } from 'react'; @@ -11,6 +11,7 @@ const PreferencesGlobalSection = ({ onChange, commitRef, ...props }: FormSection const t = useTranslation(); const userDontAskAgainList = useUserPreference<{ action: string; label: string }[]>('dontAskAgainList'); + const themePreference = useUserPreference<'light' | 'dark' | 'auto'>('themeAppearence'); const options = useMemo( () => (userDontAskAgainList || []).map(({ action, label }) => [action, label]) as SelectOption[], @@ -22,18 +23,26 @@ const PreferencesGlobalSection = ({ onChange, commitRef, ...props }: FormSection const { values, handlers, commit } = useForm( { dontAskAgainList: selectedOptions, + themeAppearence: themePreference, }, onChange, ); - const { dontAskAgainList } = values as { + const { dontAskAgainList, themeAppearence } = values as { dontAskAgainList: string[]; + themeAppearence: string; }; - const { handleDontAskAgainList } = handlers; + const { handleDontAskAgainList, handleThemeAppearence } = handlers; commitRef.current.global = commit; + const themeOptions: SelectOption[] = [ + ['auto', t('Theme_match_system')], + ['light', t('Theme_light')], + ['dark', t('Theme_dark')], + ]; + return ( <Accordion.Item title={t('Global')} {...props}> <FieldGroup> @@ -48,6 +57,12 @@ const PreferencesGlobalSection = ({ onChange, commitRef, ...props }: FormSection /> </Field.Row> </Field> + <Field> + <Field.Label>{t('Theme_Appearence')}</Field.Label> + <Field.Row> + <Select value={themeAppearence} onChange={handleThemeAppearence} options={themeOptions} /> + </Field.Row> + </Field> </FieldGroup> </Accordion.Item> ); diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index c076a28648f..4dbffde6b8b 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -5643,5 +5643,6 @@ "cloud.RegisterWorkspace_Token_Step_One": "1. Go to: <1>cloud.rocket.chat > Workspaces</1> and click <3>'Register self-managed'</3>.", "cloud.RegisterWorkspace_Setup_Terms_Privacy": "I agree with <1>Terms and Conditions</1> and <3>Privacy Policy</3>", "Larger_amounts_of_active_connections": "For larger amounts of active connections you can consider our", - "multiple_instance_solutions": "multiple instance solutions" + "multiple_instance_solutions": "multiple instance solutions", + "Theme_Appearence": "Theme Appearence" } diff --git a/ee/packages/ui-theming/src/hooks/useThemeMode.ts b/ee/packages/ui-theming/src/hooks/useThemeMode.ts index ff1c47a5f52..84deebb2837 100644 --- a/ee/packages/ui-theming/src/hooks/useThemeMode.ts +++ b/ee/packages/ui-theming/src/hooks/useThemeMode.ts @@ -1,5 +1,6 @@ -import { useDarkMode, useSessionStorage } from '@rocket.chat/fuselage-hooks'; -import type { Dispatch, SetStateAction } from 'react'; +import { useDarkMode } from '@rocket.chat/fuselage-hooks'; +import { useEndpoint, useUserPreference } from '@rocket.chat/ui-contexts'; +import { useCallback } from 'react'; type ThemeMode = 'light' | 'dark' | 'auto'; @@ -9,8 +10,13 @@ type ThemeMode = 'light' | 'dark' | 'auto'; * @returns [currentThemeMode, setThemeMode, resolvedThemeMode] */ -export const useThemeMode = (value: ThemeMode = 'auto'): [ThemeMode, Dispatch<SetStateAction<ThemeMode>>, 'light' | 'dark'] => { - const [theme, setTheme] = useSessionStorage<ThemeMode>(`rcx-theme`, value); +export const useThemeMode = (): [ThemeMode, (value: ThemeMode) => () => void, 'light' | 'dark'] => { + const theme = useUserPreference<ThemeMode>('themeAppearence') || 'auto'; + + const saveUserPreferences = useEndpoint('POST', '/v1/users.setPreferences'); + + const setTheme = (value: ThemeMode): (() => void) => + useCallback(() => saveUserPreferences({ data: { themeAppearence: value } }), [value]); return [theme, setTheme, useDarkMode(theme === 'auto' ? undefined : theme === 'dark') ? 'dark' : 'light']; }; diff --git a/packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts b/packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts index d3082d5c678..5a07797dc80 100644 --- a/packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts +++ b/packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts @@ -38,6 +38,7 @@ export type UsersSetPreferencesParamsPOST = { sidebarGroupByType?: boolean; muteFocusedConversations?: boolean; dontAskAgainList?: Array<{ action: string; label: string }>; + themeAppearence?: 'auto' | 'light' | 'dark'; receiveLoginDetectionEmail?: boolean; idleTimeLimit?: number; omnichannelTranscriptEmail?: boolean; @@ -190,6 +191,10 @@ const UsersSetPreferencesParamsPostSchema = { }, nullable: true, }, + themeAppearence: { + type: 'string', + nullable: true, + }, receiveLoginDetectionEmail: { type: 'boolean', nullable: true, diff --git a/packages/ui-contexts/src/ServerContext/methods/saveUserPreferences.ts b/packages/ui-contexts/src/ServerContext/methods/saveUserPreferences.ts index 6b455f74f83..ae1df52b409 100644 --- a/packages/ui-contexts/src/ServerContext/methods/saveUserPreferences.ts +++ b/packages/ui-contexts/src/ServerContext/methods/saveUserPreferences.ts @@ -29,6 +29,7 @@ type UserPreferences = { sidebarGroupByType: boolean; muteFocusedConversations: boolean; dontAskAgainList: { action: string; label: string }[]; + themeAppearence: 'auto' | 'light' | 'dark'; receiveLoginDetectionEmail: boolean; }; -- GitLab