Merge branch 'auth-form-improvements' into 'develop'

Auth form improvements, fixes #454 #373 #67 #177

Closes #177, #67, #373, and #454

See merge request soapbox-pub/soapbox-fe!280
This commit is contained in:
Alex Gleason 2020-09-30 04:54:28 +00:00
commit 9b99bdcd4f
8 changed files with 83 additions and 16 deletions

View File

@ -135,8 +135,10 @@ export function logIn(username, password) {
}).catch(error => { }).catch(error => {
if (error.response.data.error === 'mfa_required') { if (error.response.data.error === 'mfa_required') {
throw error; throw error;
} else if(error.response.data.error) {
dispatch(snackbar.error(error.response.data.error));
} else { } else {
dispatch(snackbar.error('Invalid username or password.')); dispatch(snackbar.error('Wrong username or password'));
} }
throw error; throw error;
}); });
@ -174,7 +176,7 @@ export function register(params) {
if (needsConfirmation) { if (needsConfirmation) {
return dispatch(snackbar.info('You must confirm your email.')); return dispatch(snackbar.info('You must confirm your email.'));
} else if (needsApproval) { } else if (needsApproval) {
return dispatch(snackbar.info('Your account is being reviewed.')); return dispatch(snackbar.info('Your account is pending review by an admin.'));
} else { } else {
return dispatch(fetchMe()); return dispatch(fetchMe());
} }

View File

@ -10,24 +10,28 @@ exports[`<LoginForm /> renders correctly 1`] = `
className="fields-group" className="fields-group"
> >
<div <div
className="input email optional user_email" className="input email user_email"
> >
<input <input
aria-label="Username" aria-label="Username"
className="string email optional" autoComplete="off"
className="string email"
name="username" name="username"
placeholder="Username" placeholder="Username"
required={true}
type="text" type="text"
/> />
</div> </div>
<div <div
className="input password optional user_password" className="input password user_password"
> >
<input <input
aria-label="Password" aria-label="Password"
className="password optional" autoComplete="off"
className="password"
name="password" name="password"
placeholder="Password" placeholder="Password"
required={true}
type="password" type="password"
/> />
</div> </div>

View File

@ -13,24 +13,28 @@ exports[`<LoginPage /> renders correctly on load 1`] = `
className="fields-group" className="fields-group"
> >
<div <div
className="input email optional user_email" className="input email user_email"
> >
<input <input
aria-label="Username" aria-label="Username"
className="string email optional" autoComplete="off"
className="string email"
name="username" name="username"
placeholder="Username" placeholder="Username"
required={true}
type="text" type="text"
/> />
</div> </div>
<div <div
className="input password optional user_password" className="input password user_password"
> >
<input <input
aria-label="Password" aria-label="Password"
className="password optional" autoComplete="off"
className="password"
name="password" name="password"
placeholder="Password" placeholder="Password"
required={true}
type="password" type="password"
/> />
</div> </div>

View File

@ -20,11 +20,27 @@ class LoginForm extends ImmutablePureComponent {
<form className='simple_form new_user' method='post' onSubmit={handleSubmit}> <form className='simple_form new_user' method='post' onSubmit={handleSubmit}>
<fieldset disabled={isLoading}> <fieldset disabled={isLoading}>
<div className='fields-group'> <div className='fields-group'>
<div className='input email optional user_email'> <div className='input email user_email'>
<input aria-label={intl.formatMessage(messages.username)} className='string email optional' placeholder={intl.formatMessage(messages.username)} type='text' name='username' /> <input
aria-label={intl.formatMessage(messages.username)}
className='string email'
placeholder={intl.formatMessage(messages.username)}
type='text'
name='username'
autoComplete='off'
required
/>
</div> </div>
<div className='input password optional user_password'> <div className='input password user_password'>
<input aria-label={intl.formatMessage(messages.password)} className='password optional' placeholder={intl.formatMessage(messages.password)} type='password' name='password' /> <input
aria-label={intl.formatMessage(messages.password)}
className='password'
placeholder={intl.formatMessage(messages.password)}
type='password'
name='password'
autoComplete='off'
required
/>
</div> </div>
<p className='hint subtle-hint'> <p className='hint subtle-hint'>
<Link to='/auth/reset_password'> <Link to='/auth/reset_password'>

View File

@ -37,6 +37,7 @@ class PasswordReset extends ImmutablePureComponent {
name='nickname_or_email' name='nickname_or_email'
label='Email or username' label='Email or username'
placeholder='me@example.com' placeholder='me@example.com'
required
/> />
</FieldsGroup> </FieldsGroup>
</fieldset> </fieldset>

View File

@ -20,6 +20,7 @@ import { getSettings } from 'soapbox/actions/settings';
const messages = defineMessages({ const messages = defineMessages({
username: { id: 'registration.fields.username_placeholder', defaultMessage: 'Username' }, username: { id: 'registration.fields.username_placeholder', defaultMessage: 'Username' },
username_hint: { id: 'registration.fields.username_hint', defaultMessage: 'Only letters, numbers, and underscores are allowed.' },
email: { id: 'registration.fields.email_placeholder', defaultMessage: 'E-Mail address' }, email: { id: 'registration.fields.email_placeholder', defaultMessage: 'E-Mail address' },
password: { id: 'registration.fields.password_placeholder', defaultMessage: 'Password' }, password: { id: 'registration.fields.password_placeholder', defaultMessage: 'Password' },
confirm: { id: 'registration.fields.confirm_placeholder', defaultMessage: 'Password (again)' }, confirm: { id: 'registration.fields.confirm_placeholder', defaultMessage: 'Password (again)' },
@ -92,11 +93,32 @@ class RegistrationForm extends ImmutablePureComponent {
render() { render() {
const { instance, intl } = this.props; const { instance, intl } = this.props;
const isOpen = instance.get('registrations');
const isLoading = this.state.captchaLoading || this.state.submissionLoading; const isLoading = this.state.captchaLoading || this.state.submissionLoading;
if (isOpen === false) {
return (
<div className='registrations-closed'>
<h2>
<FormattedMessage
id='registration.closed_title'
defaultMessage='Registrations Closed'
/>
</h2>
<div className='registrations-closed__message'>
<FormattedMessage
id='registration.closed_message'
defaultMessage='{instance} is not accepting new members'
values={{ instance: <strong>{instance.get('title')}</strong> }}
/>
</div>
</div>
);
}
return ( return (
<SimpleForm onSubmit={this.onSubmit}> <SimpleForm onSubmit={this.onSubmit}>
<fieldset disabled={isLoading}> <fieldset disabled={isLoading || !isOpen}>
<div className='simple_form__overlay-area'> <div className='simple_form__overlay-area'>
<p className='lead'> <p className='lead'>
<FormattedMessage <FormattedMessage
@ -109,7 +131,9 @@ class RegistrationForm extends ImmutablePureComponent {
<TextInput <TextInput
placeholder={intl.formatMessage(messages.username)} placeholder={intl.formatMessage(messages.username)}
name='username' name='username'
hint={intl.formatMessage(messages.username_hint)}
autoComplete='off' autoComplete='off'
pattern='^[a-zA-Z\d_-]+'
onChange={this.onInputChange} onChange={this.onInputChange}
required required
/> />

View File

@ -126,7 +126,7 @@ export const getAlerts = createSelector([getAlertsBase], (base) => {
key: item.get('key'), key: item.get('key'),
className: `snackbar snackbar--${item.get('severity', 'info')}`, className: `snackbar snackbar--${item.get('severity', 'info')}`,
activeClassName: 'snackbar--active', activeClassName: 'snackbar--active',
dismissAfter: 5000, dismissAfter: 6000,
}); });
}); });

View File

@ -443,6 +443,22 @@ $fluid-breakpoint: $maximum-width + 20px;
} }
} }
.registrations-closed {
display: flex;
flex-direction: column;
height: 100%;
align-items: center;
justify-content: center;
text-align: center;
font-size: 18px;
h2 {
font-weight: bold;
font-size: 24px;
margin-bottom: 10px;
}
}
@media (min-width: 767px) and (max-width: 1024px) { @media (min-width: 767px) and (max-width: 1024px) {
padding: 40px 20px 20px; padding: 40px 20px 20px;