fix(next): adds client-side field validations to login and forgot-password views (#5871)

This commit is contained in:
Patrik
2024-04-16 10:36:37 -04:00
committed by GitHub
parent 7369da3d8d
commit 6669a2cedb
4 changed files with 128 additions and 46 deletions

View File

@@ -0,0 +1,81 @@
'use client'
import type { FormState, PayloadRequest } from 'payload/types'
import { Email } from '@payloadcms/ui/fields/Email'
import { Form } from '@payloadcms/ui/forms/Form'
import { FormSubmit } from '@payloadcms/ui/forms/Submit'
import { useConfig } from '@payloadcms/ui/providers/Config'
import { useTranslation } from '@payloadcms/ui/providers/Translation'
import { email } from 'payload/fields/validations'
import React, { Fragment, useState } from 'react'
import { toast } from 'react-toastify'
export const ForgotPasswordForm: React.FC = () => {
const config = useConfig()
const {
admin: { user: userSlug },
routes: { api },
} = config
const { t } = useTranslation()
const [hasSubmitted, setHasSubmitted] = useState(false)
const handleResponse = (res) => {
res.json().then(
() => {
setHasSubmitted(true)
},
() => {
toast.error(t('authentication:emailNotValid'))
},
)
}
const initialState: FormState = {
email: {
initialValue: '',
valid: true,
value: undefined,
},
}
if (hasSubmitted) {
return (
<Fragment>
<h1>{t('authentication:emailSent')}</h1>
<p>{t('authentication:checkYourEmailForPasswordReset')}</p>
</Fragment>
)
}
return (
<Form
action={`${api}/${userSlug}/forgot-password`}
handleResponse={handleResponse}
initialState={initialState}
method="POST"
>
<h1>{t('authentication:forgotPassword')}</h1>
<p>{t('authentication:forgotPasswordEmailInstructions')}</p>
<Email
autoComplete="email"
label={t('general:email')}
name="email"
required
validate={(value) =>
email(value, {
name: 'email',
type: 'email',
data: {},
req: { t } as PayloadRequest,
required: true,
siblingData: {},
})
}
/>
<FormSubmit>{t('general:submit')}</FormSubmit>
</Form>
)
}

View File

@@ -2,12 +2,11 @@ import type { AdminViewProps } from 'payload/types'
import { Button } from '@payloadcms/ui/elements/Button'
import { Translation } from '@payloadcms/ui/elements/Translation'
import { Email } from '@payloadcms/ui/fields/Email'
import { Form } from '@payloadcms/ui/forms/Form'
import { FormSubmit } from '@payloadcms/ui/forms/Submit'
import LinkImport from 'next/link.js'
import React, { Fragment } from 'react'
import { ForgotPasswordForm } from './ForgotPasswordForm/index.js'
export { generateForgotPasswordMetadata } from './meta.js'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
@@ -23,22 +22,9 @@ export const ForgotPasswordView: React.FC<AdminViewProps> = ({ initPageResult })
} = initPageResult
const {
admin: { user: userSlug },
routes: { admin, api },
serverURL,
routes: { admin },
} = config
// const handleResponse = (res) => {
// res.json().then(
// () => {
// setHasSubmitted(true)
// },
// () => {
// toast.error(i18n.t('authentication:emailNotValid'))
// },
// )
// }
if (user) {
return (
<Fragment>
@@ -60,34 +46,9 @@ export const ForgotPasswordView: React.FC<AdminViewProps> = ({ initPageResult })
)
}
// if (hasSubmitted) {
// return (
// <Fragment>
// <h1>{i18n.t('authentication:emailSent')}</h1>
// <p>{i18n.t('authentication:checkYourEmailForPasswordReset')}</p>
// </Fragment>
// )
// }
return (
<Fragment>
<Form
action={`${serverURL}${api}/${userSlug}/forgot-password`}
// handleResponse={handleResponse}
initialState={{
email: {
initialValue: '',
valid: false,
value: undefined,
},
}}
method="POST"
>
<h1>{i18n.t('authentication:forgotPassword')}</h1>
<p>{i18n.t('authentication:forgotPasswordEmailInstructions')}</p>
<Email autoComplete="email" label={i18n.t('general:emailAddress')} name="email" required />
<FormSubmit>{i18n.t('general:submit')}</FormSubmit>
</Form>
<ForgotPasswordForm />
<Link href={`${admin}/login`}>{i18n.t('authentication:backToLogin')}</Link>
</Fragment>
)

View File

@@ -6,7 +6,7 @@ import React from 'react'
const baseClass = 'login__form'
const Link = (LinkImport.default || LinkImport) as unknown as typeof LinkImport.default
import type { FormState } from 'payload/types'
import type { FormState, PayloadRequest } from 'payload/types'
import { FormLoadingOverlayToggle } from '@payloadcms/ui/elements/Loading'
import { Email } from '@payloadcms/ui/fields/Email'
@@ -15,6 +15,7 @@ import { Form } from '@payloadcms/ui/forms/Form'
import { FormSubmit } from '@payloadcms/ui/forms/Submit'
import { useConfig } from '@payloadcms/ui/providers/Config'
import { useTranslation } from '@payloadcms/ui/providers/Translation'
import { email, password } from 'payload/fields/validations'
import './index.scss'
@@ -57,8 +58,43 @@ export const LoginForm: React.FC<{
>
<FormLoadingOverlayToggle action="loading" name="login-form" />
<div className={`${baseClass}__inputWrap`}>
<Email autoComplete="email" label={t('general:email')} name="email" required />
<Password autoComplete="off" label={t('general:password')} name="password" required />
<Email
autoComplete="email"
label={t('general:email')}
name="email"
required
validate={(value) =>
email(value, {
name: 'email',
type: 'email',
data: {},
req: { t } as PayloadRequest,
required: true,
siblingData: {},
})
}
/>
<Password
autoComplete="off"
label={t('general:password')}
name="password"
required
validate={(value) =>
password(value, {
name: 'password',
type: 'text',
data: {},
req: {
payload: {
config,
},
t,
} as PayloadRequest,
required: true,
siblingData: {},
})
}
/>
</div>
<Link href={`${admin}/forgot`}>{t('authentication:forgotPasswordQuestion')}</Link>
<FormSubmit>{t('authentication:login')}</FormSubmit>

View File

@@ -6,6 +6,7 @@ export const clientTranslationKeys = [
'authentication:backToLogin',
'authentication:beginCreateFirstUser',
'authentication:changePassword',
'authentication:checkYourEmailForPasswordReset',
'authentication:confirmGeneration',
'authentication:confirmPassword',
'authentication:createFirstUser',
@@ -222,10 +223,13 @@ export const clientTranslationKeys = [
'upload:sizesFor',
'upload:width',
'validation:emailAddress',
'validation:fieldHasNo',
'validation:limitReached',
'validation:longerThanMin',
'validation:required',
'validation:requiresAtLeast',
'validation:shorterThanMax',
'version:aboutToPublishSelection',
'version:aboutToRestore',