Refactored layout. Added NavBar component.

This commit is contained in:
Mike Cao 2023-01-18 15:05:39 -08:00
parent fad38dc180
commit 1d9c3133f0
56 changed files with 601 additions and 429 deletions

View file

@ -4,7 +4,7 @@ import { defineMessages, useIntl } from 'react-intl';
import Page from 'components/layout/Page';
import PageHeader from 'components/layout/PageHeader';
import WebsiteChartList from 'components/pages/websites/WebsiteChartList';
import DashboardSettingsButton from 'components/settings/DashboardSettingsButton';
import DashboardSettingsButton from 'components/pages/dashboard/DashboardSettingsButton';
import DashboardEdit from 'components/pages/dashboard/DashboardEdit';
import styles from 'components/pages/websites/WebsiteList.module.css';
import useUser from 'hooks/useUser';

View file

@ -0,0 +1,42 @@
import { defineMessages, useIntl } from 'react-intl';
import MenuButton from 'components/common/MenuButton';
import Gear from 'assets/gear.svg';
import { saveDashboard } from 'store/dashboard';
import { Icon } from 'react-basics';
const messages = defineMessages({
toggleCharts: { id: 'message.toggle-charts', defaultMessage: 'Toggle charts' },
editDashboard: { id: 'message.edit-dashboard', defaultMessage: 'Edit dashboard' },
});
export default function DashboardSettingsButton() {
const { formatMessage } = useIntl();
const menuOptions = [
{
label: formatMessage(messages.toggleCharts),
value: 'charts',
},
{
label: formatMessage(messages.editDashboard),
value: 'order',
},
];
function handleSelect(value) {
if (value === 'charts') {
saveDashboard(state => ({ showCharts: !state.showCharts }));
}
if (value === 'order') {
saveDashboard({ editing: true });
}
}
return (
<MenuButton options={menuOptions} onSelect={handleSelect} hideLabel>
<Icon>
<Gear />
</Icon>
</MenuButton>
);
}

View file

@ -0,0 +1,5 @@
.buttonGroup {
display: flex;
place-items: center;
gap: 10px;
}

View file

@ -4,4 +4,5 @@
align-items: center;
justify-content: center;
height: 100vh;
background: var(--base75);
}

View file

@ -1,23 +0,0 @@
import AppLayout from 'components/layout/AppLayout';
import Menu from 'components/nav/Nav';
import styles from './SettingsLayout.module.css';
import useConfig from 'hooks/useConfig';
export default function SettingsLayout({ children }) {
const { adminDisabled } = useConfig();
if (adminDisabled) {
return null;
}
return (
<AppLayout>
<div className={styles.dashboard}>
<div className={styles.nav}>
<Menu />
</div>
<div className={styles.content}>{children}</div>
</div>
</AppLayout>
);
}

View file

@ -1,16 +0,0 @@
.dashboard {
display: flex;
flex: 1;
}
.nav {
margin-top: 20px;
}
.content {
position: relative;
background: var(--base50);
flex: 1;
border-radius: 8px;
overflow: hidden;
}

View file

@ -0,0 +1,21 @@
import { FormattedMessage } from 'react-intl';
import DateFilter from 'components/common/DateFilter';
import { Button, Flexbox } from 'react-basics';
import useDateRange from 'hooks/useDateRange';
import { DEFAULT_DATE_RANGE } from 'lib/constants';
export default function DateRangeSetting() {
const [dateRange, setDateRange] = useDateRange();
const { startDate, endDate, value } = dateRange;
const handleReset = () => setDateRange(DEFAULT_DATE_RANGE);
return (
<Flexbox width={400} gap={10}>
<DateFilter value={value} startDate={startDate} endDate={endDate} onChange={setDateRange} />
<Button onClick={handleReset}>
<FormattedMessage id="label.reset" defaultMessage="Reset" />
</Button>
</Flexbox>
);
}

View file

@ -0,0 +1,34 @@
import { useIntl, defineMessages } from 'react-intl';
import { Button, Dropdown, Item, Flexbox } from 'react-basics';
import useLocale from 'hooks/useLocale';
import { DEFAULT_LOCALE } from 'lib/constants';
import { languages } from 'lib/lang';
const messages = defineMessages({
reset: { id: 'label.reset', defaultMessage: 'Reset' },
});
export default function LanguageSetting() {
const { formatMessage } = useIntl();
const { locale, saveLocale } = useLocale();
const options = Object.keys(languages);
const handleReset = () => saveLocale(DEFAULT_LOCALE);
const renderValue = value => languages[value].label;
return (
<Flexbox width={400} gap={10}>
<Dropdown
items={options}
value={locale}
renderValue={renderValue}
onChange={saveLocale}
menuProps={{ style: { height: 300, width: 300 } }}
>
{item => <Item key={item}>{languages[item].label}</Item>}
</Dropdown>
<Button onClick={handleReset}>{formatMessage(messages.reset)}</Button>
</Flexbox>
);
}

View file

