diff --git a/client/src/components/AccountSettings/ManageAccount.tsx b/client/src/components/AccountSettings/ManageAccount.tsx index cc941df7b067ac78f18c2b02f21fc591defdaf1d..cfd7a65075cad74f740056d90771ea920b3fcb0f 100644 --- a/client/src/components/AccountSettings/ManageAccount.tsx +++ b/client/src/components/AccountSettings/ManageAccount.tsx @@ -18,11 +18,13 @@ import Grid from '@mui/material/Grid'; import Typography from '@mui/material/Typography'; +import { useTranslation } from 'react-i18next'; import { useAuthContext } from '../../contexts/AuthProvider'; import JamiIdCard from '../JamiIdCard'; function ManageAccount() { + const { t } = useTranslation(); const { account } = useAuthContext(); const devices: string[][] = []; @@ -32,12 +34,11 @@ function ManageAccount() { console.log(devices); const isJamiAccount = account.getType() === 'RING'; - const alias = isJamiAccount ? 'Jami account' : 'SIP account'; return ( <> <Typography variant="h2" component="h2" gutterBottom> - {alias} + {t('jami_account')} </Typography> <Grid container spacing={3} style={{ marginBottom: 16 }}> {isJamiAccount && ( diff --git a/client/src/components/GeneralSettings/Appearance.tsx b/client/src/components/GeneralSettings/Appearance.tsx new file mode 100644 index 0000000000000000000000000000000000000000..71d6aebcd8cd26a31f711738ae3908452d429705 --- /dev/null +++ b/client/src/components/GeneralSettings/Appearance.tsx @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 Savoir-faire Linux Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see + * <https://www.gnu.org/licenses/>. + */ + +import { useContext } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { CustomThemeContext } from '../../contexts/CustomThemeProvider'; +import { SettingsGroup, SettingSwitch } from '../Settings'; +function Appearance() { + const { t } = useTranslation(); + return ( + <SettingsGroup label={t('settings_theme')}> + <SettingTheme /> + </SettingsGroup> + ); +} + +const SettingTheme = () => { + const { t } = useTranslation(); + + const { mode, toggleMode } = useContext(CustomThemeContext); + + return <SettingSwitch label={t('settings_dark_theme')} onChange={toggleMode} checked={mode === 'dark'} />; +}; + +export default Appearance; diff --git a/client/src/components/GeneralSettings/System.tsx b/client/src/components/GeneralSettings/System.tsx new file mode 100644 index 0000000000000000000000000000000000000000..02ecbf56d5b1eed9edb04292d4e8c150d0d1e521 --- /dev/null +++ b/client/src/components/GeneralSettings/System.tsx @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 Savoir-faire Linux Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see + * <https://www.gnu.org/licenses/>. + */ +import { useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { languagesInfos, LanguageTag } from '../../i18n'; +import { SettingSelect, SettingSelectProps, SettingsGroup, SettingSwitch } from '../Settings'; + +function System() { + const { t } = useTranslation(); + return ( + <SettingsGroup label={t('settings_title_system')}> + <SettingLanguage /> + <SettingLinkPreview /> + </SettingsGroup> + ); +} + +const settingLanguageOptions = languagesInfos.map(({ tag, fullName }) => ({ + label: fullName, + payload: tag, +})); + +const SettingLanguage = () => { + const { t, i18n } = useTranslation(); + + const option = useMemo( + // TODO: Tell Typescript the result can't be undefined + () => settingLanguageOptions.find((option) => option.payload === i18n.language), + [i18n.language] + ); + + const onChange = useCallback<SettingSelectProps<LanguageTag>['onChange']>( + (newValue) => { + if (newValue) { + i18n.changeLanguage(newValue.payload); + } + }, + [i18n] + ); + + return ( + <SettingSelect + label={t('settings_language')} + option={option} + options={settingLanguageOptions} + onChange={onChange} + /> + ); +}; + +const SettingLinkPreview = () => { + const { t } = useTranslation(); + + const [isOn, setIsOn] = useState<boolean>(true); + + return <SettingSwitch label={t('settings_link_preview')} onChange={() => setIsOn((isOn) => !isOn)} checked={isOn} />; +}; + +export default System; diff --git a/client/src/components/Header.tsx b/client/src/components/Header.tsx index 496330946442a78963a7eb16468bd0ad76897721..46c0457d30b9322643b83415dd88313b4f069b6b 100644 --- a/client/src/components/Header.tsx +++ b/client/src/components/Header.tsx @@ -22,8 +22,8 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { useAuthContext } from '../contexts/AuthProvider'; - -type NavigateURL = '/' | '/contacts' | '/settings-account' | '/settings-general'; +//TODO: remove 'settings-account' and 'settings-general' when migration is finished +type NavigateURL = '/' | '/contacts' | '/settings-account' | '/settings-general' | '/settings/account/manage-account'; export default function Header() { const { t } = useTranslation(); @@ -51,6 +51,7 @@ export default function Header() { <MenuItem onClick={() => closeMenuAndNavigate(`/contacts`)}>{t('settings_menu_item_contacts')}</MenuItem> <MenuItem onClick={() => closeMenuAndNavigate('/settings-account')}>{t('settings_menu_item_account')}</MenuItem> <MenuItem onClick={() => closeMenuAndNavigate('/settings-general')}>{t('settings_menu_item_general')}</MenuItem> + <MenuItem onClick={() => closeMenuAndNavigate('/settings/account/manage-account')}>{t('settings')}</MenuItem> <MenuItem onClick={logout}>{t('logout')}</MenuItem> </Menu> </Box> diff --git a/client/src/components/SettingSidebar.tsx b/client/src/components/SettingSidebar.tsx index 813572afbc244d2c36ab751007c7949e3e564f02..32a33058f817e50fd83be63f0c792bb1383b8377 100644 --- a/client/src/components/SettingSidebar.tsx +++ b/client/src/components/SettingSidebar.tsx @@ -78,8 +78,14 @@ function SettingSidebar() { icon: null, title: t('settings_title_general'), highlightKey: 'general', - link: '/settings/general/appearance', + link: '/settings/general/system', submenuItems: [ + { + highlightKey: 'system', + icon: null, + title: t('settings_title_system'), + link: '/settings/general/system', + }, { highlightKey: 'appearance', icon: null, diff --git a/client/src/locale/en/translation.json b/client/src/locale/en/translation.json index 07827f339d5cd4c090cb2145470706cf505cfcc8..8f18869e2604fbcea11a24bebbaf258d145964fd 100644 --- a/client/src/locale/en/translation.json +++ b/client/src/locale/en/translation.json @@ -69,6 +69,7 @@ "incoming_call_video": "Incoming video call from {{member0}}", "invitations": "Invitations", "jami": "Jami", + "jami_account": "Jami Account", "jami_user_id": "Jami user ID", "jams": "JAMS", "loading": "Loading...", @@ -132,6 +133,7 @@ "registration_success": "You've successfully registered! — Logging you in...", "search_results": "Search Results", "select_placeholder": "Select an option", + "settings": "Settings", "settings_appearance": "Appearance", "settings_customize_profile": "Customize profile", "settings_dark_theme": "Dark theme", @@ -142,6 +144,7 @@ "settings_menu_item_account": "Account settings", "settings_menu_item_contacts": "Contacts", "settings_menu_item_general": "General settings", + "settings_theme": "Theme", "settings_title_account": "Account", "settings_title_chat": "Chat", "settings_title_general": "General", diff --git a/client/src/locale/fr/translation.json b/client/src/locale/fr/translation.json index 358d878e127ad50fc1c4d0cb07d58a633d47cd6b..b0e385b284693407a00f566b1819e2d8b6386f91 100644 --- a/client/src/locale/fr/translation.json +++ b/client/src/locale/fr/translation.json @@ -69,6 +69,7 @@ "incoming_call_video": "Appel vidéo entrant de {{member0}}", "invitations": "Invitations", "jami": "Jami", + "jami_account": "Compte Jami", "jami_user_id": "ID Jami de l'utilisateur", "jams": "JAMS", "loading": "Chargement...", @@ -132,6 +133,7 @@ "registration_success": "Inscription réussie! — Connexion en cours...", "search_results": "Résultats de la recherche", "select_placeholder": "Sélectionner une option", + "settings": "Paramètres", "settings_appearance": "Apparence", "settings_customize_profile": "Paramétrer le profil", "settings_dark_theme": "Thème sombre", @@ -142,6 +144,7 @@ "settings_menu_item_account": "Paramètres du compte", "settings_menu_item_contacts": "Contacts", "settings_menu_item_general": "Paramètres généraux", + "settings_theme": "Thème", "settings_title_account": "Compte", "settings_title_chat": "Clavardage", "settings_title_general": "Général", diff --git a/client/src/router.tsx b/client/src/router.tsx index a590daab85fdf9eab5633455fa74fd067c747dc5..6cfcb7f4c2fb601b24e3f22e9fb9714d29d6f116 100644 --- a/client/src/router.tsx +++ b/client/src/router.tsx @@ -23,6 +23,8 @@ import LinkedDevices from './components/AccountSettings/LinkedDevices'; import ManageAccount from './components/AccountSettings/ManageAccount'; import ContactList from './components/ContactList'; import ConversationView from './components/ConversationView'; +import Appearance from './components/GeneralSettings/Appearance'; +import System from './components/GeneralSettings/System'; import Header from './components/Header'; import SettingSidebar from './components/SettingSidebar'; import AuthProvider from './contexts/AuthProvider'; @@ -88,7 +90,8 @@ export const router = createBrowserRouter( <Route path="settings/account/manage-account" element={<ManageAccount />} /> <Route path="settings/account/customize-profile" element={<CustomizeProfile />} /> <Route path="settings/account/linked-devices" element={<LinkedDevices />} /> - <Route path="settings/general/appearance" element={<GeneralSettings />} /> + <Route path="settings/general/system" element={<System />} /> + <Route path="settings/general/appearance" element={<Appearance />} /> <Route path="settings-account" element={<AccountSettings />} /> <Route path="settings-general" element={<GeneralSettings />} />