import { ReactNode, useMemo } from "react"; import { ControllerRenderProps } from "react-hook-form"; import Decimal from "decimal.js"; import { Asset, useAssets } from "../useAssets"; import { ConvertContext, ConvertFormProps } from "./context"; import { useConvertAmountValidation } from "./useConvertAmountValidation"; import { useConvertConfigMarket } from "./useConvertConfigs"; import { useUpdatePreview } from "./useUpdatePreview"; type ConvertFromRenderProps = { render: (state: { field: ControllerRenderProps & { onSelect: (asset?: Asset) => void; assets: Asset[]; asset: Asset | undefined; getMaxSize?: (value: string | number | Decimal) => string; minQuantity?: number; maxQuantity?: number; hasError?: boolean; onFocus?: () => void; stepSize?: number; }; }) => React.ReactElement; type: "market" | "limit"; renderErrorComponent?: (message?: string) => ReactNode; }; export const ConvertFromController = ({ render, renderErrorComponent, type, }: ConvertFromRenderProps) => { const { toAsset, fromAmount, lastChangedField } = ConvertContext.useWatch(); const { resetRefreshCount } = useUpdatePreview({ mode: "from", type: type, }); const { filterLotSize, filterPrice, getMaxSize, selectedCurrency } = useConvertConfigMarket({ mode: "from", type }); const { minimumFrom, maximumFrom, checkAmount } = useConvertAmountValidation(); const { setValue, clearErrors, register } = ConvertContext.useFormContext(); const { errors } = ConvertContext.useFormState(); register("lastChangedField"); const { allAssets } = useAssets(); const canThrowError = errors["fromAmount"] && fromAmount !== null && fromAmount !== undefined; const filteredAssets = useMemo(() => { return ( allAssets?.filter( ({ canTrade, symbol }) => canTrade && symbol !== toAsset, ) || [] ); }, [allAssets, toAsset]); return ( <> { return checkAmount(value, "from"); }, }, }} render={({ field: { onChange, value, ...rest } }) => { return render({ field: { value: value, minQuantity: minimumFrom, maxQuantity: maximumFrom, assets: filteredAssets, asset: selectedCurrency, getMaxSize: getMaxSize, hasError: value ? !!errors.fromAmount : false, onSelect: async (asset?: Asset) => { if (selectedCurrency?.symbol !== asset?.symbol) { onChange(""); setValue("toAmount", ""); if (type === "limit") { setValue("price", ""); } const symbol = await new Promise( (res) => { res(asset?.symbol); }, ); setValue("fromAsset", symbol); clearErrors(); } }, onFocus() { lastChangedField !== "from" && setValue("lastChangedField", "from"); }, onChange: (value) => { if (value === "") { setValue("toAmount", ""); } resetRefreshCount(); setValue("lastChangedField", "from"); clearErrors(); onChange(value); }, stepSize: selectedCurrency?.currencyType === "Fiat" ? filterPrice?.tickSize : filterLotSize?.stepSize, ...rest, }, }); }} /> {renderErrorComponent && renderErrorComponent?.( canThrowError ? errors["fromAmount"]?.message : "", )} ); };