-
-
Save Sutil/5285f2e5a912dcf14fc23393dac97fed to your computer and use it in GitHub Desktop.
"use client"; | |
import { zodResolver } from "@hookform/resolvers/zod"; | |
import { useForm } from "react-hook-form"; | |
import MoneyInput from "src/components/custom/money-input"; | |
import { Button } from "src/components/ui/button"; | |
import { Form } from "src/components/ui/form"; | |
import * as z from "zod"; | |
const schema = z.object({ | |
value: z.coerce.number().min(0.01, "Required"), | |
}); | |
export default function PlanForm() { | |
const form = useForm<z.infer<typeof schema>>({ | |
resolver: zodResolver(schema), | |
defaultValues: { | |
value: 0, | |
}, | |
mode: "onTouched", | |
}); | |
function onSubmit(values: z.infer<typeof schema>) { | |
// handle submit | |
} | |
return ( | |
<Form {...form}> | |
<form | |
className="flex flex-col gap-8" | |
onSubmit={form.handleSubmit(onSubmit)} | |
> | |
<MoneyInput | |
form={form} | |
label="Valor" | |
name="value" | |
placeholder="Valor do plano" | |
/> | |
<Button type="submit" disabled={!form.formState.isValid}> | |
Submit | |
</Button> | |
</form> | |
</Form> | |
); | |
} |
"use client"; | |
import { useReducer } from "react"; | |
import { | |
FormControl, | |
FormField, | |
FormItem, | |
FormLabel, | |
FormMessage, | |
} from "../ui/form"; // Shadcn UI import | |
import { Input } from "../ui/input"; // Shandcn UI Input | |
import { UseFormReturn } from "react-hook-form"; | |
type TextInputProps = { | |
form: UseFormReturn<any>; | |
name: string; | |
label: string; | |
placeholder: string; | |
}; | |
// Brazilian currency config | |
const moneyFormatter = Intl.NumberFormat("pt-BR", { | |
currency: "BRL", | |
currencyDisplay: "symbol", | |
currencySign: "standard", | |
style: "currency", | |
minimumFractionDigits: 2, | |
maximumFractionDigits: 2, | |
}); | |
export default function MoneyInput(props: TextInputProps) { | |
const initialValue = props.form.getValues()[props.name] | |
? moneyFormatter.format(props.form.getValues()[props.name]) | |
: ""; | |
const [value, setValue] = useReducer((_: any, next: string) => { | |
const digits = next.replace(/\D/g, ""); | |
return moneyFormatter.format(Number(digits) / 100); | |
}, initialValue); | |
function handleChange(realChangeFn: Function, formattedValue: string) { | |
const digits = formattedValue.replace(/\D/g, ""); | |
const realValue = Number(digits) / 100; | |
realChangeFn(realValue); | |
} | |
return ( | |
<FormField | |
control={props.form.control} | |
name={props.name} | |
render={({ field }) => { | |
field.value = value; | |
const _change = field.onChange; | |
return ( | |
<FormItem> | |
<FormLabel>{props.label}</FormLabel> | |
<FormControl> | |
<Input | |
placeholder={props.placeholder} | |
type="text" | |
{...field} | |
onChange={(ev) => { | |
setValue(ev.target.value); | |
handleChange(_change, ev.target.value); | |
}} | |
value={value} | |
/> | |
</FormControl> | |
<FormMessage /> | |
</FormItem> | |
); | |
}} | |
/> | |
); | |
} |
Funciona muito bem quando estás a introduzir os dados, mas a apagar ele não funciona
@hspotted, It worked fine here. Let me know what behavior you expect on this.
Screen.Recording.2024-01-15.at.10.14.44.mov
Estou usando o componente e ele funciona perfeitamente, mas quando faço form.reset(data) para recuperar os dados, é o único campo que não atualiza
Estou usando o componente e ele funciona perfeitamente, mas quando faço form.reset(data) para recuperar os dados, é o único campo que não atualiza
Não previ este caso. A linha 51 sempre vai atrapalhar.
Vou ter que mudar a implementação
Eu consegui contornar a situação aqui, adicionei um useEffect no componente para atualizar o valor, e estou passando o value pelo formulário como uma props do componente:
useEffect(() => {
if (props.value) {
setValue((Number(props.value) * 100).toString());
}
}, [props.form, props.value]);
const [balanceValue, setBalanceValue] = useState('');
// setBalanceValue usei onde pego os dados da API
<MoneyInput
form={form}
value={balanceValue}
label="Saldo"
name="balance"
placeholder={!isDataLoading ? 'Saldo da carteira...' : 'Carregando...'}
/>
Eu consegui contornar a situação aqui, adicionei um useEffect no componente para atualizar o valor, e estou passando o value pelo formulário como uma props do componente:
useEffect(() => { if (props.value) { setValue((Number(props.value) * 100).toString()); } }, [props.form, props.value]);
const [balanceValue, setBalanceValue] = useState(''); // setBalanceValue usei onde pego os dados da API <MoneyInput form={form} value={balanceValue} label="Saldo" name="balance" placeholder={!isDataLoading ? 'Saldo da carteira...' : 'Carregando...'} />
Eu resolvi dessa forma e deixou o código um pouco mais limpo:
useEffect(() => { setValue(initialValue); }, [initialValue]);
Mas isso porque nao passo o value
como prop
e continuo utilizando apenas o form
como fonte de dado.
A little late, but here is how I managed the form.reset() outside the component:
const formData = form.watch(name);
useEffect(() => {
const formValue = moneyFormatter.format(Number(formData));
if (formValue !== value) {
setValue(formValue);
}
}, [formData, value])
Funciona muito bem quando estás a introduzir os dados, mas a apagar ele não funciona
Estou tendo esse problema, mas apenas quando pelo celular (chrome mobile).
Pra mim, ao clicar backspack ele apaga, mas move o cursor uma casa a esquerda.
WhatsApp.Video.2024-06-03.at.21.02.51.mp4
No pc está impecável.
Tenta colocar o attribute inputmode
= decimal
Funciona muito bem quando estás a introduzir os dados, mas a apagar ele não funciona