Merge pull request #405 from Discours/feature/parse-email-errors

Feature/parse email errors
This commit is contained in:
Tony 2024-02-08 19:54:51 +03:00 committed by GitHub
commit 5812c84756
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 92 additions and 76 deletions

View File

@ -2,7 +2,7 @@
"$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json",
"files": { "files": {
"include": ["*.tsx", "*.ts", "*.js", "*.json"], "include": ["*.tsx", "*.ts", "*.js", "*.json"],
"ignore": ["./dist", "./node_modules", ".husky", "docs", "gen"] "ignore": ["./dist", "./node_modules", ".husky", "docs", "gen", "*.d.ts"]
}, },
"vcs": { "vcs": {
"defaultBranch": "dev", "defaultBranch": "dev",
@ -29,7 +29,7 @@
} }
}, },
"linter": { "linter": {
"ignore": ["*.scss", "*.md", ".DS_Store", "*.svg"], "ignore": ["*.scss", "*.md", ".DS_Store", "*.svg", "*.d.ts"],
"enabled": true, "enabled": true,
"rules": { "rules": {
"all": true, "all": true,

View File

@ -377,6 +377,9 @@
"There are unsaved changes in your publishing settings. Are you sure you want to leave the page without saving?": "There are unsaved changes in your publishing settings. Are you sure you want to leave the page without saving?", "There are unsaved changes in your publishing settings. Are you sure you want to leave the page without saving?": "There are unsaved changes in your publishing settings. Are you sure you want to leave the page without saving?",
"This comment has not yet been rated": "This comment has not yet been rated", "This comment has not yet been rated": "This comment has not yet been rated",
"This email is": "This email is", "This email is": "This email is",
"This email is not verified": "This email is not verified",
"This email is verified": "This email is verified",
"This email is registered": "This email is registered",
"This functionality is currently not available, we would like to work on this issue. Use the download link.": "This functionality is currently not available, we would like to work on this issue. Use the download link.", "This functionality is currently not available, we would like to work on this issue. Use the download link.": "This functionality is currently not available, we would like to work on this issue. Use the download link.",
"This month": "This month", "This month": "This month",
"This post has not been rated yet": "This post has not been rated yet", "This post has not been rated yet": "This post has not been rated yet",
@ -407,7 +410,6 @@
"Upload video": "Upload video", "Upload video": "Upload video",
"Upload": "Upload", "Upload": "Upload",
"Uploading image": "Uploading image", "Uploading image": "Uploading image",
"User with this email already exists": "User with this email already exists",
"Username": "Username", "Username": "Username",
"Userpic": "Userpic", "Userpic": "Userpic",
"Users": "Users", "Users": "Users",

View File

@ -399,6 +399,9 @@
"There are unsaved changes in your publishing settings. Are you sure you want to leave the page without saving?": "В настройках публикации есть несохраненные изменения. Уверены, что хотите покинуть страницу без сохранения?", "There are unsaved changes in your publishing settings. Are you sure you want to leave the page without saving?": "В настройках публикации есть несохраненные изменения. Уверены, что хотите покинуть страницу без сохранения?",
"This comment has not yet been rated": "Этот комментарий еще пока никто не оценил", "This comment has not yet been rated": "Этот комментарий еще пока никто не оценил",
"This email is": "Этот email", "This email is": "Этот email",
"This email is not verified": "Этот email не подтвержден",
"This email is verified": "Этот email подтвержден",
"This email is registered": "Этот email уже зарегистрирован",
"This functionality is currently not available, we would like to work on this issue. Use the download link.": "В данный момент этот функционал не доступен, бы работаем над этой проблемой. Воспользуйтесь загрузкой по ссылке.", "This functionality is currently not available, we would like to work on this issue. Use the download link.": "В данный момент этот функционал не доступен, бы работаем над этой проблемой. Воспользуйтесь загрузкой по ссылке.",
"This month": "За месяц", "This month": "За месяц",
"This post has not been rated yet": "Эту публикацию еще пока никто не оценил", "This post has not been rated yet": "Эту публикацию еще пока никто не оценил",
@ -429,7 +432,6 @@
"Upload video": "Загрузить видео", "Upload video": "Загрузить видео",
"Upload": "Загрузить", "Upload": "Загрузить",
"Uploading image": "Загружаем изображение", "Uploading image": "Загружаем изображение",
"User with this email already exists": "Пользователь с таким email уже существует",
"Username": "Имя пользователя", "Username": "Имя пользователя",
"Userpic": "Аватар", "Userpic": "Аватар",
"Users": "Пользователи", "Users": "Пользователи",

View File

@ -74,7 +74,7 @@ export const AuthorBadge = (props: Props) => {
on( on(
() => props.isFollowed, () => props.isFollowed,
() => { () => {
setIsFollowed(props.isFollowed.value) setIsFollowed(props.isFollowed?.value)
}, },
), ),
) )

View File

@ -198,6 +198,14 @@
border-color: var(--background-color-invert); border-color: var(--background-color-invert);
} }
} }
&.info,
&.info a {
color: var(--secondary-color);
border-color: var(--secondary-color);
}
} }
.title { .title {

View File

@ -13,6 +13,7 @@ type Props = {
errorMessage?: (error: string) => void errorMessage?: (error: string) => void
onInput: (value: string) => void onInput: (value: string) => void
variant?: 'login' | 'registration' variant?: 'login' | 'registration'
disableAutocomplete?: boolean
} }
export const PasswordField = (props: Props) => { export const PasswordField = (props: Props) => {
@ -69,7 +70,7 @@ export const PasswordField = (props: Props) => {
id="password" id="password"
name="password" name="password"
disabled={props.disabled} disabled={props.disabled}
autocomplete="current-password" autocomplete={props.disableAutocomplete ? 'one-time-code' : 'current-password'}
type={showPassword() ? 'text' : 'password'} type={showPassword() ? 'text' : 'password'}
placeholder={props.placeholder || t('Password')} placeholder={props.placeholder || t('Password')}
onInput={(event) => handleInputChange(event.currentTarget.value)} onInput={(event) => handleInputChange(event.currentTarget.value)}

View File

@ -1,8 +1,8 @@
import type { JSX } from 'solid-js' import type { JSX } from 'solid-js'
import { Show, createEffect, createMemo, createSignal } from 'solid-js'
import type { AuthModalSearchParams } from './types' import type { AuthModalSearchParams } from './types'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import { Show, createEffect, createMemo, createSignal } from 'solid-js'
import { useLocalize } from '../../../context/localize' import { useLocalize } from '../../../context/localize'
import { useSession } from '../../../context/session' import { useSession } from '../../../context/session'
@ -17,6 +17,8 @@ import { email, setEmail } from './sharedLogic'
import styles from './AuthModal.module.scss' import styles from './AuthModal.module.scss'
type EmailStatus = 'not verified' | 'verified' | 'registered' | ''
type FormFields = { type FormFields = {
fullName: string fullName: string
email: string email: string
@ -39,22 +41,12 @@ export const RegisterForm = () => {
const [isSubmitting, setIsSubmitting] = createSignal(false) const [isSubmitting, setIsSubmitting] = createSignal(false)
const [isSuccess, setIsSuccess] = createSignal(false) const [isSuccess, setIsSuccess] = createSignal(false)
const [validationErrors, setValidationErrors] = createSignal<ValidationErrors>({}) const [validationErrors, setValidationErrors] = createSignal<ValidationErrors>({})
const [infoEmailMessage, setInfoEmailMessage] = createSignal<boolean>(false)
const [passwordError, setPasswordError] = createSignal<string>() const [passwordError, setPasswordError] = createSignal<string>()
const [emailStatus, setEmailStatus] = createSignal<string>('') const [emailStatus, setEmailStatus] = createSignal<string>('')
const authFormRef: { current: HTMLFormElement } = { current: null } const authFormRef: { current: HTMLFormElement } = { current: null }
const checkEmail = async (address: string) => {
const result: string = await isRegistered(address)
if (result) setEmailStatus((_s) => result)
}
const handleEmailBlur = () => {
if (validateEmail(email())) {
checkEmail(email())
}
}
const handleNameInput = (newName: string) => { const handleNameInput = (newName: string) => {
setFullName(newName) setFullName(newName)
} }
@ -100,8 +92,8 @@ export const RegisterForm = () => {
return return
} }
setIsSubmitting(true) setIsSubmitting(true)
setInfoEmailMessage(false)
try { try {
const opts = { const opts = {
given_name: cleanName, given_name: cleanName,
@ -111,26 +103,7 @@ export const RegisterForm = () => {
redirect_uri: window.location.origin, redirect_uri: window.location.origin,
} }
const { errors } = await signUp(opts) const { errors } = await signUp(opts)
if (errors?.some((error) => error.message.includes('has already signed up'))) { if (errors) return
setValidationErrors((prev) => ({
...prev,
email: (
<>
{t('User with this email already exists')},{' '}
<span
class={'link'}
onClick={() =>
changeSearchParams({
mode: 'login',
})
}
>
{t('sign in')}
</span>
</>
),
}))
}
setIsSuccess(true) setIsSuccess(true)
} catch (error) { } catch (error) {
console.error(error) console.error(error)
@ -138,9 +111,65 @@ export const RegisterForm = () => {
setIsSubmitting(false) setIsSubmitting(false)
} }
} }
createEffect(() => {
console.debug(emailStatus()) const handleCheckEmailStatus = (status: EmailStatus | string) => {
}) switch (status) {
case 'not verified':
setInfoEmailMessage(true)
setValidationErrors((prev) => ({
...prev,
email: (
<>
{t('This email is not verified')},{' '}
<span
class="link"
onClick={() => resendVerifyEmail({ email: email(), identifier: 'basic_signup' })}
>
{t('resend confirmation link')}
</span>
</>
),
}))
break
case 'verified':
setInfoEmailMessage(true)
setValidationErrors((prev) => ({
email: (
<>
{t('This email is verified')},{' '}
<span class="link" onClick={() => changeSearchParams({ mode: 'login' })}>
{t('enter')}
</span>
</>
),
}))
break
case 'registered':
setValidationErrors((prev) => ({
...prev,
email: (
<>
{t('This email is registered')},{'. '}
<span class="link" onClick={() => changeSearchParams({ mode: 'send-reset-link' })}>
{t('Set the new password').toLocaleLowerCase()}
</span>
</>
),
}))
break
default:
setInfoEmailMessage(false)
break
}
}
const handleEmailBlur = async () => {
if (validateEmail(email())) {
const checkResult = await isRegistered(email())
handleCheckEmailStatus(checkResult)
}
}
return ( return (
<> <>
@ -162,63 +191,37 @@ export const RegisterForm = () => {
name="fullName" name="fullName"
type="text" type="text"
placeholder={t('Full name')} placeholder={t('Full name')}
autocomplete="" autocomplete="one-time-code"
onInput={(event) => handleNameInput(event.currentTarget.value)} onInput={(event) => handleNameInput(event.currentTarget.value)}
/> />
<label for="name">{t('Full name')}</label> <label for="name">{t('Full name')}</label>
<Show when={!emailStatus() && validationErrors().fullName}> <Show when={validationErrors().fullName}>
<div class={styles.validationError}>{validationErrors().fullName}</div> <div class={styles.validationError}>{validationErrors().fullName}</div>
</Show> </Show>
</div> </div>
<div <div
class={clsx('pretty-form__item', { class={clsx('pretty-form__item', {
'pretty-form__item--error': validationErrors().email, 'pretty-form__item--error': validationErrors().email && !infoEmailMessage(),
})} })}
> >
<input <input
id="email" id="email"
name="email" name="email"
autocomplete="email" autocomplete="one-time-code"
type="email" type="email"
value={email()}
placeholder={t('Email')} placeholder={t('Email')}
onInput={(event) => handleEmailInput(event.currentTarget.value)} onInput={(event) => handleEmailInput(event.currentTarget.value)}
onBlur={handleEmailBlur} onBlur={handleEmailBlur}
/> />
<label for="email">{t('Email')}</label> <label for="email">{t('Email')}</label>
<div class={styles.validationError}>{validationErrors().email}</div> <div class={clsx(styles.validationError, styles.info, { [styles.info]: infoEmailMessage() })}>
<Show when={Boolean(emailStatus())}> {validationErrors().email}
{t('This email is')} {emailStatus() ? t(emailStatus()) : ''},{' '} </div>
</Show>
<Show when={emailStatus() === 'verfied'}>
<span class="link" onClick={() => changeSearchParams({ mode: 'login' })}>
{t('enter')}
</span>
</Show>
<Show when={emailStatus() === 'not verfied'}>
<span
class="link"
onClick={() => resendVerifyEmail({ email: email(), identifier: 'basic_signup' })}
>
{t('resend confirmation link')}
</span>
</Show>
<Show when={emailStatus() === 'registered'}>
<span
class="link"
onClick={() =>
changeSearchParams({
mode: 'send-reset-link',
})
}
>
{t('Set the new password').toLocaleLowerCase()}
</span>
</Show>
</div> </div>
<PasswordField <PasswordField
disableAutocomplete={true}
disabled={Boolean(emailStatus())} disabled={Boolean(emailStatus())}
errorMessage={(err) => setPasswordError(err)} errorMessage={(err) => setPasswordError(err)}
onInput={(value) => setPassword(value)} onInput={(value) => setPassword(value)}