import { clsx } from 'clsx' import { JSX, Show, createSignal } from 'solid-js' import { useSnackbar, useUI } from '~/context/ui' import { useLocalize } from '../../../context/localize' import { useSession } from '../../../context/session' import { validateEmail } from '../../../utils/validateEmail' import { AuthModalHeader } from './AuthModalHeader' import { PasswordField } from './PasswordField' import { SocialProviders } from './SocialProviders' import { email, setEmail } from './sharedLogic' import { useSearchParams } from '@solidjs/router' import styles from './AuthModal.module.scss' type FormFields = { email: string password: string } type ValidationErrors = Partial> export const LoginForm = () => { const { hideModal } = useUI() const [, setSearchParams] = useSearchParams() const { t } = useLocalize() const [submitError, setSubmitError] = createSignal() const [isSubmitting, setIsSubmitting] = createSignal(false) const [password, setPassword] = createSignal('') const [validationErrors, setValidationErrors] = createSignal({}) // FIXME: use signal or remove const [_isLinkSent, setIsLinkSent] = createSignal(false) let authFormRef: HTMLFormElement const { showSnackbar } = useSnackbar() const { signIn, authError } = useSession() const handleEmailInput = (newEmail: string) => { setValidationErrors(({ email: _notNeeded, ...rest }) => rest) setEmail(newEmail.toLowerCase()) } const handlePasswordInput = (newPassword: string) => { setValidationErrors(({ password: _notNeeded, ...rest }) => rest) setPassword(newPassword) } const handleSendLinkAgainClick = (event: Event) => { event.preventDefault() setIsLinkSent(true) setSubmitError() setSearchParams({ mode: 'send-confirm-email' }) } const preSendValidate = async (value: string, type: 'email' | 'password'): Promise => { if (type === 'email') { if (value === '' || !validateEmail(value)) { setValidationErrors((prev) => ({ ...prev, email: t('Invalid email') })) return false } } else if (type === 'password') { if (value === '') { setValidationErrors((prev) => ({ ...prev, password: t('Please enter password') })) return false } } return true } const handleSubmit = async (event: Event) => { event.preventDefault() await preSendValidate(email(), 'email') await preSendValidate(password(), 'password') setIsLinkSent(false) setSubmitError() if (Object.keys(validationErrors()).length > 0) { authFormRef .querySelector(`input[name="${Object.keys(validationErrors())[0]}"]`) ?.focus() return } setIsSubmitting(true) try { const success = await signIn({ email: email(), password: password() }) if (!success) { switch (authError()) { case 'user has not signed up email & password': case 'bad user credentials': { setValidationErrors((prev) => ({ ...prev, password: t('Something went wrong, check email and password') })) break } case 'user not found': { setValidationErrors((prev) => ({ ...prev, email: t('User was not found') })) break } case 'email not verified': { setValidationErrors((prev) => ({ ...prev, email: t('This email is not verified') })) break } default: setSubmitError(
{t('Error', authError())} {'. '} {t('Send link again')}
) } } hideModal() showSnackbar({ body: t('Welcome!') }) } catch (error) { console.error(error) setSubmitError(authError()) } finally { setIsSubmitting(false) } } return (
(authFormRef = el)}>
handleEmailInput(event.currentTarget.value)} />
{validationErrors().email}
handlePasswordInput(value)} />
{submitError()}
setSearchParams({ mode: 'send-reset-link' }) } > {t('Forgot password?')}
setSearchParams({ mode: 'register' }) } > {t('I have no account yet')}
) }