Improve form field behavior, phone formatting
This commit is contained in:
parent
135f456543
commit
1e186e5296
8 changed files with 78 additions and 19 deletions
|
|
@ -3,12 +3,13 @@ import { FormInput } from './FormInput'
|
|||
|
||||
export const EmailInput = (props: ComponentProps<'input'>) => (
|
||||
<FormInput
|
||||
form="email"
|
||||
name="email"
|
||||
id="email"
|
||||
placeholder="Digite seu e-mail"
|
||||
autoComplete="email"
|
||||
inputMode="email"
|
||||
type="text"
|
||||
minLength={5}
|
||||
maxLength={254}
|
||||
required
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,43 @@
|
|||
import type { ComponentProps } from 'react'
|
||||
'use client'
|
||||
|
||||
import { ChangeEventHandler, type ComponentProps } from 'react'
|
||||
import { Input } from './ui/input'
|
||||
import { useFormContext } from 'react-hook-form'
|
||||
import {
|
||||
type FieldPath,
|
||||
type FieldValues,
|
||||
type RegisterOptions,
|
||||
useFormContext,
|
||||
} from 'react-hook-form'
|
||||
|
||||
interface FormInpuProps extends ComponentProps<'input'> {
|
||||
form: string
|
||||
interface FormInpuProps<
|
||||
TFieldValues extends FieldValues,
|
||||
TFieldName extends FieldPath<TFieldValues>,
|
||||
> extends ComponentProps<'input'> {
|
||||
name: TFieldName
|
||||
options?: RegisterOptions<TFieldValues, TFieldName>
|
||||
format?: (value: string) => string
|
||||
}
|
||||
|
||||
export const FormInput = ({ form, ...props }: FormInpuProps) => {
|
||||
const { register } = useFormContext()
|
||||
export const FormInput = <
|
||||
TFieldValues extends FieldValues,
|
||||
TFieldName extends FieldPath<TFieldValues>,
|
||||
>({
|
||||
name,
|
||||
options,
|
||||
format,
|
||||
onChange,
|
||||
...props
|
||||
}: FormInpuProps<TFieldValues, TFieldName>) => {
|
||||
const { register } = useFormContext<TFieldValues>()
|
||||
const { onChange: onValueChange, ...registerResult } = register(name, options)
|
||||
|
||||
return <Input {...props} {...register(form)} />
|
||||
const handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
const targetValue = e.target.value
|
||||
const formattedValue = format?.(targetValue) ?? targetValue
|
||||
e.target.value = formattedValue
|
||||
onValueChange(e)
|
||||
onChange?.(e)
|
||||
}
|
||||
|
||||
return <Input {...props} {...registerResult} onChange={handleChange} />
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@ import { FormInput } from './FormInput'
|
|||
|
||||
export const NameInput = (props: ComponentProps<'input'>) => (
|
||||
<FormInput
|
||||
form="name"
|
||||
name="name"
|
||||
id="name"
|
||||
type="text"
|
||||
placeholder="Digite seu nome completo"
|
||||
autoComplete="name"
|
||||
maxLength={120}
|
||||
minLength={2}
|
||||
required
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -3,14 +3,30 @@ import { FormInput } from './FormInput'
|
|||
|
||||
export const PhoneInput = (props: ComponentProps<'input'>) => (
|
||||
<FormInput
|
||||
form="phone"
|
||||
name="phone"
|
||||
id="phone"
|
||||
placeholder="(71) 99999-9999"
|
||||
autoComplete="tel"
|
||||
inputMode="tel"
|
||||
type="tel"
|
||||
maxLength={15}
|
||||
required
|
||||
minLength={15}
|
||||
format={formatPhone}
|
||||
options={{
|
||||
setValueAs: sanitizePhone,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
const sanitizePhone = (value: string) => value.replace(/\D/g, '').slice(0, 11)
|
||||
|
||||
const formatPhone = (value: string) => {
|
||||
const digits = sanitizePhone(value)
|
||||
|
||||
if (!digits) return ''
|
||||
if (digits.length <= 2) return `(${digits}`
|
||||
if (digits.length <= 7) return `(${digits.slice(0, 2)}) ${digits.slice(2)}`
|
||||
|
||||
return `(${digits.slice(0, 2)}) ${digits.slice(2, 7)}-${digits.slice(7)}`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,5 +2,12 @@ import type { ComponentProps } from 'react'
|
|||
import { FormInput } from './FormInput'
|
||||
|
||||
export const PostalCodeInput = (props: ComponentProps<'input'>) => (
|
||||
<FormInput form="postalCode" id="postalCode" type="text" placeholder="00000-000" {...props} />
|
||||
<FormInput
|
||||
name="postalCode"
|
||||
id="postalCode"
|
||||
type="text"
|
||||
placeholder="00000-000"
|
||||
pattern="^(?:\d{8})?$"
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ interface StateSelectProps {
|
|||
placeholder?: string
|
||||
}
|
||||
|
||||
export const StateSelect = ({ placeholder = 'Selecione um estado' }) => {
|
||||
export const StateSelect = ({ placeholder = 'Selecione um estado' }: StateSelectProps) => {
|
||||
const { register } = useFormContext()
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { Textarea } from '@/components/ui/textarea'
|
|||
import { WhatsAppFormInput, whatsAppFormSchema } from '@/lib/schemas/whatsapp-form'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { FormProvider, SubmitHandler, useForm } from 'react-hook-form'
|
||||
import { useTransition } from 'react'
|
||||
import { useEffect, useTransition } from 'react'
|
||||
import { submitWhatsapp } from '@/app/(frontend)/actions/submitWhatsapp'
|
||||
|
||||
interface WhatsappFormProps {
|
||||
|
|
@ -40,7 +40,8 @@ export const WhatsappForm = ({ classname, onSubmit }: WhatsappFormProps) => {
|
|||
await submitWhatsapp(input)
|
||||
methods.reset()
|
||||
onSubmit()
|
||||
} catch {
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
methods.setError('root', {
|
||||
message: 'Falha ao enviar assinatura. Tente novamente.',
|
||||
})
|
||||
|
|
@ -78,11 +79,15 @@ export const WhatsappForm = ({ classname, onSubmit }: WhatsappFormProps) => {
|
|||
id="comment"
|
||||
{...methods.register('comment')}
|
||||
placeholder='Campo de Interesse: "O que você mais quer ver no canal?" (Votações, Bastidores, Ações Sociais, Agenda).'
|
||||
required
|
||||
className="min-h-22"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
{methods.formState.errors.root?.message ? (
|
||||
<FieldDescription className="text-destructive">
|
||||
{methods.formState.errors.root.message}
|
||||
</FieldDescription>
|
||||
) : null}
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import * as React from 'react'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ComponentProps } from 'react'
|
||||
|
||||
function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
||||
function Input({ className, type, ...props }: ComponentProps<'input'>) {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
|
|
|
|||
Loading…
Reference in a new issue