import { useCallback } from "react"; import { useTranslation } from "react-i18next"; import starkString from "starkstring"; import { v4 as uuidv4 } from "uuid"; import { usePostOtcV1PrivateOtcConvertConfirm, usePostOtcV1PrivateOtcQuickbuyMarket, usePostPaymentV1PrivateEpayrequestPostactionotcconvert, UserBankResponseVM, } from "../../services"; import { getErrorMessage } from "../../utils"; import { useAssets } from "../useAssets"; import { useCharge } from "../useCharge"; import { useDefaultCurrency } from "../useDefaultCurrency"; import { BuySellContext, BuySellProps } from "./context"; type Charge = { redirectUrl: string; clientId?: string; amountToCharge?: number; }; type SelectedQueries = { crypto?: string; fiat?: string; mode: "buy" | "sell"; }; export const useBuySell = (callbacks?: BuySellProps) => { if (typeof BuySellContext.context === "undefined") { throw new Error("You must use this hook under the BuySellProvider."); } const { t } = useTranslation(); const { handleSubmit, reset, setValue, getValues, setError, getFieldState } = BuySellContext.useFormContext(); const { getAssetBySymbol } = useAssets(); const selectedAssignedValue = useCallback( ({ crypto, fiat, mode }: SelectedQueries) => { const fiatAsset = getAssetBySymbol(fiat || ""); const cryptoAsset = getAssetBySymbol(crypto || ""); if (mode === "buy") { fiatAsset && setValue("fromAsset", fiatAsset.symbol); cryptoAsset && setValue("toAsset", cryptoAsset.symbol); } else { cryptoAsset && setValue("fromAsset", cryptoAsset.symbol); fiatAsset && setValue("toAsset", fiatAsset.symbol); } }, // eslint-disable-next-line react-hooks/exhaustive-deps [getAssetBySymbol], ); const { data: previewItem, reset: resetPreviewMarket, mutate: requestPreviewMutate, isLoading: isLoadingPreview, error: errorPreview, } = usePostOtcV1PrivateOtcQuickbuyMarket({ onSuccess: () => { setValue("isPreviewOpen", true); }, }); const { mutate: confirmMarket, isLoading: isLoadingConfirm, error: errorMarketOrder, reset: resetMarketOrder, } = usePostOtcV1PrivateOtcConvertConfirm({ onSuccess: (data) => { setValue("fromAmount", ""); setValue("toAmount", ""); callbacks?.onSuccess?.(data); setValue("isPreviewOpen", false); reset(); }, onError: (error) => { callbacks?.onError?.(error); }, }); const { defaultCurrency } = useDefaultCurrency(); const { charge: requestCharge, isLoading: isLoadingCharge, errorAmount, serverError, clearError, checkAmount, } = useCharge({ currency: defaultCurrency, onSuccess: (data) => { if (__PLATFORM__ === "native") { return callbacks?.onNavigateNative?.(data?.paymentLink || ""); } window.location.href = data?.paymentLink || ""; }, }); const chargeError = errorAmount || getErrorMessage(serverError); const { mutate: postAction, isLoading: isLoadingPostAction } = usePostPaymentV1PrivateEpayrequestPostactionotcconvert({ onSuccess: ({ postActionUniqueId }, { _extraVariables }) => { const { selectedBank } = getValues(); const clientUniqueId = _extraVariables?.clientId || uuidv4(); const { chargeAmount } = getValues(); requestCharge(chargeAmount, { postActionUniqueId, redirectUrl: _extraVariables?.redirectUrl, clientUniqueId, userBankId: selectedBank?.id, }); }, }); const charge = useCallback( ({ redirectUrl, clientId }: Charge) => { const { fromAmount, fromAsset, toAsset, toAmount, lastChangedField } = getValues(); postAction({ requestBody: { sourceCurrencySymbol: fromAsset, destinationCurrencySymbol: toAsset, sourceQuantity: lastChangedField === "from" ? starkString(fromAmount || 0) .parseNumber() .toNumber() : undefined, destinationQunatity: lastChangedField === "to" ? starkString(toAmount || 0) .parseNumber() .toNumber() : undefined, }, _extraVariables: { redirectUrl, clientId }, }); }, // eslint-disable-next-line react-hooks/exhaustive-deps [postAction], ); const validateCharge = useCallback(() => { const { chargeAmount } = getValues(); const isValidAmount = checkAmount(chargeAmount); if (!isValidAmount) { return; } setValue("showChargeMessage", true); // eslint-disable-next-line react-hooks/exhaustive-deps }, [checkAmount]); const isChargeLoading = isLoadingCharge || isLoadingPostAction; const hideChargeMessage = useCallback(() => { setValue("showChargeMessage", false); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const setSelectedBank = useCallback( (userBank?: UserBankResponseVM | null) => { setValue("selectedBank", userBank); }, [setValue], ); const requestPreview = useCallback(() => { const { error: errorFrom } = getFieldState("fromAmount"); const { error: errorTo } = getFieldState("toAmount"); if (errorFrom || errorTo) { return; } handleSubmit( ({ fromAsset, toAsset, fromAmount, lastChangedField = "from", toAmount, }) => { if (!fromAmount && lastChangedField === "from") { return setError("fromAmount", { message: t("enterAmount") }); } if (!toAmount && lastChangedField === "to") { return setError("toAmount", { message: t("enterAmount") }); } requestPreviewMutate({ requestBody: { validityDurationInSecond: callbacks?.validityDurationInSecond || 10, sourceQuantity: lastChangedField === "from" ? starkString(fromAmount || 0) .parseNumber() .toNumber() : undefined, destinationQunatity: lastChangedField === "to" ? starkString(toAmount || 0) .parseNumber() .toNumber() : undefined, sourceCurrencySymbol: fromAsset, destinationCurrencySymbol: toAsset, }, }); }, )(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [callbacks?.validityDurationInSecond, handleSubmit]); const closePreview = useCallback(() => { resetPreviewMarket(); resetMarketOrder(); setValue("isPreviewOpen", false); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const onConfirm = useCallback( () => { const order = handleSubmit(() => { confirmMarket({ queryParams: { otcConvertQuoteId: previewItem?.id }, }); }); order(); }, // eslint-disable-next-line react-hooks/exhaustive-deps [previewItem], ); return { charge, isChargeLoading, selectedAssignedValue, chargeError, clearChargeError: clearError, hideChargeMessage, setSelectedBank, validateCharge, error: errorMarketOrder, onConfirm, isLoadingConfirm, isLoadingPreview, errorPreview, previewItem, closePreview, requestPreview, }; };