add focus & fix styles for auth forms errors (#156)

* add focus & fix styles for auth forms errors

* refactor by review comments

* minor changes: let ref -> const ref: { current }, additional typings

---------

Co-authored-by: bniwredyc <bniwredyc@gmail.com>
This commit is contained in:
Arkadzi Rakouski 2023-08-13 16:36:18 +03:00 committed by GitHub
parent 8e5f34eb85
commit 4fea17a2ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 115 additions and 55 deletions

View File

@ -28,6 +28,8 @@ export const ForgotPasswordForm = () => {
const [validationErrors, setValidationErrors] = createSignal<ValidationErrors>({})
const [isUserNotFount, setIsUserNotFound] = createSignal(false)
const authFormRef: { current: HTMLFormElement } = { current: null }
const handleSubmit = async (event: Event) => {
event.preventDefault()
@ -47,6 +49,10 @@ export const ForgotPasswordForm = () => {
const isValid = Object.keys(newValidationErrors).length === 0
if (!isValid) {
authFormRef.current
.querySelector<HTMLInputElement>(`input[name="${Object.keys(newValidationErrors)[0]}"]`)
.focus()
return
}
@ -66,7 +72,11 @@ export const ForgotPasswordForm = () => {
}
return (
<form onSubmit={handleSubmit} class={clsx(styles.authForm, styles.authFormForgetPassword)}>
<form
onSubmit={handleSubmit}
class={clsx(styles.authForm, styles.authFormForgetPassword)}
ref={(el) => (authFormRef.current = el)}
>
<div>
<h4>{t('Forgot password?')}</h4>
<div class={styles.authSubtitle}>{t('Everything is ok, please give us your email address')}</div>
@ -95,7 +105,11 @@ export const ForgotPasswordForm = () => {
<Show when={validationErrors().email}>
<div class={styles.validationError}>{validationErrors().email}</div>
</Show>
<div class="pretty-form__item">
<div
class={clsx('pretty-form__item', {
'pretty-form__item--error': validationErrors().email
})}
>
<input
id="email"
name="email"

View File

@ -33,6 +33,8 @@ export const LoginForm = () => {
const [isLinkSent, setIsLinkSent] = createSignal(false)
const [showPassword, setShowPassword] = createSignal(false)
const authFormRef: { current: HTMLFormElement } = { current: null }
const {
actions: { showSnackbar }
} = useSnackbar()
@ -57,9 +59,11 @@ export const LoginForm = () => {
const handleSendLinkAgainClick = async (event: Event) => {
event.preventDefault()
setIsLinkSent(true)
setIsEmailNotConfirmed(false)
setSubmitError('')
setIsLinkSent(true)
const result = await signSendLink({ email: email(), lang: lang(), template: 'email_confirmation' })
if (result.error) setSubmitError(result.error)
}
@ -85,6 +89,11 @@ export const LoginForm = () => {
if (Object.keys(newValidationErrors).length > 0) {
setValidationErrors(newValidationErrors)
authFormRef.current
.querySelector<HTMLInputElement>(`input[name="${Object.keys(newValidationErrors)[0]}"]`)
.focus()
return
}
@ -92,18 +101,23 @@ export const LoginForm = () => {
try {
await signIn({ email: email(), password: password() })
hideModal()
showSnackbar({ body: t('Welcome!') })
} catch (error) {
if (error instanceof ApiError) {
if (error.code === 'email_not_confirmed') {
setSubmitError(t('Please, confirm email'))
setIsEmailNotConfirmed(true)
return
}
if (error.code === 'user_not_found') {
setSubmitError(t('Something went wrong, check email and password'))
return
}
}
@ -115,7 +129,7 @@ export const LoginForm = () => {
}
return (
<form onSubmit={handleSubmit} class={styles.authForm}>
<form onSubmit={handleSubmit} class={styles.authForm} ref={(el) => (authFormRef.current = el)}>
<div>
<AuthModalHeader modalType="login" />
<Show when={submitError()}>
@ -131,7 +145,11 @@ export const LoginForm = () => {
<Show when={isLinkSent()}>
<div class={styles.authInfo}>{t('Link sent, check your email')}</div>
</Show>
<div class="pretty-form__item">
<div
class={clsx('pretty-form__item', {
'pretty-form__item--error': validationErrors().email
})}
>
<input
id="email"
name="email"
@ -147,7 +165,11 @@ export const LoginForm = () => {
<div class={styles.validationError}>{validationErrors().email}</div>
</Show>
<div class="pretty-form__item">
<div
class={clsx('pretty-form__item', {
'pretty-form__item--error': validationErrors().password
})}
>
<input
id="password"
name="password"

View File

@ -15,7 +15,7 @@ import { validateEmail } from '../../../utils/validateEmail'
import { AuthModalHeader } from './AuthModalHeader'
type FormFields = {
name: string
fullName: string
email: string
password: string
}
@ -28,12 +28,14 @@ export const RegisterForm = () => {
const { emailChecks } = useEmailChecks()
const [submitError, setSubmitError] = createSignal('')
const [name, setName] = createSignal('')
const [fullName, setFullName] = createSignal('')
const [password, setPassword] = createSignal('')
const [isSubmitting, setIsSubmitting] = createSignal(false)
const [isSuccess, setIsSuccess] = createSignal(false)
const [validationErrors, setValidationErrors] = createSignal<ValidationErrors>({})
const authFormRef: { current: HTMLFormElement } = { current: null }
const handleEmailInput = (newEmail: string) => {
setValidationErrors(({ email: _notNeeded, ...rest }) => rest)
setEmail(newEmail)
@ -73,8 +75,8 @@ export const RegisterForm = () => {
}
const handleNameInput = (newPasswordCopy: string) => {
setValidationErrors(({ name: _notNeeded, ...rest }) => rest)
setName(newPasswordCopy)
setValidationErrors(({ fullName: _notNeeded, ...rest }) => rest)
setFullName(newPasswordCopy)
}
const handleSubmit = async (event: Event) => {
@ -84,11 +86,11 @@ export const RegisterForm = () => {
const newValidationErrors: ValidationErrors = {}
const cleanName = name().trim()
const cleanName = fullName().trim()
const cleanEmail = email().trim()
if (!cleanName) {
newValidationErrors.name = t('Please enter a name to sign your comments and publication')
newValidationErrors.fullName = t('Please enter a name to sign your comments and publication')
}
if (!cleanEmail) {
@ -108,6 +110,10 @@ export const RegisterForm = () => {
const isValid = Object.keys(newValidationErrors).length === 0 && !emailCheckResult
if (!isValid) {
authFormRef.current
.querySelector<HTMLInputElement>(`input[name="${Object.keys(newValidationErrors)[0]}"]`)
.focus()
return
}
@ -135,7 +141,7 @@ export const RegisterForm = () => {
return (
<>
<Show when={!isSuccess()}>
<form onSubmit={handleSubmit} class={styles.authForm}>
<form onSubmit={handleSubmit} class={styles.authForm} ref={(el) => (authFormRef.current = el)}>
<div>
<AuthModalHeader modalType="register" />
<Show when={submitError()}>
@ -145,7 +151,11 @@ export const RegisterForm = () => {
</ul>
</div>
</Show>
<div class="pretty-form__item">
<div
class={clsx('pretty-form__item', {
'pretty-form__item--error': validationErrors().fullName
})}
>
<input
name="fullName"
type="text"
@ -153,12 +163,16 @@ export const RegisterForm = () => {
autocomplete=""
onInput={(event) => handleNameInput(event.currentTarget.value)}
/>
<label for="fullName">{t('Full name')}</label>
<label for="name">{t('Full name')}</label>
</div>
<Show when={validationErrors().name}>
<div class={styles.validationError}>{validationErrors().name}</div>
<Show when={validationErrors().fullName}>
<div class={styles.validationError}>{validationErrors().fullName}</div>
</Show>
<div class="pretty-form__item">
<div
class={clsx('pretty-form__item', {
'pretty-form__item--error': validationErrors().email
})}
>
<input
id="email"
name="email"
@ -188,7 +202,11 @@ export const RegisterForm = () => {
</a>
</div>
</Show>
<div class="pretty-form__item">
<div
class={clsx('pretty-form__item', {
'pretty-form__item--error': validationErrors().password
})}
>
<input
id="password"
name="password"

View File

@ -391,42 +391,6 @@ button {
}
form {
.pretty-form__item {
position: relative;
input {
padding-top: 1.4em;
}
textarea {
line-height: 1.4;
}
}
.pretty-form__item--with-button {
margin-bottom: 1.6rem;
@include media-breakpoint-up(sm) {
display: flex;
}
input {
flex: 1;
@include media-breakpoint-up(sm) {
margin-bottom: 0 !important;
}
}
*:first-child {
flex: 1;
@include media-breakpoint-up(sm) {
margin-right: 1em;
}
}
}
input[type='text'],
input[type='email'],
input[type='password'],
@ -510,6 +474,48 @@ form {
.form-message {
@include font-size(1.2rem);
}
.pretty-form__item {
position: relative;
input {
padding-top: 1.4em;
}
textarea {
line-height: 1.4;
}
}
.pretty-form__item--error {
input {
border-color: #d00820;
}
}
.pretty-form__item--with-button {
margin-bottom: 1.6rem;
@include media-breakpoint-up(sm) {
display: flex;
}
input {
flex: 1;
@include media-breakpoint-up(sm) {
margin-bottom: 0 !important;
}
}
*:first-child {
flex: 1;
@include media-breakpoint-up(sm) {
margin-right: 1em;
}
}
}
}
.input--short {