2023-11-14 15:10:00 +00:00
|
|
|
import type { AuthModalSearchParams } from './types'
|
|
|
|
|
2022-10-21 18:17:04 +00:00
|
|
|
import { clsx } from 'clsx'
|
2022-10-31 16:40:55 +00:00
|
|
|
import { createSignal, JSX, Show } from 'solid-js'
|
2023-11-14 15:10:00 +00:00
|
|
|
|
2023-11-28 18:04:51 +00:00
|
|
|
import { useAuthorizer } from '../../../context/authorizer'
|
2023-11-14 15:10:00 +00:00
|
|
|
import { useLocalize } from '../../../context/localize'
|
2023-11-28 13:18:25 +00:00
|
|
|
import { ApiError } from '../../../graphql/error'
|
2022-10-21 18:17:04 +00:00
|
|
|
import { useRouter } from '../../../stores/router'
|
2023-07-02 05:08:42 +00:00
|
|
|
import { validateEmail } from '../../../utils/validateEmail'
|
2022-10-21 18:17:04 +00:00
|
|
|
|
2023-11-14 15:10:00 +00:00
|
|
|
import { email, setEmail } from './sharedLogic'
|
|
|
|
|
|
|
|
import styles from './AuthModal.module.scss'
|
|
|
|
|
2022-10-21 18:17:04 +00:00
|
|
|
type FormFields = {
|
|
|
|
email: string
|
|
|
|
}
|
|
|
|
|
|
|
|
type ValidationErrors = Partial<Record<keyof FormFields, string | JSX.Element>>
|
|
|
|
|
|
|
|
export const ForgotPasswordForm = () => {
|
|
|
|
const { changeSearchParam } = useRouter<AuthModalSearchParams>()
|
2023-11-28 18:04:51 +00:00
|
|
|
const { t } = useLocalize()
|
2022-10-21 18:17:04 +00:00
|
|
|
const handleEmailInput = (newEmail: string) => {
|
|
|
|
setValidationErrors(({ email: _notNeeded, ...rest }) => rest)
|
|
|
|
setEmail(newEmail)
|
|
|
|
}
|
2023-11-28 18:04:51 +00:00
|
|
|
const [, { authorizer }] = useAuthorizer()
|
2022-10-21 18:17:04 +00:00
|
|
|
const [submitError, setSubmitError] = createSignal('')
|
|
|
|
const [isSubmitting, setIsSubmitting] = createSignal(false)
|
|
|
|
const [validationErrors, setValidationErrors] = createSignal<ValidationErrors>({})
|
2022-11-14 01:17:12 +00:00
|
|
|
const [isUserNotFount, setIsUserNotFound] = createSignal(false)
|
2022-10-21 18:17:04 +00:00
|
|
|
|
2023-08-13 13:36:18 +00:00
|
|
|
const authFormRef: { current: HTMLFormElement } = { current: null }
|
|
|
|
|
2023-12-03 10:22:42 +00:00
|
|
|
const [message, setMessage] = createSignal<string>('')
|
|
|
|
|
2022-10-21 18:17:04 +00:00
|
|
|
const handleSubmit = async (event: Event) => {
|
|
|
|
event.preventDefault()
|
|
|
|
|
|
|
|
setSubmitError('')
|
2022-11-14 01:17:12 +00:00
|
|
|
setIsUserNotFound(false)
|
2022-10-21 18:17:04 +00:00
|
|
|
|
|
|
|
const newValidationErrors: ValidationErrors = {}
|
|
|
|
|
|
|
|
if (!email()) {
|
|
|
|
newValidationErrors.email = t('Please enter email')
|
2023-07-02 05:08:42 +00:00
|
|
|
} else if (!validateEmail(email())) {
|
2022-10-21 18:17:04 +00:00
|
|
|
newValidationErrors.email = t('Invalid email')
|
|
|
|
}
|
|
|
|
|
|
|
|
setValidationErrors(newValidationErrors)
|
|
|
|
|
|
|
|
const isValid = Object.keys(newValidationErrors).length === 0
|
|
|
|
|
|
|
|
if (!isValid) {
|
2023-08-13 13:36:18 +00:00
|
|
|
authFormRef.current
|
|
|
|
.querySelector<HTMLInputElement>(`input[name="${Object.keys(newValidationErrors)[0]}"]`)
|
|
|
|
.focus()
|
|
|
|
|
2022-10-21 18:17:04 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
setIsSubmitting(true)
|
|
|
|
try {
|
2023-12-03 10:22:42 +00:00
|
|
|
const response = await authorizer().forgotPassword({
|
|
|
|
email: email(),
|
|
|
|
redirect_uri: window.location.href + '&success=1', // FIXME: redirect to success page accepting confirmation code
|
|
|
|
})
|
2023-11-28 18:04:51 +00:00
|
|
|
if (response) {
|
|
|
|
console.debug(response)
|
2023-12-03 10:22:42 +00:00
|
|
|
if (response.message) setMessage(response.message)
|
2023-11-28 18:04:51 +00:00
|
|
|
}
|
2022-10-21 18:17:04 +00:00
|
|
|
} catch (error) {
|
2022-11-14 01:17:12 +00:00
|
|
|
if (error instanceof ApiError && error.code === 'user_not_found') {
|
|
|
|
setIsUserNotFound(true)
|
|
|
|
return
|
|
|
|
}
|
2022-10-21 18:17:04 +00:00
|
|
|
setSubmitError(error.message)
|
|
|
|
} finally {
|
|
|
|
setIsSubmitting(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2023-08-13 13:36:18 +00:00
|
|
|
<form
|
|
|
|
onSubmit={handleSubmit}
|
|
|
|
class={clsx(styles.authForm, styles.authFormForgetPassword)}
|
|
|
|
ref={(el) => (authFormRef.current = el)}
|
|
|
|
>
|
2023-05-18 20:02:19 +00:00
|
|
|
<div>
|
|
|
|
<h4>{t('Forgot password?')}</h4>
|
2023-12-03 10:22:42 +00:00
|
|
|
<div class={styles.authSubtitle}>
|
|
|
|
{t(message()) || t('Everything is ok, please give us your email address')}
|
|
|
|
</div>
|
2023-08-21 11:11:18 +00:00
|
|
|
|
|
|
|
<div
|
|
|
|
class={clsx('pretty-form__item', {
|
2023-11-14 15:10:00 +00:00
|
|
|
'pretty-form__item--error': validationErrors().email,
|
2023-08-21 11:11:18 +00:00
|
|
|
})}
|
|
|
|
>
|
|
|
|
<input
|
|
|
|
id="email"
|
|
|
|
name="email"
|
|
|
|
autocomplete="email"
|
|
|
|
type="email"
|
|
|
|
value={email()}
|
|
|
|
placeholder={t('Email')}
|
|
|
|
onInput={(event) => handleEmailInput(event.currentTarget.value)}
|
|
|
|
/>
|
|
|
|
|
|
|
|
<label for="email">{t('Email')}</label>
|
|
|
|
</div>
|
|
|
|
|
2023-05-18 20:02:19 +00:00
|
|
|
<Show when={submitError()}>
|
|
|
|
<div class={styles.authInfo}>
|
|
|
|
<ul>
|
|
|
|
<li class={styles.warn}>{submitError()}</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
</Show>
|
2023-08-21 11:11:18 +00:00
|
|
|
|
2023-05-18 20:02:19 +00:00
|
|
|
<Show when={isUserNotFount()}>
|
|
|
|
<div class={styles.authSubtitle}>
|
|
|
|
{t("We can't find you, check email or")}{' '}
|
|
|
|
<a
|
|
|
|
href="#"
|
|
|
|
onClick={(event) => {
|
|
|
|
event.preventDefault()
|
2023-09-29 12:48:58 +00:00
|
|
|
changeSearchParam({
|
2023-11-14 15:10:00 +00:00
|
|
|
mode: 'register',
|
2023-09-29 12:48:58 +00:00
|
|
|
})
|
2023-05-18 20:02:19 +00:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
{t('register')}
|
|
|
|
</a>
|
2023-08-30 21:30:15 +00:00
|
|
|
<Show when={validationErrors().email}>
|
|
|
|
<div class={styles.validationError}>{validationErrors().email}</div>
|
|
|
|
</Show>
|
2023-05-18 20:02:19 +00:00
|
|
|
</div>
|
|
|
|
</Show>
|
2023-08-21 11:11:18 +00:00
|
|
|
|
2023-05-18 20:02:19 +00:00
|
|
|
<div>
|
|
|
|
<button class={clsx('button', styles.submitButton)} disabled={isSubmitting()} type="submit">
|
|
|
|
{isSubmitting() ? '...' : t('Restore password')}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
<div class={styles.authControl}>
|
2023-09-29 12:48:58 +00:00
|
|
|
<span
|
|
|
|
class={styles.authLink}
|
|
|
|
onClick={() =>
|
|
|
|
changeSearchParam({
|
2023-11-14 15:10:00 +00:00
|
|
|
mode: 'login',
|
2023-09-29 12:48:58 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
>
|
2023-05-18 20:02:19 +00:00
|
|
|
{t('I know the password')}
|
|
|
|
</span>
|
|
|
|
</div>
|
2022-10-21 18:17:04 +00:00
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
)
|
|
|
|
}
|