Closed Vitu-77 closed 6 months ago
duplicate - https://github.com/nextui-org/nextui/issues/2844
as a workaround for the time being, you can use validate
to update the state. I'm currently looking into this issue.
@Vitu-77 can you also paste the code here? so that I could have one more example to test.
import { useCallback, useMemo, useState } from 'react'
import { LuEye, LuEyeOff, LuLock, LuLogIn, LuUser } from 'react-icons/lu'
import { useQuery } from 'react-query'
import { Link } from 'react-router-dom'
import { z } from 'zod'
import { Button, Checkbox, Input } from '@nextui-org/react'
import { useForm } from '@core/hooks'
import { QueryKeysEnum, RoutesEnum } from '@domain/enums'
import { signIn } from '@infra/services/requests/auth'
import { SignInPayload } from '@infra/services/requests/auth.dto'
const DEFAULT_PAYLOAD: SignInPayload = {
email: '',
password: '',
}
const LoginForm = () => {
const [visiblePass, setVisiblePass] = useState(false)
const togglePassVisibility = useCallback(() => {
setVisiblePass((prev) => !prev)
}, [])
const [payload, setPayload] = useState<SignInPayload>(DEFAULT_PAYLOAD)
const query = useQuery([QueryKeysEnum.SIGN_IN, payload], {
enabled: !!payload.email && !!payload.password,
queryFn: () => signIn(payload),
// onSuccess: (data) => console.log(data),
// onError: (error) => console.log(error),
})
const passInputIcon = useMemo(() => {
const Icon = visiblePass ? LuEyeOff : LuEye
return (
<Icon
onClick={togglePassVisibility}
className='text-2xl text-foreground-400 cursor-pointer hover:text-foreground-700'
/>
)
}, [togglePassVisibility, visiblePass])
const [formRef, formErrors] = useForm({
validationSchema: z.object({
email: z
.string()
.min(1, 'Informe seu email ou CPF')
.email('CPF ou email inválido'),
password: z.string().min(1, 'Informe sua senha'),
}),
onSubmit: (data) => {
if (data) {
setPayload(data)
}
},
})
return (
<div className='w-full flex flex-col gap-6 items-center'>
<form ref={formRef} className='w-full flex flex-col gap-2'>
<Input
defaultValue='marcelo.victor05@gmail.com'
name='email'
radius='sm'
isDisabled={query.isLoading}
isInvalid={!!formErrors?.email}
errorMessage={formErrors?.email}
label={<span className='text-foreground-400'>Email ou CPF</span>}
variant='bordered'
placeholder='Informe seu email ou CPF'
startContent={<LuUser className='text-lg text-foreground-200 mr-2' />}
labelPlacement='outside'
/>
<Input
defaultValue='Arsenalvic12345'
name='password'
className='w-full'
radius='sm'
isDisabled={query.isLoading}
label={<span className='text-foreground-400'>Senha</span>}
type={visiblePass ? 'text' : 'password'}
variant='bordered'
isInvalid={!!formErrors?.password}
errorMessage={formErrors?.password}
placeholder='Entre com sua senha de acesso'
endContent={passInputIcon}
startContent={<LuLock className='text-lg text-foreground-200 mr-2' />}
labelPlacement='outside'
description={
<div className='w-full flex justify-end relative'>
<small className='text-xs text-primary cursor-pointer hover:text-primary-600 absolute right-0 top-[-64px] hover:underline'>
Esqueceu a senha?
</small>
</div>
}
/>
<Checkbox size='md' color='primary' radius='sm' className='mb-1.5'>
<span className='text-foreground-500 text-sm'>
Manter-me conectado
</span>
</Checkbox>
<Button
type='submit'
radius='sm'
color='primary'
isLoading={query.isLoading}
className='flex items-center'
>
Entrar
<LuLogIn className='text-lg' />
</Button>
</form>
<span className='w-full text-center text-sm text-foreground-500'>
Ainda não possui uma conta?{' '}
<Link
className='text-primary-500 hover:underline hover:text-primary-600'
to={RoutesEnum.REGISTER}
>
Registre-se
</Link>
</span>
</div>
)
}
export default LoginForm
import { useCallback, useEffect, useRef, useState } from 'react'
import { ZodError, ZodObjectDef, ZodType } from 'zod'
type ZodSchema<DataType> = ZodType<DataType, ZodObjectDef>
type ValidationError<DataType> = Partial<Record<keyof DataType, string>>
type Props<DataType> = {
validationSchema?: ZodSchema<DataType>
onSubmit: (data: DataType | null) => any | Promise<any>
}
type Response<DataType> = [
React.MutableRefObject<HTMLFormElement | null>,
ValidationError<DataType> | null,
]
export default function useForm<DataType>({
validationSchema,
onSubmit,
}: Props<DataType>): Response<DataType> {
const ref = useRef<HTMLFormElement | null>(null)
const [error, setError] = useState<ValidationError<DataType> | null>(null)
const getData = useCallback(() => {
if (!ref.current) {
return null
}
const formValue: Record<string, any> = {}
const formData = new FormData(ref.current)
for (const [key, value] of Array.from(formData.entries())) {
formValue[key] = value
}
return validationSchema
? validationSchema.parse(formValue)
: (formValue as DataType)
}, [validationSchema])
const handleFormSubmit = useCallback(
(e: SubmitEvent) => {
e.preventDefault()
try {
const data = getData()
setError(null)
return onSubmit(data)
} catch (err) {
const e = err as ZodError<DataType>
const errorResponse = {} as ValidationError<DataType>
const formError = e.errors.reduce(
(e, item) => ({
...e,
[item.path[0]]: item.message,
}),
errorResponse
)
setError(formError)
return onSubmit(null)
}
},
[getData, onSubmit]
)
useEffect(() => {
const form = ref.current
if (form) {
form.addEventListener('submit', handleFormSubmit)
return () => form.removeEventListener('submit', handleFormSubmit)
}
}, [error, handleFormSubmit])
return [ref, error]
}
NextUI Version
latest
Describe the bug
When Input prop "isInvalid" changes to true, the form submit event is being blocked and not triggered
Your Example Website or App
No response
Steps to Reproduce the Bug or Issue
<Input isInvalid={error.password !== null} />
When some validation error ocurs, it will change Input states to invalid and the submit function will not be trigerred anymore, and how validation is being treated inside submit function, the form state will freeze.
Expected behavior
As a user, i expect that submit function could be trigerred however the input states.
Screenshots or Videos
Form Code
Behavior example
https://github.com/nextui-org/nextui/assets/57647656/fc77cb22-0a1f-454e-a49d-a4cb23217471
Operating System Version
Windows
Browser
Chrome