app/javascript/components/Users/SignIn/index.tsx
import React from 'react'
import { Link, useNavigate, useLocation } from 'react-router-dom'
import { Formik, Field, FormikHelpers } from 'formik'
import toast from 'react-hot-toast'
import { useLoginMutation } from 'api/sessions'
import Separator from 'components/Users/Separator'
import { useI18n } from 'components/TranslationsProvider'
import validationSchema from './validationSchema'
import styles from 'components/Users/styles.module.scss'
import RequestErrorToast from 'components/RequestErrorToast'
interface FormValues {
email: string
password: string
}
const initialValues = { email: '', password: '' }
const SignIn = (): JSX.Element => {
const navigate = useNavigate()
const location = useLocation()
const { t } = useI18n()
const loginMutation = useLoginMutation()
const returnTo = location.state?.returnTo ?? '/'
const handleSubmit = async (
values: FormValues,
formikBag: FormikHelpers<FormValues>
) => {
loginMutation.mutate(values, {
onSuccess: () => navigate(returnTo),
onSettled: () => formikBag.setSubmitting(false),
onError: error => {
toast.error(<RequestErrorToast response={error.response} />)
}
})
}
return (
<Formik
initialValues={initialValues}
onSubmit={handleSubmit}
validationSchema={validationSchema}
>
{({ touched, errors, handleSubmit, isSubmitting }) => (
<form onSubmit={handleSubmit} className={styles.container}>
{loginMutation.error && (
<p className={styles.serverError}>
{loginMutation.error.response?.data?.error || loginMutation.error.message}
</p>
)}
<div>
<Field
autoFocus
name="email"
className={styles.input}
placeholder="Email"
autoComplete="username"
data-invalid={errors.email && touched.email}
/>
{errors.email && touched.email && (
<span className={styles.error}>{errors.email}</span>
)}
</div>
<div>
<Field
name="password"
className={styles.input}
type="password"
placeholder="Password"
autoComplete="current-password"
data-invalid={errors.password && touched.password}
/>
{errors.password && touched.password && (
<span className={styles.error}>{errors.password}</span>
)}
</div>
<Link to="/users/forgot-password" className={styles.link}>
{t('devise.shared.links.forgot_your_password')}
</Link>
<button type="submit" className={styles.primaryButton} disabled={isSubmitting}>
{t('devise.sessions.new.sign_in')}
</button>
<Separator>{t('general.or')}</Separator>
<Link to="/users/sign-up" className={styles.secondaryButton}>
{t('devise.shared.links.sign_up')}
</Link>
<a href="/users/auth/facebook" className={styles.secondaryButton}>
{t('devise.shared.links.sign_in_with_provider', { provider: 'Facebook' })}
</a>
</form>
)}
</Formik>
)
}
export default SignIn