mirror of
https://github.com/kremalicious/umami.git
synced 2024-12-24 18:26:20 +01:00
Updated settings components and date filter.
This commit is contained in:
parent
70ef857dc7
commit
4b5b4db108
@ -1 +1 @@
|
|||||||
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M437.02 74.98C388.668 26.63 324.379 0 256 0S123.332 26.629 74.98 74.98C26.63 123.332 0 187.621 0 256s26.629 132.668 74.98 181.02C123.332 485.37 187.621 512 256 512s132.668-26.629 181.02-74.98C485.37 388.668 512 324.379 512 256s-26.629-132.668-74.98-181.02zM111.105 429.297c8.454-72.735 70.989-128.89 144.895-128.89 38.96 0 75.598 15.179 103.156 42.734 23.281 23.285 37.965 53.687 41.742 86.152C361.641 462.172 311.094 482 256 482s-105.637-19.824-144.895-52.703zM256 269.507c-42.871 0-77.754-34.882-77.754-77.753C178.246 148.879 213.13 114 256 114s77.754 34.879 77.754 77.754c0 42.871-34.883 77.754-77.754 77.754zm170.719 134.427a175.9 175.9 0 0 0-46.352-82.004c-18.437-18.438-40.25-32.27-64.039-40.938 28.598-19.394 47.426-52.16 47.426-89.238C363.754 132.34 315.414 84 256 84s-107.754 48.34-107.754 107.754c0 37.098 18.844 69.875 47.465 89.266-21.887 7.976-42.14 20.308-59.566 36.542-25.235 23.5-42.758 53.465-50.883 86.348C50.852 364.242 30 312.512 30 256 30 131.383 131.383 30 256 30s226 101.383 226 226c0 56.523-20.86 108.266-55.281 147.934zm0 0"/></svg>
|
<svg height="512pt" viewBox="-56 0 512 512" width="512pt" xmlns="http://www.w3.org/2000/svg"><path d="m267 236.375c36.253906-22.582031 60.433594-62.796875 60.433594-108.5625 0-70.476562-57.335938-127.8125-127.8125-127.8125-70.476563 0-127.8125 57.335938-127.8125 127.8125 0 45.765625 24.179687 85.976562 60.429687 108.558594-77.015625 27.699218-132.238281 101.46875-132.238281 187.902344v72.242187c0 8.550781 6.933594 15.484375 15.484375 15.484375h368.265625c8.550781 0 15.480469-6.933594 15.480469-15.484375v-72.242187c0-86.429688-55.21875-160.195313-132.230469-187.898438zm101.265625 244.65625h-337.296875v-56.757812c0-92.992188 75.652344-168.644532 168.648438-168.644532 92.992187 0 168.648437 75.652344 168.648437 168.644532zm-71.800781-353.21875c0 53.402344-43.441406 96.847656-96.84375 96.847656s-96.84375-43.445312-96.84375-96.847656c0-53.398438 43.441406-96.84375 96.84375-96.84375s96.84375 43.445312 96.84375 96.84375zm0 0"/></svg>
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 940 B |
@ -1,99 +1,109 @@
|
|||||||
import Calendar from 'assets/calendar-alt.svg';
|
|
||||||
import DatePickerForm from 'components/metrics/DatePickerForm';
|
|
||||||
import { endOfYear, isSameDay } from 'date-fns';
|
import { endOfYear, isSameDay } from 'date-fns';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Icon, Modal, Dropdown, Item } from 'react-basics';
|
||||||
|
import { useIntl, defineMessages } from 'react-intl';
|
||||||
|
import DatePickerForm from 'components/metrics/DatePickerForm';
|
||||||
import useLocale from 'hooks/useLocale';
|
import useLocale from 'hooks/useLocale';
|
||||||
import { dateFormat } from 'lib/date';
|
import { dateFormat } from 'lib/date';
|
||||||
import PropTypes from 'prop-types';
|
import Calendar from 'assets/calendar-alt.svg';
|
||||||
import { useState } from 'react';
|
|
||||||
import { Icon, Modal } from 'react-basics';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
import DropDown from './DropDown';
|
|
||||||
|
|
||||||
export const filterOptions = [
|
const messages = defineMessages({
|
||||||
{ label: <FormattedMessage id="label.today" defaultMessage="Today" />, value: '1day' },
|
today: { id: 'label.today', defaultMessage: 'Today' },
|
||||||
{
|
lastHours: { id: 'label.last-hours', defaultMessage: 'Last {x} hours' },
|
||||||
label: (
|
yesterday: { id: 'label.yesterday', defaultMessage: 'Yesterday' },
|
||||||
<FormattedMessage id="label.last-hours" defaultMessage="Last {x} hours" values={{ x: 24 }} />
|
thisWeek: { id: 'label.this-week', defaultMessage: 'This week' },
|
||||||
),
|
lastDays: { id: 'label.last-days', defaultMessage: 'Last {x} days' },
|
||||||
value: '24hour',
|
thisMonth: { id: 'label.this-month', defaultMessage: 'This month' },
|
||||||
},
|
thisYear: { id: 'label.this-year', defaultMessage: 'This year' },
|
||||||
{
|
allTime: { id: 'label.all-time', defaultMessage: 'All time' },
|
||||||
label: <FormattedMessage id="label.yesterday" defaultMessage="Yesterday" />,
|
customRange: { id: 'label.custom-range', defaultMessage: 'Custom-range' },
|
||||||
value: '-1day',
|
});
|
||||||
},
|
|
||||||
{
|
|
||||||
label: <FormattedMessage id="label.this-week" defaultMessage="This week" />,
|
|
||||||
value: '1week',
|
|
||||||
divider: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: (
|
|
||||||
<FormattedMessage id="label.last-days" defaultMessage="Last {x} days" values={{ x: 7 }} />
|
|
||||||
),
|
|
||||||
value: '7day',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: <FormattedMessage id="label.this-month" defaultMessage="This month" />,
|
|
||||||
value: '1month',
|
|
||||||
divider: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: (
|
|
||||||
<FormattedMessage id="label.last-days" defaultMessage="Last {x} days" values={{ x: 30 }} />
|
|
||||||
),
|
|
||||||
value: '30day',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: (
|
|
||||||
<FormattedMessage id="label.last-days" defaultMessage="Last {x} days" values={{ x: 90 }} />
|
|
||||||
),
|
|
||||||
value: '90day',
|
|
||||||
},
|
|
||||||
{ label: <FormattedMessage id="label.this-year" defaultMessage="This year" />, value: '1year' },
|
|
||||||
{
|
|
||||||
label: <FormattedMessage id="label.all-time" defaultMessage="All time" />,
|
|
||||||
value: 'all',
|
|
||||||
divider: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: <FormattedMessage id="label.custom-range" defaultMessage="Custom range" />,
|
|
||||||
value: 'custom',
|
|
||||||
divider: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function DateFilter({ value, startDate, endDate, onChange, className, options }) {
|
function DateFilter({ value, startDate, endDate, onChange, className }) {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
const [showPicker, setShowPicker] = useState(false);
|
const [showPicker, setShowPicker] = useState(false);
|
||||||
const displayValue =
|
|
||||||
value === 'custom' ? (
|
const options = [
|
||||||
|
{ label: formatMessage(messages.today), value: '1day' },
|
||||||
|
{
|
||||||
|
label: formatMessage(messages.lastHours, { x: 24 }),
|
||||||
|
value: '24hour',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: formatMessage(messages.yesterday),
|
||||||
|
value: '-1day',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: formatMessage(messages.thisWeek),
|
||||||
|
value: '1week',
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: formatMessage(messages.lastDays, { x: 7 }),
|
||||||
|
value: '7day',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: formatMessage(messages.thisMonth),
|
||||||
|
value: '1month',
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: formatMessage(messages.lastDays, { x: 30 }),
|
||||||
|
value: '30day',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: formatMessage(messages.lastDays, { x: 90 }),
|
||||||
|
value: '90day',
|
||||||
|
},
|
||||||
|
{ label: formatMessage(messages.thisYear), value: '1year' },
|
||||||
|
{
|
||||||
|
label: formatMessage(messages.allTime),
|
||||||
|
value: 'all',
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: formatMessage(messages.customRange),
|
||||||
|
value: 'custom',
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const renderValue = value => {
|
||||||
|
return value === 'custom' ? (
|
||||||
<CustomRange startDate={startDate} endDate={endDate} onClick={() => handleChange('custom')} />
|
<CustomRange startDate={startDate} endDate={endDate} onClick={() => handleChange('custom')} />
|
||||||
) : (
|
) : (
|
||||||
value
|
options.find(e => e.value === value).label
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
async function handleChange(value) {
|
const handleChange = async value => {
|
||||||
if (value === 'custom') {
|
if (value === 'custom') {
|
||||||
setShowPicker(true);
|
setShowPicker(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onChange(value);
|
onChange(value);
|
||||||
}
|
};
|
||||||
|
|
||||||
function handlePickerChange(value) {
|
const handlePickerChange = value => {
|
||||||
setShowPicker(false);
|
setShowPicker(false);
|
||||||
onChange(value);
|
onChange(value);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const handleClose = () => setShowPicker(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DropDown
|
<Dropdown
|
||||||
className={className}
|
className={className}
|
||||||
value={displayValue}
|
items={options}
|
||||||
options={options || filterOptions}
|
renderValue={renderValue}
|
||||||
|
value={value}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
>
|
||||||
|
{({ label, value }) => <Item key={value}>{label}</Item>}
|
||||||
|
</Dropdown>
|
||||||
{showPicker && (
|
{showPicker && (
|
||||||
<Modal>
|
<Modal onClose={handleClose}>
|
||||||
<DatePickerForm
|
<DatePickerForm
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
@ -128,12 +138,4 @@ const CustomRange = ({ startDate, endDate, onClick }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
DateFilter.propTypes = {
|
|
||||||
value: PropTypes.string,
|
|
||||||
startDate: PropTypes.instanceOf(Date),
|
|
||||||
endDate: PropTypes.instanceOf(Date),
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
className: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default DateFilter;
|
export default DateFilter;
|
||||||
|
@ -66,8 +66,9 @@ export default function WebsiteChart({
|
|||||||
|
|
||||||
async function handleDateChange(value) {
|
async function handleDateChange(value) {
|
||||||
if (value === 'all') {
|
if (value === 'all') {
|
||||||
const { data, ok } = await get(`/websites/${websiteId}`);
|
const data = await get(`/websites/${websiteId}`);
|
||||||
if (ok) {
|
|
||||||
|
if (data) {
|
||||||
setDateRange({ value, ...getDateRangeValues(new Date(data.createdAt), Date.now()) });
|
setDateRange({ value, ...getDateRangeValues(new Date(data.createdAt), Date.now()) });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import User from 'assets/user.svg';
|
|
||||||
import Team from 'assets/users.svg';
|
|
||||||
import Website from 'assets/website.svg';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { Icon, Item, Menu, Text } from 'react-basics';
|
import { Icon, Item, Menu, Text } from 'react-basics';
|
||||||
import styles from './Nav.module.css';
|
|
||||||
import useUser from 'hooks/useUser';
|
import useUser from 'hooks/useUser';
|
||||||
|
import User from 'assets/user.svg';
|
||||||
|
import Team from 'assets/users.svg';
|
||||||
|
import Website from 'assets/website.svg';
|
||||||
|
import Profile from 'assets/profile.svg';
|
||||||
|
import styles from './Nav.module.css';
|
||||||
|
|
||||||
export default function Nav() {
|
export default function Nav() {
|
||||||
const user = useUser();
|
const user = useUser();
|
||||||
@ -22,7 +23,7 @@ export default function Nav() {
|
|||||||
{ icon: <Website />, label: 'Websites', url: '/settings/websites' },
|
{ icon: <Website />, label: 'Websites', url: '/settings/websites' },
|
||||||
{ icon: <User />, label: 'Users', url: '/settings/users' },
|
{ icon: <User />, label: 'Users', url: '/settings/users' },
|
||||||
{ icon: <Team />, label: 'Teams', url: '/settings/teams' },
|
{ icon: <Team />, label: 'Teams', url: '/settings/teams' },
|
||||||
{ icon: <User />, label: 'Profile', url: '/settings/profile' },
|
{ icon: <Profile />, label: 'Profile', url: '/settings/profile' },
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item a {
|
.item a {
|
||||||
color: var(--base700);
|
color: var(--base600);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
@ -42,5 +42,4 @@
|
|||||||
|
|
||||||
.item.selected a {
|
.item.selected a {
|
||||||
color: var(--base900);
|
color: var(--base900);
|
||||||
background: var(--base100);
|
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,12 @@ import Page from 'components/layout/Page';
|
|||||||
import PageHeader from 'components/layout/PageHeader';
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
import ProfileDetails from 'components/settings/ProfileDetails';
|
import ProfileDetails from 'components/settings/ProfileDetails';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Breadcrumbs, Icon, Item, Tabs, useToast, Modal, Button } from 'react-basics';
|
import { Breadcrumbs, Icon, Item, useToast, Modal, Button } from 'react-basics';
|
||||||
import UserPasswordForm from 'components/pages/settings/users/UserPasswordForm';
|
import UserPasswordForm from 'components/pages/settings/users/UserPasswordForm';
|
||||||
import Pen from 'assets/pen.svg';
|
import Lock from 'assets/lock.svg';
|
||||||
|
|
||||||
export default function ProfileSettings() {
|
export default function ProfileSettings() {
|
||||||
const [edit, setEdit] = useState(false);
|
const [edit, setEdit] = useState(false);
|
||||||
const [tab, setTab] = useState('general');
|
|
||||||
const { toast, showToast } = useToast();
|
const { toast, showToast } = useToast();
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
@ -33,17 +32,14 @@ export default function ProfileSettings() {
|
|||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
<Button onClick={handleAdd}>
|
<Button onClick={handleAdd}>
|
||||||
<Icon>
|
<Icon>
|
||||||
<Pen />
|
<Lock />
|
||||||
</Icon>
|
</Icon>
|
||||||
Change Password
|
Change Password
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<Tabs selectedKey={tab} onSelect={setTab} style={{ marginBottom: 30, fontSize: 14 }}>
|
<ProfileDetails />
|
||||||
<Item key="general">General</Item>
|
|
||||||
</Tabs>
|
|
||||||
{tab === 'general' && <ProfileDetails />}
|
|
||||||
{edit && (
|
{edit && (
|
||||||
<Modal title="Add website" onClose={handleClose}>
|
<Modal title="Change password" onClose={handleClose}>
|
||||||
{close => <UserPasswordForm onSave={handleSave} onClose={close} />}
|
{close => <UserPasswordForm onSave={handleSave} onClose={close} />}
|
||||||
</Modal>
|
</Modal>
|
||||||
)}
|
)}
|
||||||
|
@ -12,7 +12,6 @@ import { useRef } from 'react';
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import useApi from 'hooks/useApi';
|
import useApi from 'hooks/useApi';
|
||||||
import { ROLES } from 'lib/constants';
|
import { ROLES } from 'lib/constants';
|
||||||
import styles from './UserForm.module.css';
|
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
@ -41,14 +40,7 @@ export default function UserEditForm({ data, onSave }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form key={id} ref={ref} onSubmit={handleSubmit} error={error} values={data}>
|
||||||
key={id}
|
|
||||||
className={styles.form}
|
|
||||||
ref={ref}
|
|
||||||
onSubmit={handleSubmit}
|
|
||||||
error={error}
|
|
||||||
values={data}
|
|
||||||
>
|
|
||||||
<FormRow label="Username">
|
<FormRow label="Username">
|
||||||
<FormInput name="username">
|
<FormInput name="username">
|
||||||
<TextField />
|
<TextField />
|
||||||
|
@ -1,30 +1,28 @@
|
|||||||
import { FormattedMessage } from 'react-intl';
|
import { useIntl, defineMessages } from 'react-intl';
|
||||||
import DropDown from 'components/common/DropDown';
|
import { Button, Dropdown, Item, Flexbox } from 'react-basics';
|
||||||
import { Button } from 'react-basics';
|
|
||||||
import useLocale from 'hooks/useLocale';
|
import useLocale from 'hooks/useLocale';
|
||||||
import { DEFAULT_LOCALE } from 'lib/constants';
|
import { DEFAULT_LOCALE } from 'lib/constants';
|
||||||
import styles from './TimezoneSetting.module.css';
|
|
||||||
import { languages } from 'lib/lang';
|
import { languages } from 'lib/lang';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
reset: { id: 'label.reset', defaultMessage: 'Reset' },
|
||||||
|
});
|
||||||
|
|
||||||
export default function LanguageSetting() {
|
export default function LanguageSetting() {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
const { locale, saveLocale } = useLocale();
|
const { locale, saveLocale } = useLocale();
|
||||||
const options = Object.keys(languages).map(key => ({ ...languages[key], value: key }));
|
const options = Object.keys(languages);
|
||||||
|
|
||||||
function handleReset() {
|
function handleReset() {
|
||||||
saveLocale(DEFAULT_LOCALE);
|
saveLocale(DEFAULT_LOCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Flexbox gap={10} style={{ width: 400 }}>
|
||||||
<DropDown
|
<Dropdown items={options} value={locale} onChange={saveLocale}>
|
||||||
menuClassName={styles.menu}
|
{item => <Item key={item}>{languages[item].label}</Item>}
|
||||||
value={locale}
|
</Dropdown>
|
||||||
options={options}
|
<Button onClick={handleReset}>{formatMessage(messages.reset)}</Button>
|
||||||
onChange={saveLocale}
|
</Flexbox>
|
||||||
/>
|
|
||||||
<Button className={styles.button} size="sm" onClick={handleReset}>
|
|
||||||
<FormattedMessage id="label.reset" defaultMessage="Reset" />
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,46 @@
|
|||||||
|
import { Form, FormRow } from 'react-basics';
|
||||||
|
import { useIntl, defineMessages } from 'react-intl';
|
||||||
import TimezoneSetting from 'components/settings/TimezoneSetting';
|
import TimezoneSetting from 'components/settings/TimezoneSetting';
|
||||||
|
import DateRangeSetting from 'components/settings/DateRangeSetting';
|
||||||
|
import LanguageSetting from 'components/settings/LanguageSetting';
|
||||||
|
import ThemeSetting from 'components/settings/ThemeSetting';
|
||||||
import useUser from 'hooks/useUser';
|
import useUser from 'hooks/useUser';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
const messages = defineMessages({
|
||||||
import DateRangeSetting from './DateRangeSetting';
|
username: { id: 'label.username', defaultMessage: 'Username' },
|
||||||
import LanguageSetting from './LanguageSetting';
|
role: { id: 'label.role', defaultMessage: 'Role' },
|
||||||
import styles from './ProfileDetails.module.css';
|
timezone: { id: 'label.timezone', defaultMessage: 'Timezone' },
|
||||||
import ThemeSetting from './ThemeSetting';
|
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() {
|
export default function ProfileDetails() {
|
||||||
const user = useUser();
|
const user = useUser();
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { username } = user;
|
const { username, role } = user;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Form>
|
||||||
<dl className={styles.list}>
|
<FormRow label={formatMessage(messages.username)}>{username}</FormRow>
|
||||||
<dt>
|
<FormRow label={formatMessage(messages.role)}>{role}</FormRow>
|
||||||
<FormattedMessage id="label.username" defaultMessage="Username" />
|
<FormRow label={formatMessage(messages.language)} inline>
|
||||||
</dt>
|
<LanguageSetting />
|
||||||
<dd>{username}</dd>
|
</FormRow>
|
||||||
<dt>
|
<FormRow label={formatMessage(messages.timezone)} inline>
|
||||||
<FormattedMessage id="label.timezone" defaultMessage="Timezone" />
|
<TimezoneSetting />
|
||||||
</dt>
|
</FormRow>
|
||||||
<dd>
|
<FormRow label={formatMessage(messages.dateRange)} inline>
|
||||||
<TimezoneSetting />
|
<DateRangeSetting />
|
||||||
</dd>
|
</FormRow>
|
||||||
<dt>
|
<FormRow label={formatMessage(messages.theme)}>
|
||||||
<FormattedMessage id="label.default-date-range" defaultMessage="Default date range" />
|
<ThemeSetting />
|
||||||
</dt>
|
</FormRow>
|
||||||
<dd>
|
</Form>
|
||||||
<DateRangeSetting />
|
|
||||||
</dd>
|
|
||||||
<dt>
|
|
||||||
<FormattedMessage id="label.language" defaultMessage="Language" />
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<LanguageSetting />
|
|
||||||
</dd>
|
|
||||||
<dt>
|
|
||||||
<FormattedMessage id="label.theme" defaultMessage="Theme" />
|
|
||||||
</dt>
|
|
||||||
<dd>
|
|
||||||
<ThemeSetting />
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import { FormattedMessage } from 'react-intl';
|
import { Dropdown, Item, Button } from 'react-basics';
|
||||||
|
import { useIntl, defineMessages } from 'react-intl';
|
||||||
import { listTimeZones } from 'timezone-support';
|
import { listTimeZones } from 'timezone-support';
|
||||||
import DropDown from 'components/common/DropDown';
|
|
||||||
import { Button } from 'react-basics';
|
|
||||||
import useTimezone from 'hooks/useTimezone';
|
import useTimezone from 'hooks/useTimezone';
|
||||||
import { getTimezone } from 'lib/date';
|
import { getTimezone } from 'lib/date';
|
||||||
import styles from './TimezoneSetting.module.css';
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
reset: { id: 'label.reset', defaultMessage: 'Reset' },
|
||||||
|
});
|
||||||
|
|
||||||
export default function TimezoneSetting() {
|
export default function TimezoneSetting() {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
const [timezone, saveTimezone] = useTimezone();
|
const [timezone, saveTimezone] = useTimezone();
|
||||||
const options = listTimeZones().map(n => ({ label: n, value: n }));
|
const options = listTimeZones();
|
||||||
|
|
||||||
function handleReset() {
|
function handleReset() {
|
||||||
saveTimezone(getTimezone());
|
saveTimezone(getTimezone());
|
||||||
@ -16,15 +19,10 @@ export default function TimezoneSetting() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DropDown
|
<Dropdown items={options} value={timezone} onChange={saveTimezone}>
|
||||||
menuClassName={styles.menu}
|
{item => <Item key={item}>{item}</Item>}
|
||||||
value={timezone}
|
</Dropdown>
|
||||||
options={options}
|
<Button onClick={handleReset}>{formatMessage(messages.reset)}</Button>
|
||||||
onChange={saveTimezone}
|
|
||||||
/>
|
|
||||||
<Button className={styles.button} size="sm" onClick={handleReset}>
|
|
||||||
<FormattedMessage id="label.reset" defaultMessage="Reset" />
|
|
||||||
</Button>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
.menu {
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
import User from 'assets/user.svg';
|
|
||||||
import useConfig from 'hooks/useConfig';
|
import useConfig from 'hooks/useConfig';
|
||||||
import useUser from 'hooks/useUser';
|
import useUser from 'hooks/useUser';
|
||||||
import { AUTH_TOKEN } from 'lib/constants';
|
import { AUTH_TOKEN } from 'lib/constants';
|
||||||
@ -7,8 +6,9 @@ import { useRouter } from 'next/router';
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { Button, Icon, Item, Menu, Popup, Text } from 'react-basics';
|
import { Button, Icon, Item, Menu, Popup, Text } from 'react-basics';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import useDocumentClick from 'hooks/useDocumentClick';
|
||||||
|
import Profile from 'assets/profile.svg';
|
||||||
import styles from './UserButton.module.css';
|
import styles from './UserButton.module.css';
|
||||||
import useDocumentClick from '../../hooks/useDocumentClick';
|
|
||||||
|
|
||||||
export default function UserButton() {
|
export default function UserButton() {
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
@ -61,7 +61,7 @@ export default function UserButton() {
|
|||||||
<div className={styles.button} ref={ref}>
|
<div className={styles.button} ref={ref}>
|
||||||
<Button variant="light" onClick={handleClick}>
|
<Button variant="light" onClick={handleClick}>
|
||||||
<Icon className={styles.icon} size="large">
|
<Icon className={styles.icon} size="large">
|
||||||
<User />
|
<Profile />
|
||||||
</Icon>
|
</Icon>
|
||||||
</Button>
|
</Button>
|
||||||
{show && (
|
{show && (
|
||||||
|
@ -12,9 +12,9 @@ export default function useCountryNames(locale) {
|
|||||||
const { basePath } = useRouter();
|
const { basePath } = useRouter();
|
||||||
|
|
||||||
async function loadData(locale) {
|
async function loadData(locale) {
|
||||||
const { ok, data } = await get(`${basePath}/intl/country/${locale}.json`);
|
const data = await get(`${basePath}/intl/country/${locale}.json`);
|
||||||
|
|
||||||
if (ok) {
|
if (data) {
|
||||||
countryNames[locale] = data;
|
countryNames[locale] = data;
|
||||||
setList(countryNames[locale]);
|
setList(countryNames[locale]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -12,9 +12,9 @@ export default function useLanguageNames(locale) {
|
|||||||
const { basePath } = useRouter();
|
const { basePath } = useRouter();
|
||||||
|
|
||||||
async function loadData(locale) {
|
async function loadData(locale) {
|
||||||
const { ok, data } = await get(`${basePath}/intl/language/${locale}.json`);
|
const data = await get(`${basePath}/intl/language/${locale}.json`);
|
||||||
|
|
||||||
if (ok) {
|
if (data) {
|
||||||
languageNames[locale] = data;
|
languageNames[locale] = data;
|
||||||
setList(languageNames[locale]);
|
setList(languageNames[locale]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -21,9 +21,9 @@ export default function useLocale() {
|
|||||||
const dateLocale = getDateLocale(locale);
|
const dateLocale = getDateLocale(locale);
|
||||||
|
|
||||||
async function loadMessages(locale) {
|
async function loadMessages(locale) {
|
||||||
const { ok, data } = await get(`${basePath}/intl/messages/${locale}.json`);
|
const data = await get(`${basePath}/intl/messages/${locale}.json`);
|
||||||
|
|
||||||
if (ok) {
|
if (data) {
|
||||||
messages[locale] = data;
|
messages[locale] = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,13 @@ import 'styles/index.css';
|
|||||||
import '@fontsource/inter/400.css';
|
import '@fontsource/inter/400.css';
|
||||||
import '@fontsource/inter/600.css';
|
import '@fontsource/inter/600.css';
|
||||||
|
|
||||||
const client = new QueryClient();
|
const client = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
refetchOnWindowFocus: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export default function App({ Component, pageProps }) {
|
export default function App({ Component, pageProps }) {
|
||||||
const { locale, messages } = useLocale();
|
const { locale, messages } = useLocale();
|
||||||
|
Loading…
Reference in New Issue
Block a user