diff --git a/app/soapbox/actions/compose.js b/app/soapbox/actions/compose.js index 1d16fe554..efef9c786 100644 --- a/app/soapbox/actions/compose.js +++ b/app/soapbox/actions/compose.js @@ -83,7 +83,7 @@ export const COMPOSE_SET_STATUS = 'COMPOSE_SET_STATUS'; const messages = defineMessages({ exceededImageSizeLimit: { id: 'upload_error.image_size_limit', defaultMessage: 'Image exceeds the current file size limit ({limit})' }, exceededVideoSizeLimit: { id: 'upload_error.video_size_limit', defaultMessage: 'Video exceeds the current file size limit ({limit})' }, - scheduleError: { id: 'compose.invalid_schedule', defaultMessage: 'You must schedule a post at least 5 minutes out.' }, + scheduleError: { id: 'compose.invalid_schedule', defaultMessage: 'You must schedule a post at least 5 minutes out.' }, success: { id: 'compose.submit_success', defaultMessage: 'Your post was sent' }, uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' }, uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, diff --git a/app/soapbox/components/badge.tsx b/app/soapbox/components/badge.tsx index 2eb2d221d..c14a58d56 100644 --- a/app/soapbox/components/badge.tsx +++ b/app/soapbox/components/badge.tsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import React from 'react'; interface IBadge { - title: string, + title: string | React.ReactNode, slug: 'patron' | 'donor' | 'admin' | 'moderator' | 'bot' | 'opaque', } diff --git a/app/soapbox/components/media_gallery.js b/app/soapbox/components/media_gallery.js index 30ddbbc34..44b08a3df 100644 --- a/app/soapbox/components/media_gallery.js +++ b/app/soapbox/components/media_gallery.js @@ -614,12 +614,12 @@ class MediaGallery extends React.PureComponent {
{warning} - {intl.formatMessage({ id: 'status.sensitive_warning.subtitle', defaultMessage: 'This content may not be suitable for all audiences.' })} +
diff --git a/app/soapbox/components/profile-hover-card.tsx b/app/soapbox/components/profile-hover-card.tsx index 8511839fb..9c9f2e79a 100644 --- a/app/soapbox/components/profile-hover-card.tsx +++ b/app/soapbox/components/profile-hover-card.tsx @@ -1,6 +1,6 @@ import classNames from 'classnames'; import React, { useEffect, useState } from 'react'; -import { useIntl } from 'react-intl'; +import { FormattedMessage } from 'react-intl'; import { usePopper } from 'react-popper'; import { useHistory } from 'react-router-dom'; @@ -64,7 +64,6 @@ interface IProfileHoverCard { export const ProfileHoverCard: React.FC = ({ visible = true }) => { const dispatch = useAppDispatch(); const history = useHistory(); - const intl = useIntl(); const [popperElement, setPopperElement] = useState(null); @@ -130,7 +129,7 @@ export const ProfileHoverCard: React.FC = ({ visible = true }
} />
)} diff --git a/app/soapbox/components/status.tsx b/app/soapbox/components/status.tsx index 9bcc772ee..141394420 100644 --- a/app/soapbox/components/status.tsx +++ b/app/soapbox/components/status.tsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import React from 'react'; import { HotKeys } from 'react-hotkeys'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { injectIntl, FormattedMessage, IntlShape } from 'react-intl'; +import { injectIntl, FormattedMessage, IntlShape, defineMessages } from 'react-intl'; import { NavLink, withRouter, RouteComponentProps } from 'react-router-dom'; import Icon from 'soapbox/components/icon'; @@ -31,6 +31,10 @@ import type { // Defined in components/scrollable_list export type ScrollPosition = { height: number, top: number }; +const messages = defineMessages({ + reblogged_by: { id: 'status.reblogged_by', defaultMessage: '{name} reposted' }, +}); + export const textForScreenReader = (intl: IntlShape, status: StatusEntity, rebloggedByText?: string): string => { const { account } = status; if (!account || typeof account !== 'object') return ''; @@ -437,12 +441,10 @@ class Status extends ImmutablePureComponent { ); - rebloggedByText = intl.formatMessage({ - id: 'status.reblogged_by', - defaultMessage: '{name} reposted', - }, { - name: String(status.getIn(['account', 'acct'])), - }); + rebloggedByText = intl.formatMessage( + messages.reblogged_by, + { name: String(status.getIn(['account', 'acct'])) }, + ); // @ts-ignore what the FUCK account = status.account; diff --git a/app/soapbox/components/status_list.js b/app/soapbox/components/status_list.js index bfc90869e..5d08ab1a2 100644 --- a/app/soapbox/components/status_list.js +++ b/app/soapbox/components/status_list.js @@ -102,7 +102,7 @@ export default class StatusList extends ImmutablePureComponent { } renderLoadGap(index) { - const { statusIds, onLoadMore, isLoading } = this.props; + const { statusIds, onLoadMore, isLoading } = this.props; return ( ( @@ -164,7 +164,7 @@ export default class StatusList extends ImmutablePureComponent { } renderStatuses() { - const { statusIds, isLoading } = this.props; + const { statusIds, isLoading } = this.props; if (isLoading || statusIds.size > 0) { return statusIds.map((statusId, index) => { @@ -193,7 +193,7 @@ export default class StatusList extends ImmutablePureComponent { } render() { - const { statusIds, divideType, featuredStatusIds, onLoadMore, timelineId, totalQueuedItemsCount, isLoading, isPartial, withGroupAdmin, group, ...other } = this.props; + const { statusIds, divideType, featuredStatusIds, onLoadMore, timelineId, totalQueuedItemsCount, isLoading, isPartial, withGroupAdmin, group, ...other } = this.props; if (isPartial) { return ( diff --git a/app/soapbox/features/account/components/header.js b/app/soapbox/features/account/components/header.js index 7a65b0bef..b6fe013a7 100644 --- a/app/soapbox/features/account/components/header.js +++ b/app/soapbox/features/account/components/header.js @@ -6,7 +6,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl } from 'react-intl'; +import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; @@ -457,7 +457,7 @@ class Header extends ImmutablePureComponent { } makeInfo() { - const { account, intl, me } = this.props; + const { account, me } = this.props; const info = []; @@ -468,7 +468,7 @@ class Header extends ImmutablePureComponent { } />, ); } else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) { @@ -476,7 +476,7 @@ class Header extends ImmutablePureComponent { } />, ); } @@ -486,7 +486,7 @@ class Header extends ImmutablePureComponent { } />, ); } else if (me !== account.get('id') && account.getIn(['relationship', 'domain_blocking'])) { @@ -494,7 +494,7 @@ class Header extends ImmutablePureComponent { } />, ); } diff --git a/app/soapbox/features/admin/components/unapproved_account.tsx b/app/soapbox/features/admin/components/unapproved_account.tsx index 5f38684cb..ffd76fc30 100644 --- a/app/soapbox/features/admin/components/unapproved_account.tsx +++ b/app/soapbox/features/admin/components/unapproved_account.tsx @@ -2,13 +2,12 @@ import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { approveUsers } from 'soapbox/actions/admin'; +import { rejectUserModal } from 'soapbox/actions/moderation'; import snackbar from 'soapbox/actions/snackbar'; import IconButton from 'soapbox/components/icon_button'; import { useAppSelector, useAppDispatch } from 'soapbox/hooks'; import { makeGetAccount } from 'soapbox/selectors'; -import { rejectUserModal } from '../../../actions/moderation'; - const messages = defineMessages({ approved: { id: 'admin.awaiting_approval.approved_message', defaultMessage: '{acct} was approved!' }, rejected: { id: 'admin.awaiting_approval.rejected_message', defaultMessage: '{acct} was rejected.' }, diff --git a/app/soapbox/features/auth_login/components/login_form.tsx b/app/soapbox/features/auth_login/components/login_form.tsx index dd125b568..64145453c 100644 --- a/app/soapbox/features/auth_login/components/login_form.tsx +++ b/app/soapbox/features/auth_login/components/login_form.tsx @@ -26,7 +26,7 @@ const LoginForm: React.FC = ({ isLoading, handleSubmit }) => { return (
-

{intl.formatMessage({ id: 'login_form.header', defaultMessage: 'Sign In' })}

+

diff --git a/app/soapbox/features/auth_login/components/otp_auth_form.js b/app/soapbox/features/auth_login/components/otp_auth_form.js index 637f78529..0446a7afe 100644 --- a/app/soapbox/features/auth_login/components/otp_auth_form.js +++ b/app/soapbox/features/auth_login/components/otp_auth_form.js @@ -11,6 +11,7 @@ import { Button, Form, FormActions, FormGroup, Input } from 'soapbox/components/ const messages = defineMessages({ otpCodeHint: { id: 'login.fields.otp_code_hint', defaultMessage: 'Enter the two-factor code generated by your phone app or use one of your recovery codes' }, otpCodeLabel: { id: 'login.fields.otp_code_label', defaultMessage: 'Two-factor code:' }, + otpLoginFail: { id: 'login.otp_log_in.fail', defaultMessage: 'Invalid code, please try again.' }, }); export default @connect() @@ -70,7 +71,7 @@ class OtpAuthForm extends ImmutablePureComponent {

- {intl.formatMessage({ id: 'password_reset.header', defaultMessage: 'Reset Password' })} +

diff --git a/app/soapbox/features/auth_login/components/password_reset_confirm.js b/app/soapbox/features/auth_login/components/password_reset_confirm.tsx similarity index 74% rename from app/soapbox/features/auth_login/components/password_reset_confirm.js rename to app/soapbox/features/auth_login/components/password_reset_confirm.tsx index 4d6372a48..2f30e700f 100644 --- a/app/soapbox/features/auth_login/components/password_reset_confirm.js +++ b/app/soapbox/features/auth_login/components/password_reset_confirm.tsx @@ -1,14 +1,17 @@ -import PropTypes from 'prop-types'; import * as React from 'react'; -import { FormattedMessage, injectIntl, useIntl } from 'react-intl'; -import { connect } from 'react-redux'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { Redirect } from 'react-router-dom'; import { resetPasswordConfirm } from 'soapbox/actions/security'; import { Button, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui'; +import { useAppDispatch } from 'soapbox/hooks'; const token = new URLSearchParams(window.location.search).get('reset_password_token'); +const messages = defineMessages({ + resetPasswordFail: { id: 'reset_password.fail', defaultMessage: 'Expired token, please try again.' }, +}); + const Statuses = { IDLE: 'IDLE', LOADING: 'LOADING', @@ -16,12 +19,9 @@ const Statuses = { FAIL: 'FAIL', }; -const mapDispatchToProps = dispatch => ({ - resetPasswordConfirm: (password, token) => dispatch(resetPasswordConfirm(password, token)), -}); - -const PasswordResetConfirm = ({ resetPasswordConfirm }) => { +const PasswordResetConfirm = () => { const intl = useIntl(); + const dispatch = useAppDispatch(); const [password, setPassword] = React.useState(''); const [status, setStatus] = React.useState(Statuses.IDLE); @@ -32,10 +32,10 @@ const PasswordResetConfirm = ({ resetPasswordConfirm }) => { event.preventDefault(); setStatus(Statuses.LOADING); - resetPasswordConfirm(password, token) + dispatch(resetPasswordConfirm(password, token)) .then(() => setStatus(Statuses.SUCCESS)) .catch(() => setStatus(Statuses.FAIL)); - }, [resetPasswordConfirm, password]); + }, [password]); const onChange = React.useCallback((event) => { setPassword(event.target.value); @@ -43,7 +43,7 @@ const PasswordResetConfirm = ({ resetPasswordConfirm }) => { const renderErrors = () => { if (status === Statuses.FAIL) { - return [intl.formatMessage({ id: 'reset_password.fail', defaultMessage: 'Expired token, please try again.' })]; + return [intl.formatMessage(messages.resetPasswordFail)]; } return []; @@ -84,8 +84,4 @@ const PasswordResetConfirm = ({ resetPasswordConfirm }) => { ); }; -PasswordResetConfirm.propTypes = { - resetPasswordConfirm: PropTypes.func, -}; - -export default injectIntl(connect(null, mapDispatchToProps)(PasswordResetConfirm)); +export default PasswordResetConfirm; diff --git a/app/soapbox/features/compose/components/compose_form.js b/app/soapbox/features/compose/components/compose_form.js index eb1fb1557..713b5d087 100644 --- a/app/soapbox/features/compose/components/compose_form.js +++ b/app/soapbox/features/compose/components/compose_form.js @@ -208,9 +208,9 @@ class ComposeForm extends ImmutablePureComponent { } handleEmojiPick = (data) => { - const { text } = this.props; - const position = this.autosuggestTextarea.textarea.selectionStart; - const needsSpace = data.custom && position > 0 && !allowedAroundShortCode.includes(text[position - 1]); + const { text } = this.props; + const position = this.autosuggestTextarea.textarea.selectionStart; + const needsSpace = data.custom && position > 0 && !allowedAroundShortCode.includes(text[position - 1]); this.props.onPickEmoji(position, data, needsSpace); } diff --git a/app/soapbox/features/compose/components/search.tsx b/app/soapbox/features/compose/components/search.tsx index 660045694..401001fc9 100644 --- a/app/soapbox/features/compose/components/search.tsx +++ b/app/soapbox/features/compose/components/search.tsx @@ -6,16 +6,15 @@ import { defineMessages, useIntl } from 'react-intl'; import { useDispatch } from 'react-redux'; import { useHistory } from 'react-router-dom'; -import AutosuggestAccountInput from 'soapbox/components/autosuggest_account_input'; -import SvgIcon from 'soapbox/components/ui/icon/svg-icon'; -import { useAppSelector } from 'soapbox/hooks'; - import { changeSearch, clearSearch, submitSearch, showSearch, -} from '../../../actions/search'; +} from 'soapbox/actions/search'; +import AutosuggestAccountInput from 'soapbox/components/autosuggest_account_input'; +import SvgIcon from 'soapbox/components/ui/icon/svg-icon'; +import { useAppSelector } from 'soapbox/hooks'; const messages = defineMessages({ placeholder: { id: 'search.placeholder', defaultMessage: 'Search' }, diff --git a/app/soapbox/features/directory/index.js b/app/soapbox/features/directory/index.js index 99eccf947..37795a4e9 100644 --- a/app/soapbox/features/directory/index.js +++ b/app/soapbox/features/directory/index.js @@ -86,7 +86,7 @@ class Directory extends React.PureComponent { render() { const { isLoading, accountIds, intl, title, features } = this.props; - const { order, local } = this.getParams(this.props, this.state); + const { order, local } = this.getParams(this.props, this.state); return ( diff --git a/app/soapbox/features/edit_email/index.js b/app/soapbox/features/edit_email/index.tsx similarity index 83% rename from app/soapbox/features/edit_email/index.js rename to app/soapbox/features/edit_email/index.tsx index b6ab94f1d..bd9becc2e 100644 --- a/app/soapbox/features/edit_email/index.js +++ b/app/soapbox/features/edit_email/index.tsx @@ -1,16 +1,17 @@ import * as React from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { useDispatch } from 'react-redux'; import { changeEmail } from 'soapbox/actions/security'; import snackbar from 'soapbox/actions/snackbar'; - -import { Button, Card, CardBody, CardHeader, CardTitle, Column, Form, FormActions, FormGroup, Input } from '../../components/ui'; +import { Button, Card, CardBody, CardHeader, CardTitle, Column, Form, FormActions, FormGroup, Input } from 'soapbox/components/ui'; +import { useAppDispatch } from 'soapbox/hooks'; const messages = defineMessages({ + header: { id: 'edit_email.header', defaultMessage: 'Change Email' }, updateEmailSuccess: { id: 'security.update_email.success', defaultMessage: 'Email successfully updated.' }, updateEmailFail: { id: 'security.update_email.fail', defaultMessage: 'Update email failed.' }, emailFieldLabel: { id: 'security.fields.email.label', defaultMessage: 'Email address' }, + emailFieldPlaceholder: { id: 'edit_email.placeholder', defaultMessage: 'me@example.com' }, passwordFieldLabel: { id: 'security.fields.password.label', defaultMessage: 'Password' }, submit: { id: 'security.submit', defaultMessage: 'Save changes' }, cancel: { id: 'common.cancel', defaultMessage: 'Cancel' }, @@ -20,7 +21,7 @@ const initialState = { email: '', password: '' }; const EditEmail = () => { const intl = useIntl(); - const dispatch = useDispatch(); + const dispatch = useAppDispatch(); const [state, setState] = React.useState(initialState); const [isLoading, setLoading] = React.useState(false); @@ -48,14 +49,14 @@ const EditEmail = () => { return ( @@ -63,9 +64,10 @@ const EditEmail = () => {
diff --git a/app/soapbox/features/email_confirmation/index.js b/app/soapbox/features/email_confirmation/index.tsx similarity index 60% rename from app/soapbox/features/email_confirmation/index.js rename to app/soapbox/features/email_confirmation/index.tsx index 5e18f03a7..0c4939eed 100644 --- a/app/soapbox/features/email_confirmation/index.js +++ b/app/soapbox/features/email_confirmation/index.tsx @@ -1,14 +1,12 @@ -import PropTypes from 'prop-types'; import * as React from 'react'; -import { useIntl } from 'react-intl'; -import { useDispatch } from 'react-redux'; +import { defineMessages, useIntl } from 'react-intl'; import { Redirect } from 'react-router-dom'; +import { confirmChangedEmail } from 'soapbox/actions/security'; import snackbar from 'soapbox/actions/snackbar'; import { Spinner } from 'soapbox/components/ui'; - -import { confirmChangedEmail } from '../../actions/security'; -import { buildErrorMessage } from '../../utils/errors'; +import { useAppDispatch } from 'soapbox/hooks'; +import { buildErrorMessage } from 'soapbox/utils/errors'; const Statuses = { IDLE: 'IDLE', @@ -16,11 +14,15 @@ const Statuses = { FAIL: 'FAIL', }; +const messages = defineMessages({ + success: { id: 'email_confirmation.success', defaultMessage: 'Your email has been confirmed!' }, +}); + const token = new URLSearchParams(window.location.search).get('confirmation_token'); const EmailConfirmation = () => { const intl = useIntl(); - const dispatch = useDispatch(); + const dispatch = useAppDispatch(); const [status, setStatus] = React.useState(Statuses.IDLE); @@ -32,10 +34,7 @@ const EmailConfirmation = () => { dispatch( snackbar.success( - intl.formatMessage({ - id: 'email_confirmation.success', - defaultMessage: 'Your email has been confirmed!', - }), + intl.formatMessage(messages.success), ), ); }) @@ -43,14 +42,15 @@ const EmailConfirmation = () => { setStatus(Statuses.FAIL); if (error.response.data.error) { - const defaultMessage = buildErrorMessage(error.response.data.error); + const message = buildErrorMessage(error.response.data.error); dispatch( snackbar.error( - intl.formatMessage({ - id: 'email_confirmation.fail', - defaultMessage, - }), + message, + // intl.formatMessage({ + // id: 'email_confirmation.fail', + // defaultMessage, + // }), ), ); } @@ -67,8 +67,4 @@ const EmailConfirmation = () => { ); }; -EmailConfirmation.propTypes = { - history: PropTypes.object, -}; - export default EmailConfirmation; diff --git a/app/soapbox/features/hashtag_timeline/index.js b/app/soapbox/features/hashtag_timeline/index.js index a1854550f..bdc302f96 100644 --- a/app/soapbox/features/hashtag_timeline/index.js +++ b/app/soapbox/features/hashtag_timeline/index.js @@ -31,11 +31,11 @@ class HashtagTimeline extends React.PureComponent { // TODO: wtf is all this? // It exists in Mastodon's codebase, but undocumented if (this.additionalFor('any')) { - title.push(' ', ); + title.push(' ', ); } if (this.additionalFor('all')) { - title.push(' ', ); + title.push(' ', ); } if (this.additionalFor('none')) { diff --git a/app/soapbox/features/settings/index.tsx b/app/soapbox/features/settings/index.tsx index 1bb6722a8..c1386c288 100644 --- a/app/soapbox/features/settings/index.tsx +++ b/app/soapbox/features/settings/index.tsx @@ -23,6 +23,8 @@ const messages = defineMessages({ sessions: { id: 'settings.sessions', defaultMessage: 'Active sessions' }, deleteAccount: { id: 'settings.delete_account', defaultMessage: 'Delete Account' }, other: { id: 'settings.other', defaultMessage: 'Other options' }, + mfaEnabled: { id: 'mfa.enabled', defaultMessage: 'Enabled' }, + mfaDisabled: { id: 'mfa.disabled', defaultMessage: 'Disabled' }, }); /** User settings page. */ @@ -77,8 +79,8 @@ const Settings = () => { {isMfaEnabled ? - intl.formatMessage({ id: 'mfa.enabled', defaultMessage: 'Enabled' }) : - intl.formatMessage({ id: 'mfa.disabled', defaultMessage: 'Disabled' })} + intl.formatMessage(messages.mfaEnabled) : + intl.formatMessage(messages.mfaDisabled)} {features.sessionsAPI && ( diff --git a/app/soapbox/features/verification/registration.tsx b/app/soapbox/features/verification/registration.tsx index e038ae01a..400f6b6c4 100644 --- a/app/soapbox/features/verification/registration.tsx +++ b/app/soapbox/features/verification/registration.tsx @@ -1,6 +1,6 @@ import { AxiosError } from 'axios'; import * as React from 'react'; -import { useIntl } from 'react-intl'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { useDispatch } from 'react-redux'; import { Redirect } from 'react-router-dom'; @@ -10,10 +10,24 @@ import { startOnboarding } from 'soapbox/actions/onboarding'; import snackbar from 'soapbox/actions/snackbar'; import { createAccount } from 'soapbox/actions/verification'; import { removeStoredVerification } from 'soapbox/actions/verification'; +import { Button, Form, FormGroup, Input } from 'soapbox/components/ui'; import { useAppSelector } from 'soapbox/hooks'; import { getRedirectUrl } from 'soapbox/utils/redirect'; -import { Button, Form, FormGroup, Input } from '../../components/ui'; +const messages = defineMessages({ + success: { + id: 'registrations.success', + defaultMessage: 'Welcome to {siteTitle}!', + }, + usernameTaken: { + id: 'registrations.unprocessable_entity', + defaultMessage: 'This username has already been taken.', + }, + error: { + id: 'registrations.error', + defaultMessage: 'Failed to register your account.', + }, +}); const initialState = { username: '', @@ -45,10 +59,7 @@ const Registration = () => { dispatch(startOnboarding()); dispatch( snackbar.success( - intl.formatMessage({ - id: 'registrations.success', - defaultMessage: 'Welcome to {siteTitle}!', - }, { siteTitle }), + intl.formatMessage(messages.success, { siteTitle }), ), ); }) @@ -56,19 +67,13 @@ const Registration = () => { if (error?.response?.status === 422) { dispatch( snackbar.error( - intl.formatMessage({ - id: 'registrations.unprocessable_entity', - defaultMessage: 'This username has already been taken.', - }), + intl.formatMessage(messages.usernameTaken), ), ); } else { dispatch( snackbar.error( - intl.formatMessage({ - id: 'registrations.error', - defaultMessage: 'Failed to register your account.', - }), + intl.formatMessage(messages.error), ), ); } @@ -90,7 +95,7 @@ const Registration = () => {

- {intl.formatMessage({ id: 'registration.header', defaultMessage: 'Register your account' })} +

diff --git a/app/soapbox/features/verification/steps/age-verification.js b/app/soapbox/features/verification/steps/age-verification.js index ff1ba51f9..caeed7704 100644 --- a/app/soapbox/features/verification/steps/age-verification.js +++ b/app/soapbox/features/verification/steps/age-verification.js @@ -1,13 +1,19 @@ import PropTypes from 'prop-types'; import * as React from 'react'; import DatePicker from 'react-datepicker'; -import { useIntl } from 'react-intl'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { useDispatch, useSelector } from 'react-redux'; import snackbar from 'soapbox/actions/snackbar'; import { verifyAge } from 'soapbox/actions/verification'; +import { Button, Form, FormGroup, Text } from 'soapbox/components/ui'; -import { Button, Form, FormGroup, Text } from '../../../components/ui'; +const messages = defineMessages({ + fail: { + id: 'age_verification.fail', + defaultMessage: 'You must be {ageMinimum, plural, one {# year} other {# years}} old or older.', + }, +}); function meetsAgeMinimum(birthday, ageMinimum) { const month = birthday.getUTCMonth(); @@ -46,15 +52,9 @@ const AgeVerification = () => { dispatch(verifyAge(birthday)); } else { dispatch( - snackbar.error( - intl.formatMessage({ - id: 'age_verification.fail', - defaultMessage: 'You must be {ageMinimum, plural, one {# year} other {# years}} old or older.', - values: { - ageMinimum, - }, - }), - ), + snackbar.error(intl.formatMessage(messages.fail, { + ageMinimum, + })), ); } }, [date, ageMinimum]); @@ -63,7 +63,7 @@ const AgeVerification = () => {

- {intl.formatMessage({ id: 'age_verification.header', defaultMessage: 'Enter your birth date' })} +