import { ReactNode, useEffect, useMemo } from "react"; import { ControllerRenderProps } from "react-hook-form"; import Decimal from "decimal.js"; import { Asset, useAssets } from "../useAssets"; import { useDisplayDecimalDigits } from "../useDisplayDecimalDigits"; import { useMarkets } from "../useMarkets"; import { ConvertContext, ConvertFormProps } from "./context"; import { useConvertAmountValidation } from "./useConvertAmountValidation"; import { useConvertConfigMarket } from "./useConvertConfigs"; import { useUpdatePreview } from "./useUpdatePreview"; type ConvertToRenderProps = { render: (state: { field: ControllerRenderProps & { onSelect: (asset?: Asset) => void; assets: Asset[]; asset?: Asset; fromAsset?: string; minQuantity?: number; maxQuantity?: number; hasError?: boolean; getMaxSize?: (value: string | number | Decimal) => string; onFocus?: () => void; stepSize?: number; }; }) => React.ReactElement; type: "market" | "limit"; renderErrorComponent?: (message?: string) => ReactNode; }; export const ConvertToController = ({ render, renderErrorComponent, type, }: ConvertToRenderProps) => { const { toAsset, toAmount, fromAsset, lastChangedField, price, fromAmount } = ConvertContext.useWatch(); const { resetRefreshCount } = useUpdatePreview({ mode: "to", type: type }); const { marketsSymbols } = useMarkets(); const { setValue, clearErrors, register } = ConvertContext.useFormContext(); const { truncFix } = useDisplayDecimalDigits(); const { errors } = ConvertContext.useFormState(); const { filterLotSize, filterPrice, getMaxSize, selectedCurrency } = useConvertConfigMarket({ mode: "to", type }); register("lastChangedField"); const { checkAmount, minimumTo, maximumTo } = useConvertAmountValidation(); const { allAssets } = useAssets(); const filteredAssets = useMemo(() => { return ( allAssets?.filter( ({ canTrade, symbol }) => canTrade && symbol !== fromAsset, ) || [] ); }, [allAssets, fromAsset]); useEffect(() => { if (selectedCurrency) return; const _asset = allAssets?.find( (item) => item.symbol?.toLowerCase() === toAsset?.toLowerCase(), ); setValue("toAsset", _asset?.name); // eslint-disable-next-line react-hooks/exhaustive-deps }, [marketsSymbols, selectedCurrency, fromAsset]); const canThrowError = errors["toAmount"] && toAmount !== null && toAmount !== undefined; useEffect(() => { !toAsset && filteredAssets.length && setValue("toAsset", filteredAssets?.[0].symbol); // eslint-disable-next-line react-hooks/exhaustive-deps }, [filteredAssets, toAsset]); return ( <> { return checkAmount(value, "to"); }, }, }} render={({ field: { onChange, value, ...rest } }) => { const multiple = new Decimal(Number(fromAmount)).mul( new Decimal(Number(price)), ); const result = truncFix(Number(multiple), toAsset).toString() === "0" ? undefined : truncFix(Number(multiple), toAsset).toString(); return render({ field: { value: type === "limit" ? result : value, minQuantity: type === "limit" ? undefined : minimumTo, maxQuantity: type === "limit" ? undefined : maximumTo, assets: filteredAssets || [], asset: selectedCurrency, getMaxSize: getMaxSize, fromAsset, hasError: value ? !!errors.toAmount : false, onSelect: async (asset?: Asset) => { if (selectedCurrency?.symbol !== asset?.symbol) { onChange(""); setValue("fromAmount", ""); type === "limit" && setValue("price", ""); const symbol = await new Promise( (res) => { res(asset?.symbol); }, ); setValue("toAsset", symbol); } }, onFocus() { lastChangedField !== "to" && setValue("lastChangedField", "to"); }, onChange: (value) => { if (value === "") { setValue("fromAmount", ""); } resetRefreshCount(); setValue("lastChangedField", "to"); clearErrors("fromAmount"); onChange(value); }, stepSize: selectedCurrency?.currencyType === "Fiat" ? filterPrice?.tickSize : filterLotSize?.stepSize, ...rest, }, }); }} /> {renderErrorComponent && renderErrorComponent?.( canThrowError ? errors["toAmount"]?.message : "", )} ); };