import { useCallback, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { useAuth } from "react-oidc-js"; import moment from "moment-jalaali"; import starkString from "starkstring"; import { usePostOtcV1PrivateOtcConvertConfirm, usePostOtcV1PrivateOtcConvertLimit, usePostOtcV1PrivateOtcConvertMarket, usePostOtcV1PublicOtcConvertPreview, } from "../../services"; import { useAssets } from "../useAssets"; import { ConvertContext, ConvertProps } from "./context"; type OrderProps = { triggerBeforeOrder?: () => Promise | void; }; export const useConvert = ({ type, onError, onSuccess, validityDurationInSecond, }: ConvertProps) => { if (typeof ConvertContext.context === "undefined") { throw new Error("You must use this hook under the ConvertProvider."); } const { userData } = useAuth(); const { t } = useTranslation(); const { setValue, handleSubmit, getValues, setError, getFieldState } = ConvertContext.useFormContext(); const { allAssets } = useAssets(); useEffect(() => { const { fromAsset } = getValues(); if (fromAsset === undefined) { const BTC = allAssets?.find( ({ symbol }) => symbol?.toUpperCase() === "BTC", ); const symbol = BTC?.symbol ? BTC?.symbol : allAssets?.[0]?.symbol; setValue("fromAsset", symbol); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [allAssets]); const { mutate: confirmMarket, isLoading: isLoadingMarketOrder, error: errorMarketOrder, reset: resetMarketOrder, } = usePostOtcV1PrivateOtcConvertConfirm({ onSuccess: (data) => { setValue("fromAmount", ""); setValue("toAmount", ""); onSuccess?.(data); setValue("isPreviewOpen", false); }, onError: (error) => { onError?.(error); }, }); const { mutate: confirmLimit, isLoading: isLoadingLimitOrder, error: errorLimitOrder, reset: resetLimitOrder, } = usePostOtcV1PrivateOtcConvertLimit({ onSuccess: (data) => { setValue("fromAmount", ""); setValue("toAmount", ""); onSuccess?.(data); setValue("isPreviewOpen", false); }, onError: (error) => { onError?.(error); }, }); //preview orders const { data: previewItemMarket, reset: resetPreviewMarket, mutate: requestPreviewMutate, isLoading: isLoadingMarketPreview, error: errorMarketPreview, } = usePostOtcV1PrivateOtcConvertMarket({ onSuccess: () => { setValue("isPreviewOpen", true); }, }); const { data: previewItemLimit, reset: resetPreviewLimit, mutate: requestPreviewMutateLimit, isLoading: isLoadingLimitPreview, error: errorLimitPreview, } = usePostOtcV1PublicOtcConvertPreview({ onSuccess: () => { setValue("isPreviewOpen", true); }, }); const onConfirm = useCallback( async ({ triggerBeforeOrder }: OrderProps) => { await triggerBeforeOrder?.(); const order = handleSubmit(({ limitExpireDate }) => { if (type === "market") { confirmMarket({ queryParams: { otcConvertQuoteId: previewItemMarket?.id }, }); } else { const { fromAsset, lastChangedField, toAsset, fromAmount, price } = getValues(); confirmLimit({ requestBody: { expireDate: limitExpireDate || moment().clone().add(30, "days").startOf("day").toISOString(), sourceQuantity: lastChangedField === "from" ? starkString(fromAmount || 0) .parseNumber() .toNumber() : 0, destinationCurrencySymbol: toAsset, sourceCurrencySymbol: fromAsset, price: Number(price), validityDurationInSecond, }, }); } }); order(); }, // eslint-disable-next-line react-hooks/exhaustive-deps [previewItemLimit, previewItemMarket, type, validityDurationInSecond], ); const requestPreview = useCallback( async () => { const { error: errorFrom } = getFieldState("fromAmount"); const { error: errorTo } = getFieldState("toAmount"); if (errorFrom || errorTo) { return; } const order = handleSubmit( ({ fromAmount, toAmount, lastChangedField, toAsset, fromAsset }) => { if (!fromAmount && lastChangedField === "from") { return setError("fromAmount", { message: t("enterAmount") }); } if (!toAmount && lastChangedField === "to") { return setError("toAmount", { message: t("enterAmount") }); } if (type === "market" && !!userData) { requestPreviewMutate({ requestBody: { validityDurationInSecond, sourceQuantity: lastChangedField === "from" ? starkString(fromAmount || 0) .parseNumber() .toNumber() : undefined, destinationQunatity: lastChangedField === "to" ? starkString(toAmount || 0) .parseNumber() .toNumber() : undefined, sourceCurrencySymbol: fromAsset, destinationCurrencySymbol: toAsset, }, }); } else { requestPreviewMutateLimit({ requestBody: { validityDurationInSecond, sourceQuantity: lastChangedField === "from" ? starkString(fromAmount || 0) .parseNumber() .toNumber() : undefined, destinationQunatity: lastChangedField === "to" ? starkString(toAmount || 0) .parseNumber() .toNumber() : undefined, sourceCurrencySymbol: fromAsset, destinationCurrencySymbol: toAsset, }, }); } }, ); order(); }, // eslint-disable-next-line react-hooks/exhaustive-deps [type, userData, validityDurationInSecond], ); const closePreview = useCallback(() => { if (type === "limit") { resetPreviewLimit(); resetLimitOrder(); setValue("isPreviewOpen", false); } else { resetPreviewMarket(); resetMarketOrder(); setValue("isPreviewOpen", false); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [type]); return { onConfirm, isLoadingConfirm: isLoadingMarketOrder || isLoadingLimitOrder, isLoadingPreview: isLoadingMarketPreview || isLoadingLimitPreview, errorPreview: errorLimitPreview || errorMarketPreview, error: errorLimitOrder || errorMarketOrder, previewItem: type === "limit" || !userData ? previewItemLimit : previewItemMarket, resetPreviewApi: type === "limit" || !userData ? resetPreviewLimit : resetPreviewMarket, resetSubmitApi: type === "limit" || !userData ? resetLimitOrder : resetMarketOrder, closePreview, requestPreview, }; };