@coin-voyage/paykit
Version:
Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.
102 lines (101 loc) • 4.29 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { PaymentMethod, PayOrderMode } from "@coin-voyage/shared/types";
import { useQuery } from "@tanstack/react-query";
import { useMemo } from "react";
import { CreditCardIcon } from "../assets/icons";
import Logos from "../assets/logos";
import { useBackendApi } from "../components/contexts/api";
import usePayContext from "../components/contexts/pay";
import { ROUTE } from "../types/routes";
import { Ethereum, Solana, Sui } from "@coin-voyage/shared/chain";
function getTitle(subject, isDeposit) {
return `${isDeposit ? "Deposit" : "Pay"} ${subject}`;
}
export function useMethodOptions({ mode, onClick }) {
const api = useBackendApi();
const { setRoute, paymentState, options: contextOptions } = usePayContext();
const { payOrder, setPaymentMethod } = paymentState;
const isDeposit = mode === PayOrderMode.DEPOSIT;
const mayUseCardPayments = payOrder?.settings?.card_payments === true;
const wantsToUseCardPayments = contextOptions?.experimentalFeatures?.cardPayments === true;
const shouldCheckCardAvailability = wantsToUseCardPayments && mayUseCardPayments;
const { data: paymentMethods, isLoading } = useQuery({
queryKey: ["payment-methods", payOrder?.id],
enabled: shouldCheckCardAvailability && Boolean(payOrder?.id),
retry: false,
refetchOnWindowFocus: false,
queryFn: async () => {
if (!payOrder?.id) {
throw new Error("Missing pay order");
}
const response = await api.getPayOrderPaymentMethods(payOrder.id);
if (response.error || !response.data) {
throw new Error(response.error?.message ?? "Unable to load payment methods");
}
return response.data;
},
});
const options = useMemo(() => {
const nextOptions = [
{
id: PaymentMethod.WALLET,
title: getTitle("with Wallet", isDeposit),
iconShape: "squircle",
icons: [
_jsx(Logos.MetaMask, {}, "metamask"),
_jsx(Logos.Phantom, {}, "phantom"),
_jsx(Logos.Slush, { style: { backgroundColor: "#000" } }, "slush"),
],
onClick: () => {
setPaymentMethod(PaymentMethod.WALLET);
setRoute(ROUTE.WALLET_CHAIN_SELECT);
onClick();
},
},
{
id: PaymentMethod.DEPOSIT_ADDRESS,
title: getTitle("to Address", isDeposit),
iconShape: "circle",
icons: [_jsx(Ethereum, {}, "ethereum"), _jsx(Solana, {}, "solana"), _jsx(Sui, {}, "sui")],
onClick: () => {
setPaymentMethod(PaymentMethod.DEPOSIT_ADDRESS);
setRoute(ROUTE.ADDRESS_CHAIN_SELECT);
onClick();
},
},
];
if (!shouldCheckCardAvailability) {
return nextOptions;
}
const cardMethod = paymentMethods?.methods.find((m) => m.method === PaymentMethod.CARD);
if (!cardMethod) {
return nextOptions;
}
nextOptions.push({
id: PaymentMethod.CARD,
title: getTitle("with Card", isDeposit),
subtitle: !cardMethod.available
? (cardMethod.reason ?? formatMinimumAmount(cardMethod.minimum_amount))
: undefined,
disabled: !cardMethod.available,
iconShape: "squircle",
icons: [_jsx(CreditCardIcon, {}, "stripe")],
onClick: () => {
if (!cardMethod.available) {
return;
}
setPaymentMethod(PaymentMethod.CARD);
setRoute(ROUTE.CARD_PAYMENT);
onClick();
},
});
return nextOptions;
}, [isDeposit, onClick, paymentMethods?.methods, setPaymentMethod, setRoute, shouldCheckCardAvailability]);
return { options, isLoading };
}
function formatMinimumAmount(minimumAmount) {
if (!minimumAmount) {
return undefined;
}
return `Minimum ${minimumAmount.amount} ${minimumAmount.unit}`;
}