@ -0,0 +1,46 @@
import { Form, FormRow } from 'react-basics';
import { useIntl, defineMessages } from 'react-intl';
import TimezoneSetting from 'components/pages/settings/profile/TimezoneSetting';
import DateRangeSetting from 'components/pages/settings/profile/DateRangeSetting';
import LanguageSetting from 'components/pages/settings/profile/LanguageSetting';
import ThemeSetting from 'components/buttons/ThemeSetting';
import useUser from 'hooks/useUser';
const messages = defineMessages({
username: { id: 'label.username', defaultMessage: 'Username' },
role: { id: 'label.role', defaultMessage: 'Role' },
timezone: { id: 'label.timezone', defaultMessage: 'Timezone' },
dateRange: { id: 'label.default-date-range', defaultMessage: 'Default date range' },
language: { id: 'label.language', defaultMessage: 'Language' },
theme: { id: 'label.theme', defaultMessage: 'Theme' },
});
export default function ProfileDetails() {
const { user } = useUser();
const { formatMessage } = useIntl();
if (!user) {
return null;
}
const { username, role } = user;
return (
<Form>
<FormRow label={formatMessage(messages.username)}>{username}</FormRow>
<FormRow label={formatMessage(messages.role)}>{role}</FormRow>
<FormRow label={formatMessage(messages.language)} inline>
<LanguageSetting />
</FormRow>
<FormRow label={formatMessage(messages.timezone)} inline>
<TimezoneSetting />
</FormRow>
<FormRow label={formatMessage(messages.dateRange)} inline>
<DateRangeSetting />
</FormRow>
<FormRow label={formatMessage(messages.theme)}>
<ThemeSetting />
</FormRow>
</Form>
);
}

View file

@ -0,0 +1,3 @@
.list dd {
display: flex;
}

View file

@ -1,6 +1,6 @@
import Page from 'components/layout/Page';
import PageHeader from 'components/layout/PageHeader';
import ProfileDetails from 'components/settings/ProfileDetails';
import ProfileDetails from 'components/pages/settings/profile/ProfileDetails';
import { useState } from 'react';
import { Breadcrumbs, Icon, Item, useToast, Modal, Button } from 'react-basics';
import UserPasswordForm from 'components/pages/settings/users/UserPasswordForm';

View file

@ -0,0 +1,31 @@
import { Dropdown, Item, Button, Flexbox } from 'react-basics';
import { useIntl, defineMessages } from 'react-intl';
import { listTimeZones } from 'timezone-support';
import useTimezone from 'hooks/useTimezone';
import { getTimezone } from 'lib/date';
const messages = defineMessages({
reset: { id: 'label.reset', defaultMessage: 'Reset' },
});
export default function TimezoneSetting() {
const { formatMessage } = useIntl();
const [timezone, saveTimezone] = useTimezone();
const options = listTimeZones();
const handleReset = () => saveTimezone(getTimezone());
return (
<Flexbox width={400} gap={10}>
<Dropdown
items={options}
value={timezone}
onChange={saveTimezone}
menuProps={{ style: { height: 300, width: 300 } }}
>
{item => <Item key={item}>{item}</Item>}
</Dropdown>
<Button onClick={handleReset}>{formatMessage(messages.reset)}</Button>
</Flexbox>
);
}

View file

@ -1,5 +1,5 @@
import { useState } from 'react';
import { Button, Icon, Modal, useToast } from 'react-basics';
import { Button, Icon, Text, Modal, useToast, Icons } from 'react-basics';
import useApi from 'hooks/useApi';
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
import WebsiteAddForm from 'components/pages/settings/websites/WebsiteAddForm';
@ -8,6 +8,8 @@ import WebsitesTable from 'components/pages/settings/websites/WebsitesTable';
import Page from 'components/layout/Page';
import useUser from 'hooks/useUser';
const { Plus } = Icons;
export default function WebsitesList() {
const [edit, setEdit] = useState(false);
const { get, useQuery } = useApi();
@ -44,8 +46,11 @@ export default function WebsitesList() {
<Page loading={isLoading} error={error}>
{toast}
<PageHeader title="Websites">
<Button onClick={handleAdd}>
<Icon icon="plus" /> Add website
<Button variant="primary" onClick={handleAdd}>
<Icon>
<Plus />
</Icon>
<Text>Add website</Text>
</Button>
</PageHeader>
@ -53,7 +58,10 @@ export default function WebsitesList() {
{!hasData && (
<EmptyPlaceholder message="You don't have any websites configured.">
<Button variant="primary" onClick={handleAdd}>
<Icon icon="plus" /> Add website
<Icon>
<Plus />
</Icon>
<Text>Add website</Text>
</Button>
</EmptyPlaceholder>
)}

View file

@ -8,10 +8,12 @@ import {
TableColumn,
Button,
Icon,
Icons,
} from 'react-basics';
import ExternalLink from 'assets/external-link.svg';
import styles from './WebsitesTable.module.css';
const { ArrowRight, External } = Icons;
export default function WebsitesTable({ columns = [], rows = [] }) {
return (
<Table className={styles.table} columns={columns} rows={rows}>
@ -33,7 +35,9 @@ export default function WebsitesTable({ columns = [], rows = [] }) {
<Link href={`/settings/websites/${id}`}>
<a>
<Button>
<Icon icon="arrow-right" />
<Icon>
<ArrowRight />
</Icon>
Settings
</Button>
</a>
@ -42,7 +46,7 @@ export default function WebsitesTable({ columns = [], rows = [] }) {
<a>
<Button>
<Icon>
<ExternalLink />
<External />
</Icon>
View
</Button>

View file

@ -15,8 +15,8 @@ const messages = defineMessages({
defaultMessage: "You don't have any websites configured.",
},
goToSettngs: {
id: 'message.go-to-settings',
defaultMessage: 'Go to settings',
id: 'message.go-to-buttons',
defaultMessage: 'Go to buttons',
},
});