Refactored intl messages.

This commit is contained in:
Mike Cao 2023-01-25 07:42:46 -08:00
parent fbccf4d3af
commit 7725b5c129
44 changed files with 558 additions and 485 deletions

View file

@ -1,10 +1,12 @@
import { FormattedMessage } from 'react-intl';
import { useIntl } 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';
import { labels } from 'components/messages';
export default function DateRangeSetting() {
const { formatMessage } = useIntl();
const [dateRange, setDateRange] = useDateRange();
const { startDate, endDate, value } = dateRange;
@ -13,9 +15,7 @@ export default function DateRangeSetting() {
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>
<Button onClick={handleReset}>{formatMessage(labels.reset)}</Button>
</Flexbox>
);
}

View file

@ -1,12 +1,9 @@
import { useIntl, defineMessages } from 'react-intl';
import { useIntl } 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' },
});
import { labels } from 'components/messages';
export default function LanguageSetting() {
const { formatMessage } = useIntl();
@ -28,7 +25,7 @@ export default function LanguageSetting() {
>
{item => <Item key={item}>{languages[item].label}</Item>}
</Dropdown>
<Button onClick={handleReset}>{formatMessage(messages.reset)}</Button>
<Button onClick={handleReset}>{formatMessage(labels.reset)}</Button>
</Flexbox>
);
}

View file

