Added router navigation for settings and details.

This commit is contained in:
Mike Cao 2020-09-16 21:55:32 -07:00
parent 30bca80dac
commit 53c23a280b
21 changed files with 156 additions and 73 deletions

View File

@ -1,5 +1,6 @@
import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { useRouter } from 'next/router';
import classNames from 'classnames';
import WebsiteChart from 'components/metrics/WebsiteChart';
import WorldMap from 'components/common/WorldMap';
@ -19,12 +20,28 @@ import EventsChart from './metrics/EventsChart';
import useFetch from 'hooks/useFetch';
import Loading from 'components/common/Loading';
const views = {
url: PagesTable,
referrer: ReferrersTable,
browser: BrowsersTable,
os: OSTable,
device: DevicesTable,
country: CountriesTable,
event: EventsTable,
};
export default function WebsiteDetails({ websiteId }) {
const router = useRouter();
const { data } = useFetch(`/api/website/${websiteId}`);
const [chartLoaded, setChartLoaded] = useState(false);
const [countryData, setCountryData] = useState();
const [eventsData, setEventsData] = useState();
const [expand, setExpand] = useState();
const {
query: { id, view },
} = router;
const path = `/website/${id.join('/')}`;
console.log({ router });
const BackButton = () => (
<Button
@ -32,7 +49,7 @@ export default function WebsiteDetails({ websiteId }) {
className={styles.backButton}
icon={<Arrow />}
size="xsmall"
onClick={() => setExpand(null)}
onClick={() => router.push(path)}
>
<div>
<FormattedMessage id="button.back" defaultMessage="Back" />
@ -46,38 +63,31 @@ export default function WebsiteDetails({ websiteId }) {
},
{
label: <FormattedMessage id="metrics.pages" defaultMessage="Pages" />,
value: 'url',
component: PagesTable,
value: `${path}?view=url`,
},
{
label: <FormattedMessage id="metrics.referrers" defaultMessage="Referrers" />,
value: 'referrer',
component: ReferrersTable,
value: `${path}?view=referrer`,
},
{
label: <FormattedMessage id="metrics.browsers" defaultMessage="Browsers" />,
value: 'browser',
component: BrowsersTable,
value: `${path}?view=browser`,
},
{
label: <FormattedMessage id="metrics.operating-systems" defaultMessage="Operating system" />,
value: 'os',
component: OSTable,
value: `${path}?view=os`,
},
{
label: <FormattedMessage id="metrics.devices" defaultMessage="Devices" />,
value: 'device',
component: DevicesTable,
value: `${path}?view=device`,
},
{
label: <FormattedMessage id="metrics.countries" defaultMessage="Countries" />,
value: 'country',
component: CountriesTable,
value: `${path}?view=country`,
},
{
label: <FormattedMessage id="metrics.events" defaultMessage="Events" />,
value: 'event',
component: EventsTable,
value: `${path}?view=event`,
},
];
@ -88,11 +98,7 @@ export default function WebsiteDetails({ websiteId }) {
onExpand: handleExpand,
};
const DetailsComponent = expand?.component;
function getSelectedMenuOption(value) {
return menuOptions.find(e => e.value === value);
}
const DetailsComponent = views[view];
function handleDataLoad() {
if (!chartLoaded) {
@ -101,11 +107,7 @@ export default function WebsiteDetails({ websiteId }) {
}
function handleExpand(value) {
setExpand(getSelectedMenuOption(value));
}
function handleMenuSelect(value) {
setExpand(getSelectedMenuOption(value));
router.push(`${path}?view=${value}`);
}
if (!data) {
@ -126,7 +128,7 @@ export default function WebsiteDetails({ websiteId }) {
</div>
</div>
{!chartLoaded && <Loading />}
{chartLoaded && !expand && (
{chartLoaded && !view && (
<>
<div className={classNames(styles.row, 'row')}>
<div className="col-md-12 col-lg-6">
@ -167,15 +169,8 @@ export default function WebsiteDetails({ websiteId }) {
</div>
</>
)}
{expand && (
<MenuLayout
className={styles.expand}
menuClassName={styles.menu}
optionClassName={styles.option}
menu={menuOptions}
selectedOption={expand.value}
onMenuSelect={handleMenuSelect}
>
{view && (
<MenuLayout className={styles.view} menuClassName={styles.menu} menu={menuOptions}>
<DetailsComponent {...tableProps} limit={false} />
</MenuLayout>
)}

View File

@ -2,7 +2,7 @@
margin-bottom: 30px;
}
.expand {
.view {
border-top: 1px solid var(--gray300);
}
@ -10,10 +10,6 @@
font-size: var(--font-size-small);
}
.menu .option {
font-size: var(--font-size-small);
}
.backButton {
align-self: flex-start;
margin-bottom: 16px;

View File

@ -0,0 +1,32 @@
import React from 'react';
import { useRouter } from 'next/router';
import classNames from 'classnames';
import styles from './NavMenu.module.css';
export default function NavMenu({ options = [], className, onSelect = () => {} }) {
const router = useRouter();
return (
<div className={classNames(styles.menu, className)}>
{options
.filter(({ hidden }) => !hidden)
.map(option => {
const { label, value, className: customClassName, render } = option;
return render ? (
render(option)
) : (
<div
key={value}
className={classNames(styles.option, customClassName, {
[styles.selected]: router.asPath === value,
})}
onClick={e => onSelect(value, e)}
>
{label}
</div>
);
})}
</div>
);
}

View File

@ -0,0 +1,20 @@
.menu {
border: 1px solid var(--gray500);
border-radius: 4px;
overflow: hidden;
z-index: 2;
}
.option {
padding: 8px 16px;
cursor: pointer;
border-radius: 4px;
}
.option:hover {
background: var(--gray75);
}
.selected {
font-weight: 600;
}

View File

@ -27,6 +27,7 @@ export default function UserButton() {
value: 'username',
className: styles.username,
},
{ label: <FormattedMessage id="label.profile" defaultMessage="Profile" />, value: 'profile' },
{ label: <FormattedMessage id="label.logout" defaultMessage="Logout" />, value: 'logout' },
];
@ -35,6 +36,8 @@ export default function UserButton() {
if (value === 'logout') {
router.push('/logout');
} else if (value === 'profile') {
router.push('/settings/profile');
}
}

View File

@ -1,29 +1,37 @@
import React from 'react';
import { useRouter } from 'next/router';
import classNames from 'classnames';
import Menu from 'components/common/Menu';
import NavMenu from 'components/common/NavMenu';
import styles from './MenuLayout.module.css';
export default function MenuLayout({
menu,
selectedOption,
onMenuSelect,
className,
menuClassName,
contentClassName,
optionClassName,
children,
replace = false,
}) {
const router = useRouter();
function handleSelect(url) {
if (replace) {
router.replace(url);
} else {
router.push(url);
}
}
return (
<div className={classNames(styles.container, className, 'row')}>
<Menu
<NavMenu
options={menu}
selectedOption={selectedOption}
className={classNames(styles.menu, menuClassName, 'col-12 col-lg-3')}
selectedClassName={styles.selected}
optionClassName={classNames(styles.option, optionClassName)}
onSelect={onMenuSelect}
className={classNames(styles.menu, menuClassName, 'col-12 col-lg-2')}
onSelect={handleSelect}
/>
<div className={classNames(styles.content, contentClassName, 'col-12 col-lg-9')}>
<div className={classNames(styles.content, contentClassName, 'col-12 col-lg-10')}>
{children}
</div>
</div>

View File

@ -10,25 +10,11 @@
}
.container .content {
flex: 1;
position: relative;
border-left: 1px solid var(--gray300);
padding-left: 30px;
}
.option {
font-size: var(--font-size-normal);
padding: 8px 16px;
cursor: pointer;
margin-right: 30px;
border-radius: 4px;
}
.option:hover {
background: var(--gray75);
}
.selected {
font-weight: 600;
margin-left: 30px;
}
@media only screen and (max-width: 992px) {
@ -40,5 +26,6 @@
border-top: 1px solid var(--gray300);
border-left: 0;
padding-left: 0;
margin-left: 0;
}
}

View File

@ -1,4 +1,5 @@
import React, { useState } from 'react';
import { useRouter } from 'next/router';
import Page from 'components/layout/Page';
import MenuLayout from 'components/layout/MenuLayout';
import WebsiteSettings from './WebsiteSettings';
@ -7,13 +8,15 @@ import ProfileSettings from './ProfileSettings';
import { useSelector } from 'react-redux';
import { FormattedMessage } from 'react-intl';
const WEBSITES = 1;
const ACCOUNTS = 2;
const PROFILE = 3;
const WEBSITES = '/settings';
const ACCOUNTS = '/settings/accounts';
const PROFILE = '/settings/profile';
export default function Settings() {
const user = useSelector(state => state.user);
const [option, setOption] = useState(WEBSITES);
const router = useRouter();
const { pathname } = router;
const menuOptions = [
{
@ -25,15 +28,18 @@ export default function Settings() {
value: ACCOUNTS,
hidden: !user.is_admin,
},
{ label: <FormattedMessage id="settings.profile" defaultMessage="Profile" />, value: PROFILE },
{
label: <FormattedMessage id="settings.profile" defaultMessage="Profile" />,
value: PROFILE,
},
];
return (
<Page>
<MenuLayout menu={menuOptions} selectedOption={option} onMenuSelect={setOption}>
{option === WEBSITES && <WebsiteSettings />}
{option === ACCOUNTS && <AccountSettings />}
{option === PROFILE && <ProfileSettings />}
{pathname === WEBSITES && <WebsiteSettings />}
{pathname === ACCOUNTS && <AccountSettings />}
{pathname === PROFILE && <ProfileSettings />}
</MenuLayout>
</Page>
);

View File

@ -6,12 +6,14 @@
"button.cancel": "Abbrechen",
"button.change-password": "Passwort ändern",
"button.copy-to-clipboard": "In die Zwischenablage kopieren",
"button.date-range": "Date range",
"button.delete": "Löschen",
"button.edit": "Bearbeiten",
"button.login": "Anmelden",
"button.more": "Mehr",
"button.refresh": "Refresh",
"button.save": "Speichern",
"button.single-day": "Single day",
"button.view-details": "Details anzeigen",
"button.websites": "Webseiten",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "Neues Passwort",
"label.password": "Passwort",
"label.passwords-dont-match": "Passwörter stimmen nicht überein",
"label.profile": "Profile",
"label.required": "Erforderlich",
"label.this-month": "Diesen Monat",
"label.this-week": "Diese Woche",

View File

@ -6,12 +6,14 @@
"button.cancel": "Cancel",
"button.change-password": "Change password",
"button.copy-to-clipboard": "Copy to clipboard",
"button.date-range": "Date range",
"button.delete": "Delete",
"button.edit": "Edit",
"button.login": "Login",
"button.more": "More",
"button.refresh": "Refresh",
"button.save": "Save",
"button.single-day": "Single day",
"button.view-details": "View details",
"button.websites": "Websites",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "New password",
"label.password": "Password",
"label.passwords-dont-match": "Passwords don't match",
"label.profile": "Profile",
"label.required": "Required",
"label.this-month": "This month",
"label.this-week": "This week",

View File

@ -6,12 +6,14 @@
"button.cancel": "Cancelar",
"button.change-password": "Cambiar contraseña",
"button.copy-to-clipboard": "Copiar al portapapeles",
"button.date-range": "Date range",
"button.delete": "Eliminar",
"button.edit": "Editar",
"button.login": "Iniciar sesión",
"button.more": "Más",
"button.refresh": "Refresh",
"button.save": "Guardar",
"button.single-day": "Single day",
"button.view-details": "Ver detalles",
"button.websites": "Sitios",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "Nueva contraseña",
"label.password": "Contraseña",
"label.passwords-dont-match": "Las contraseñas no coinciden",
"label.profile": "Profile",
"label.required": "Requerido",
"label.this-month": "Este mes",
"label.this-week": "Esta semana",

View File

@ -6,12 +6,14 @@
"button.cancel": "Annuler",
"button.change-password": "Changer de mot de passse",
"button.copy-to-clipboard": "Copier dans le presse papier",
"button.date-range": "Date range",
"button.delete": "Supprimer",
"button.edit": "Modifier",
"button.login": "Connexion",
"button.more": "Plus",
"button.refresh": "Refresh",
"button.save": "Sauvegarder",
"button.single-day": "Single day",
"button.view-details": "Voir les details",
"button.websites": "Sites",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "Nouveau mot de passe",
"label.password": "Mot de passe",
"label.passwords-dont-match": "Les mots de passe ne correspondent pas",
"label.profile": "Profile",
"label.required": "Requis",
"label.this-month": "Ce mois ci",
"label.this-week": "Cette semaine",

View File

@ -6,12 +6,14 @@
"button.cancel": "キャンセル",
"button.change-password": "パスワード変更",
"button.copy-to-clipboard": "クリップボードにコピー",
"button.date-range": "Date range",
"button.delete": "削除",
"button.edit": "編集",
"button.login": "ログイン",
"button.more": "さらに表示",
"button.refresh": "Refresh",
"button.save": "保存",
"button.single-day": "Single day",
"button.view-details": "詳細表示",
"button.websites": "Webサイト",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "新しいパスワード",
"label.password": "パスワード",
"label.passwords-dont-match": "パスワードが一致しません",
"label.profile": "Profile",
"label.required": "必須",
"label.this-month": "今月",
"label.this-week": "今週",

View File

@ -6,12 +6,14 @@
"button.cancel": "Цуцлах",
"button.change-password": "Нууц үг солих",
"button.copy-to-clipboard": "Хуулах",
"button.date-range": "Date range",
"button.delete": "Устгах",
"button.edit": "Засах",
"button.login": "Нэвтрэх",
"button.more": "Цааш",
"button.refresh": "Refresh",
"button.save": "Хадгалах",
"button.single-day": "Single day",
"button.view-details": "Дэлгэрүүлж харах",
"button.websites": "Вебүүд",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "Шинэ нууц үг",
"label.password": "Нууц үг",
"label.passwords-dont-match": "Нууц үг тохирохгүй байна",
"label.profile": "Profile",
"label.required": "Шаардлагатай",
"label.this-month": "Энэ сар",
"label.this-week": "Энэ долоо хоног",

View File

@ -6,12 +6,14 @@
"button.cancel": "Annuleren",
"button.change-password": "Wachtwoord wijzigen",
"button.copy-to-clipboard": "Kopiëer naar klembord",
"button.date-range": "Date range",
"button.delete": "Verwijderen",
"button.edit": "Bewerken",
"button.login": "Inloggen",
"button.more": "Toon meer",
"button.refresh": "Refresh",
"button.save": "Opslaan",
"button.single-day": "Single day",
"button.view-details": "Meer details",
"button.websites": "Websites",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "Nieuw wachtwoord",
"label.password": "Wachtwoord",
"label.passwords-dont-match": "Wachtwoorden komen niet overeen",
"label.profile": "Profile",
"label.required": "Verplicht",
"label.this-month": "Deze maand",
"label.this-week": "Deze week",

View File

@ -6,12 +6,14 @@
"button.cancel": "Отменить",
"button.change-password": "Изменить пароль",
"button.copy-to-clipboard": "Скопировать в буфер обмена",
"button.date-range": "Date range",
"button.delete": "Удалить",
"button.edit": "Редактировать",
"button.login": "Войти",
"button.more": "Больше",
"button.refresh": "Refresh",
"button.save": "Сохранить",
"button.single-day": "Single day",
"button.view-details": "Посмотреть детали",
"button.websites": "Сайты",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "Новый пароль",
"label.password": "Пароль",
"label.passwords-dont-match": "Пароли не совпадают",
"label.profile": "Profile",
"label.required": "Обязательное",
"label.this-month": "Этот месяц",
"label.this-week": "Эта неделя",

View File

@ -6,12 +6,14 @@
"button.cancel": "İptal",
"button.change-password": "Şifre değiştir",
"button.copy-to-clipboard": "Panoya kopyala",
"button.date-range": "Date range",
"button.delete": "Sil",
"button.edit": "Düzenle",
"button.login": "Giriş Yap",
"button.more": "Detaylı göster",
"button.refresh": "Refresh",
"button.save": "Kaydet",
"button.single-day": "Single day",
"button.view-details": "Detayı incele",
"button.websites": "Web siteleri",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "Yeni parola",
"label.password": "Parola",
"label.passwords-dont-match": "Parolalar uyuşmuyor",
"label.profile": "Profile",
"label.required": "Zorunlu alan",
"label.this-month": "Bu ay",
"label.this-week": "Bu hafta",

View File

@ -6,12 +6,14 @@
"button.cancel": "取消",
"button.change-password": "更新密码",
"button.copy-to-clipboard": "复制",
"button.date-range": "Date range",
"button.delete": "删除",
"button.edit": "编辑",
"button.login": "登录",
"button.more": "更多",
"button.refresh": "Refresh",
"button.save": "保存",
"button.single-day": "Single day",
"button.view-details": "查看更多",
"button.websites": "网站",
"device.desktop": "Desktop",
@ -37,6 +39,7 @@
"label.new-password": "新密码",
"label.password": "密码",
"label.passwords-dont-match": "密码不一致",
"label.profile": "Profile",
"label.required": "必填",
"label.this-month": "本月",
"label.this-week": "本周",

View File

@ -0,0 +1,3 @@
import Index from './index';
export default Index;

View File

@ -0,0 +1,3 @@
import Index from './index';
export default Index;