import { cn } from "@/lib/utils"; import { FormControl, FormDescription, FormField, FormItem, InputProps } from "@/ui"; import { CurrencyData, Language, MoneyValue, MoneyValueObject } from "@shared/contexts"; import { cva, type VariantProps } from "class-variance-authority"; import * as React from "react"; import CurrencyInput, { CurrencyInputOnChangeValues } from "react-currency-input-field"; import { FieldPath, FieldValues, UseControllerProps, useFormContext } from "react-hook-form"; import { FormErrorMessage } from "./FormErrorMessage"; import { FormLabel, FormLabelProps } from "./FormLabel"; import { FormInputProps, FormInputWithIconProps } from "./FormProps"; const formCurrencyFieldVariants = cva( "flex h-10 w-full rounded-md bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50", { variants: { variant: { default: "border border-input ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ", outline: "focus-visible:border focus-visible:border-input", }, }, defaultVariants: { variant: "default", }, } ); export type FormCurrencyFieldProps< TFieldValues extends FieldValues = FieldValues, TName extends FieldPath = FieldPath > = { button?: (props?: React.PropsWithChildren) => React.ReactNode; defaultValue?: any; } & InputProps & FormInputProps & Partial & FormInputWithIconProps & UseControllerProps & VariantProps & { currency: CurrencyData; language: Language; scale: number; }; export const FormCurrencyField = React.forwardRef( (props, ref) => { const { name, label, hint, description, placeholder, className, disabled, defaultValue, rules, readOnly, scale, currency, language, variant, } = props; const { control } = useFormContext(); const [inputValue, setInputValue] = React.useState(""); const transform = { input: (value: MoneyValueObject) => { if (typeof value !== "object") { return value; } const moneyOrError = MoneyValue.create(value); if (moneyOrError.isFailure) { throw moneyOrError.error; } const result = moneyOrError.object.toString(); return inputValue.endsWith(",") ? result.replace(/.0$/, ",") : result; }, output: (value: string | undefined, name?: string, values?: CurrencyInputOnChangeValues) => { const { value: amount } = values ?? { value: null }; setInputValue(amount ?? ""); const moneyOrError = MoneyValue.createFromFormattedValue(amount, currency.code); if (moneyOrError.isFailure) { throw moneyOrError.error; } return moneyOrError.object.toObject(); }, }; return ( { return ( {label && ( )} {}} onValueChange={(value, name, values) => field.onChange(transform.output(value, name, values)) } /> {description && {description}} ); }} /> ); } ); FormCurrencyField.displayName = "FormCurrencyField";