import styles from './AuthModal.module.scss' import { clsx } from 'clsx' import { SocialProviders } from './SocialProviders' import { ApiError } from '../../../utils/apiClient' import { createSignal, Show } from 'solid-js' import { email, setEmail } from './sharedLogic' import { useRouter } from '../../../stores/router' import type { AuthModalSearchParams } from './types' import { hideModal } from '../../../stores/ui' import { useSession } from '../../../context/session' import { signSendLink } from '../../../stores/auth' import { validateEmail } from '../../../utils/validateEmail' import { useSnackbar } from '../../../context/snackbar' import { useLocalize } from '../../../context/localize' import { Icon } from '../../_shared/Icon' import { AuthModalHeader } from './AuthModalHeader' type FormFields = { email: string password: string } type ValidationErrors = Partial> export const LoginForm = () => { const { t, lang } = useLocalize() const [submitError, setSubmitError] = createSignal('') const [isSubmitting, setIsSubmitting] = createSignal(false) const [validationErrors, setValidationErrors] = createSignal({}) // TODO: better solution for interactive error messages const [isEmailNotConfirmed, setIsEmailNotConfirmed] = createSignal(false) const [isLinkSent, setIsLinkSent] = createSignal(false) const [showPassword, setShowPassword] = createSignal(false) const authFormRef: { current: HTMLFormElement } = { current: null } const { actions: { showSnackbar } } = useSnackbar() const { actions: { signIn } } = useSession() const { changeSearchParam } = useRouter() const [password, setPassword] = createSignal('') const handleEmailInput = (newEmail: string) => { setValidationErrors(({ email: _notNeeded, ...rest }) => rest) setEmail(newEmail) } const handlePasswordInput = (newPassword: string) => { setValidationErrors(({ password: _notNeeded, ...rest }) => rest) setPassword(newPassword) } const handleSendLinkAgainClick = async (event: Event) => { event.preventDefault() setIsLinkSent(true) setIsEmailNotConfirmed(false) setSubmitError('') const result = await signSendLink({ email: email(), lang: lang(), template: 'email_confirmation' }) if (result.error) setSubmitError(result.error) } const handleSubmit = async (event: Event) => { event.preventDefault() setIsLinkSent(false) setIsEmailNotConfirmed(false) setSubmitError('') const newValidationErrors: ValidationErrors = {} if (!email()) { newValidationErrors.email = t('Please enter email') } else if (!validateEmail(email())) { newValidationErrors.email = t('Invalid email') } if (!password()) { newValidationErrors.password = t('Please enter password') } if (Object.keys(newValidationErrors).length > 0) { setValidationErrors(newValidationErrors) authFormRef.current .querySelector(`input[name="${Object.keys(newValidationErrors)[0]}"]`) .focus() return } setIsSubmitting(true) 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 } } setSubmitError(error.message) } finally { setIsSubmitting(false) } } return (
(authFormRef.current = el)}>
{submitError()}
{t('Send link again')}
{t('Link sent, check your email')}
handleEmailInput(event.currentTarget.value)} />
{validationErrors().email}
handlePasswordInput(event.currentTarget.value)} />
{validationErrors().password}
changeSearchParam('mode', 'register')}> {t('I have no account yet')}
) }