@ -1,46 +1,29 @@
import { useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { Button, Icon, Text, Modal, useToast } from 'react-basics';
import { useIntl } from 'react-intl';
import { Button, Icon, Text, useToast, ModalTrigger } from 'react-basics';
import PasswordEditForm from 'components/pages/settings/profile/PasswordEditForm';
import { Lock } from 'components/icons';
const messages = defineMessages({
changePassword: { id: 'label.change-password', defaultMessage: 'Change password' },
saved: { id: 'message.saved-successfully', defaultMessage: 'Saved successfully.' },
});
import { labels, messages } from 'components/messages';
export default function PasswordChangeButton() {
const { formatMessage } = useIntl();
const [edit, setEdit] = useState(false);
const { toast, showToast } = useToast();
const handleSave = () => {
showToast({ message: formatMessage(messages.saved), variant: 'success' });
setEdit(false);
};
const handleEdit = () => {
setEdit(true);
};
const handleClose = () => {
setEdit(false);
};
return (
<>
{toast}
<Button onClick={handleEdit}>
<Icon>
<Lock />
</Icon>
<Text>{formatMessage(messages.changePassword)}</Text>
</Button>
{edit && (
<Modal title={formatMessage(messages.changePassword)} onClose={handleClose}>
{() => <PasswordEditForm onSave={handleSave} onClose={handleClose} />}
</Modal>
)}
<ModalTrigger modalProps={{ title: formatMessage(labels.changePassword) }}>
<Button>
<Icon>
<Lock />
</Icon>
<Text>{formatMessage(labels.changePassword)}</Text>
</Button>
{close => <PasswordEditForm onSave={handleSave} onClose={close} />}
</ModalTrigger>
</>
);
}

View file

@ -1,75 +1,65 @@
import { useRef } from 'react';
import { Form, FormRow, FormInput, FormButtons, PasswordField, Button } from 'react-basics';
import { useIntl } from 'react-intl';
import useApi from 'hooks/useApi';
import useUser from 'hooks/useUser';
import { labels, messages } from 'components/messages';
export default function PasswordEditForm({ userId, onSave, onClose }) {
const user = useUser();
const isCurrentUser = !userId || user?.id === userId;
const url = isCurrentUser ? `/users/${user?.id}/password` : `/users/${user?.id}`;
export default function PasswordEditForm({ onSave, onClose }) {
const { formatMessage } = useIntl();
const { post, useMutation } = useApi();
const { mutate, error, isLoading } = useMutation(data => post(url, data));
const { mutate, error, isLoading } = useMutation(data => post('/me/password', data));
const ref = useRef(null);
const handleSubmit = async data => {
const payload = isCurrentUser
? data
: {
password: data.newPassword,
};
mutate(payload, {
mutate(data, {
onSuccess: async () => {
onSave();
ref.current.reset();
},
});
};
const samePassword = value => {
if (value !== ref?.current?.getValues('newPassword')) {
return "Passwords don't match";
return formatMessage(messages.noMatchPassword);
}
return true;
};
return (
<Form ref={ref} onSubmit={handleSubmit} error={error}>
{isCurrentUser && (
<FormRow label="Current password">
<FormInput name="currentPassword" rules={{ required: 'Required' }}>
<PasswordField autoComplete="off" />
</FormInput>
</FormRow>
)}
<FormRow label="New password">
<FormRow label={formatMessage(labels.currentPassword)}>
<FormInput name="currentPassword" rules={{ required: 'Required' }}>
<PasswordField autoComplete="current-password" />
</FormInput>
</FormRow>
<FormRow label={formatMessage(labels.newPassword)}>
<FormInput
name="newPassword"
rules={{
required: 'Required',
minLength: { value: 8, message: 'Minimum length 8 characters' },
minLength: { value: 8, message: formatMessage(messages.minPasswordLength) },
}}
>
<PasswordField autoComplete="off" />
<PasswordField autoComplete="new-password" />
</FormInput>
</FormRow>
<FormRow label="Confirm password">
<FormRow label={formatMessage(labels.confirmPassword)}>
<FormInput
name="confirmPassword"
rules={{
required: 'Required',
minLength: { value: 8, message: 'Minimum length 8 characters' },
required: formatMessage(labels.required),
minLength: { value: 8, message: formatMessage(messages.minPasswordLength) },
validate: samePassword,
}}
>
<PasswordField autoComplete="off" />
<PasswordField autoComplete="confirm-password" />
</FormInput>
</FormRow>
<FormButtons flex>
<Button type="submit" variant="primary" disabled={isLoading}>
Save
{formatMessage(labels.save)}
</Button>
<Button onClick={onClose}>Close</Button>
<Button onClick={onClose}>{formatMessage(labels.cancel)}</Button>
</FormButtons>
</Form>
);

View file

@ -1,19 +1,11 @@
import { Form, FormRow } from 'react-basics';
import { useIntl, defineMessages } from 'react-intl';
import { useIntl } 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' },
});
import { labels } from 'components/messages';
export default function ProfileDetails() {
const { user } = useUser();
@ -27,18 +19,18 @@ export default function ProfileDetails() {
return (
<Form>
<FormRow label={formatMessage(messages.username)}>{username}</FormRow>
<FormRow label={formatMessage(messages.role)}>{role}</FormRow>
<FormRow label={formatMessage(messages.language)} inline>
<FormRow label={formatMessage(labels.username)}>{username}</FormRow>
<FormRow label={formatMessage(labels.role)}>{role}</FormRow>
<FormRow label={formatMessage(labels.language)} inline>
<LanguageSetting />
</FormRow>
<FormRow label={formatMessage(messages.timezone)} inline>
<FormRow label={formatMessage(labels.timezone)} inline>
<TimezoneSetting />
</FormRow>
<FormRow label={formatMessage(messages.dateRange)} inline>
<FormRow label={formatMessage(labels.dateRange)} inline>
<DateRangeSetting />
</FormRow>
<FormRow label={formatMessage(messages.theme)}>
<FormRow label={formatMessage(labels.theme)}>
<ThemeSetting />
</FormRow>
</Form>

View file

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

View file

@ -1,13 +1,10 @@
import { Breadcrumbs, Item } from 'react-basics';
import { defineMessages, useIntl } from 'react-intl';
import { useIntl } from 'react-intl';
import Page from 'components/layout/Page';
import PageHeader from 'components/layout/PageHeader';
import ProfileDetails from './ProfileDetails';
import PasswordChangeButton from './PasswordChangeButton';
const messages = defineMessages({
profile: { id: 'label.profile', defaultMessage: 'Profile' },
});
import { labels } from 'components/messages';
export default function ProfileSettings() {
const { formatMessage } = useIntl();
@ -16,7 +13,7 @@ export default function ProfileSettings() {
<Page>
<PageHeader>
<Breadcrumbs>
<Item>{formatMessage(messages.profile)}</Item>
<Item>{formatMessage(labels.profile)}</Item>
</Breadcrumbs>
<PasswordChangeButton />
</PageHeader>

View file

@ -1,12 +1,9 @@
import { Dropdown, Item, Button, Flexbox } from 'react-basics';
import { useIntl, defineMessages } from 'react-intl';
import { useIntl } 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' },
});
import { labels } from 'components/messages';
export default function TimezoneSetting() {
const { formatMessage } = useIntl();
@ -25,7 +22,7 @@ export default function TimezoneSetting() {
>
{item => <Item key={item}>{item}</Item>}
</Dropdown>
<Button onClick={handleReset}>{formatMessage(messages.reset)}</Button>
<Button onClick={handleReset}>{formatMessage(labels.reset)}</Button>
</Flexbox>
);
}