Skip to content
Snippets Groups Projects
Commit cffda38e authored by Ziwei Wang's avatar Ziwei Wang
Browse files

Add user settings side bar

This is only the skeleton and the UI will be implemented when wireframes for the web version are ready
The original components and their routes are preserved for now.

Change-Id: Ib0900fdd78d6ab5058b7b0278ce92d4741f8be5a
parent 9da76141
No related branches found
No related tags found
No related merge requests found
/*
* 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 { AvatarEditor } from '../ConversationAvatar';
function CustomizeProfile() {
return (
<>
<AvatarEditor />
</>
);
}
export default CustomizeProfile;
/*
* 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 GroupRounded from '@mui/icons-material/AddCircle';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Grid from '@mui/material/Grid';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import Typography from '@mui/material/Typography';
import { useTranslation } from 'react-i18next';
import { useAuthContext } from '../../contexts/AuthProvider';
function LinkedDevices() {
const { account } = useAuthContext();
const { t } = useTranslation();
const devices: string[][] = [];
const accountDevices = account.devices;
for (const i in accountDevices) devices.push([i, accountDevices[i]]);
//TODO: reduce number of renders
console.log(devices);
return (
<>
<Grid item xs={12} sm={6}>
<Card>
<CardContent>
<Typography color="textSecondary" gutterBottom>
{t('settings_linked_devices')}
</Typography>
<Typography gutterBottom variant="h5" component="h2">
{devices.map((device, i) => (
<ListItem key={i}>
<GroupRounded />
<ListItemText id="switch-list-label-rendezvous" primary={device[1]} secondary={device[0]} />
</ListItem>
))}
{/* <ListItemTextsion> */}
</Typography>
</CardContent>
</Card>
</Grid>
</>
);
}
export default LinkedDevices;
/*
* 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 Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
import { useAuthContext } from '../../contexts/AuthProvider';
import JamiIdCard from '../JamiIdCard';
function ManageAccount() {
const { account } = useAuthContext();
const devices: string[][] = [];
const accountDevices = account.devices;
for (const i in accountDevices) devices.push([i, accountDevices[i]]);
console.log(devices);
const isJamiAccount = account.getType() === 'RING';
const alias = isJamiAccount ? 'Jami account' : 'SIP account';
return (
<>
<Typography variant="h2" component="h2" gutterBottom>
{alias}
</Typography>
<Grid container spacing={3} style={{ marginBottom: 16 }}>
{isJamiAccount && (
<Grid item xs={12}>
<JamiIdCard account={account} />
</Grid>
)}
</Grid>
</>
);
}
export default ManageAccount;
/*
* 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 Collapse from '@mui/material/Collapse';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
// import ListItemIcon from '@mui/material/ListItemIcon';
import Stack from '@mui/material/Stack';
import { Theme, useTheme } from '@mui/system';
import Box from '@mui/system/Box';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
//Settings meta structure
interface ISettingItem {
icon: unknown;
title: string;
highlightKey: string; //The string used to determine whether to highlight the title or not.
link: string;
submenuItems?: ISettingItem[];
}
function SettingSidebar() {
const { t } = useTranslation();
const navigate = useNavigate();
const theme: Theme = useTheme();
const { pathname } = useLocation();
const isCurrentlyViewing = (text: string) => {
return pathname.includes(text);
};
const settingMeta: ISettingItem[] = useMemo(() => {
return [
{
icon: null,
title: t('settings_title_account'),
highlightKey: 'account',
link: '/settings/account/manage-account',
submenuItems: [
{
highlightKey: 'manage-account',
icon: null,
title: t('settings_manage_account'),
link: '/settings/account/manage-account',
},
{
highlightKey: 'customize-profile',
icon: null,
title: t('settings_customize_profile'),
link: '/settings/account/customize-profile',
},
{
highlightKey: 'linked-devices',
icon: null,
title: t('settings_linked_devices'),
link: '/settings/account/linked-devices',
},
],
},
{
icon: null,
title: t('settings_title_general'),
highlightKey: 'general',
link: '/settings/general/appearance',
submenuItems: [
{
highlightKey: 'appearance',
icon: null,
title: t('settings_appearance'),
link: '/settings/general/appearance',
},
],
},
];
}, [t]);
return (
<Stack direction="row">
<List sx={{ width: '300px' }}>
{settingMeta.map((settingItem, index) => (
<Box key={index}>
<ListItemButton
selected={isCurrentlyViewing(settingItem.highlightKey)}
onClick={() => navigate(settingItem.link)}
>
{/* TODO: add icons */}
{/* <ListItemIcon>
{/* <InboxIcon /> */}
{/* </ListItemIcon> */}
<ListItemText
primaryTypographyProps={{
color: isCurrentlyViewing(settingItem.highlightKey) ? theme.palette.primary.dark : 'initial',
}}
primary={settingItem.title}
/>
</ListItemButton>
<Collapse in={isCurrentlyViewing(settingItem.highlightKey)} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{settingItem.submenuItems &&
settingItem.submenuItems.map((submenuItem, itemIndex) => (
<ListItemButton key={itemIndex} sx={{ pl: 4 }} onClick={() => navigate(submenuItem.link)}>
<ListItemText
primaryTypographyProps={{
color: isCurrentlyViewing(submenuItem.highlightKey) ? theme.palette.primary.dark : 'initial',
}}
primary={submenuItem.title}
/>
</ListItemButton>
))}
</List>
</Collapse>
</Box>
))}
</List>
<Outlet />
</Stack>
);
}
export default SettingSidebar;
......@@ -2,12 +2,12 @@
"accept_call_audio": "Accept in audio",
"accept_call_video": "Accept in video",
"admin_page_create_button": "Create admin account",
"admin_page_login_title": "Jami Web Admin Login",
"admin_page_password_placeholder": "New password",
"admin_page_password_repeat_placeholder": "Repeat password",
"admin_page_setup_complete": "Setup is already complete",
"admin_page_setup_intro": "Let's start by creating a new administrator account to control access to the server configuration.",
"admin_page_setup_not_complete": "Setup is not complete",
"admin_page_login_title": "Jami Web Admin Login",
"admin_page_setup_title": "Jami Web Admin Setup",
"admin_page_welcome": "Welcome to the Jami web node setup.",
"are_composing_1": "{{member0}} is writing",
......@@ -132,12 +132,17 @@
"registration_success": "You've successfully registered! — Logging you in...",
"search_results": "Search Results",
"select_placeholder": "Select an option",
"setting_dark_theme": "Dark theme",
"setting_language": "Language",
"setting_link_preview": "Show link previews",
"settings_appearance": "Appearance",
"settings_customize_profile": "Customize profile",
"settings_dark_theme": "Dark theme",
"settings_language": "Language",
"settings_link_preview": "Show link previews",
"settings_linked_devices": "Linked devices",
"settings_manage_account": "Manage account",
"settings_menu_item_account": "Account settings",
"settings_menu_item_contacts": "Contacts",
"settings_menu_item_general": "General settings",
"settings_title_account": "Account",
"settings_title_chat": "Chat",
"settings_title_general": "General",
"settings_title_system": "System",
......
......@@ -2,12 +2,12 @@
"accept_call_audio": "Accepter en audio",
"accept_call_video": "Accepter en vidéo",
"admin_page_create_button": "Créer un compte admin",
"admin_page_login_title": "Jami web — administration — connexion",
"admin_page_password_placeholder": "Nouveau mot de passe",
"admin_page_password_repeat_placeholder": "Répéter le mot de passe",
"admin_page_setup_complete": "La configuration est déjà terminée",
"admin_page_setup_intro": "Commençons par créer un nouveau compte administrateur pour contrôler l'accès à la configuration du serveur.",
"admin_page_setup_not_complete": "La configuration n'est pas terminée",
"admin_page_login_title": "Jami web — administration — connexion",
"admin_page_setup_title": "Jami web — administration — configuration",
"admin_page_welcome": "Bienvenue à la configuration du nœud web Jami.",
"are_composing_1": "{{member0}} est en train d'écrire",
......@@ -132,12 +132,17 @@
"registration_success": "Inscription réussie! — Connexion en cours...",
"search_results": "Résultats de la recherche",
"select_placeholder": "Sélectionner une option",
"setting_dark_theme": "Thème sombre",
"setting_language": "Langue",
"setting_link_preview": "Montrer la prévisualisation des liens",
"settings_appearance": "Apparence",
"settings_customize_profile": "Paramétrer le profil",
"settings_dark_theme": "Thème sombre",
"settings_language": "Langue",
"settings_link_preview": "Montrer la prévisualisation des liens",
"settings_linked_devices": "Appareils associés",
"settings_manage_account": "Gérer le compte",
"settings_menu_item_account": "Paramètres du compte",
"settings_menu_item_contacts": "Contacts",
"settings_menu_item_general": "Paramètres généraux",
"settings_title_account": "Compte",
"settings_title_chat": "Clavardage",
"settings_title_general": "Général",
"settings_title_system": "Système",
......
......@@ -45,7 +45,7 @@ const SettingTheme = () => {
const { mode, toggleMode } = useContext(CustomThemeContext);
return <SettingSwitch label={t('setting_dark_theme')} onChange={toggleMode} checked={mode === 'dark'} />;
return <SettingSwitch label={t('settings_dark_theme')} onChange={toggleMode} checked={mode === 'dark'} />;
};
const settingLanguageOptions = languagesInfos.map(({ tag, fullName }) => ({
......@@ -72,7 +72,12 @@ const SettingLanguage = () => {
);
return (
<SettingSelect label={t('setting_language')} option={option} options={settingLanguageOptions} onChange={onChange} />
<SettingSelect
label={t('settings_language')}
option={option}
options={settingLanguageOptions}
onChange={onChange}
/>
);
};
......@@ -81,5 +86,5 @@ const SettingLinkPreview = () => {
const [isOn, setIsOn] = useState<boolean>(true);
return <SettingSwitch label={t('setting_link_preview')} onChange={() => setIsOn((isOn) => !isOn)} checked={isOn} />;
return <SettingSwitch label={t('settings_link_preview')} onChange={() => setIsOn((isOn) => !isOn)} checked={isOn} />;
};
......@@ -18,9 +18,13 @@
import { createBrowserRouter, createRoutesFromElements, Outlet, Route } from 'react-router-dom';
import App, { appLoader } from './App';
import CustomizeProfile from './components/AccountSettings/CustomizeProfile';
import LinkedDevices from './components/AccountSettings/LinkedDevices';
import ManageAccount from './components/AccountSettings/ManageAccount';
import ContactList from './components/ContactList';
import ConversationView from './components/ConversationView';
import Header from './components/Header';
import SettingSidebar from './components/SettingSidebar';
import AuthProvider from './contexts/AuthProvider';
import CallManagerProvider from './contexts/CallManagerProvider';
import ConversationProvider from './contexts/ConversationProvider';
......@@ -80,8 +84,15 @@ export const router = createBrowserRouter(
}
/>
</Route>
<Route element={<SettingSidebar />}>
<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-account" element={<AccountSettings />} />
<Route path="settings-general" element={<GeneralSettings />} />
</Route>
<Route path="contacts" element={<ContactList />} />
</Route>
</Route>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment