@daimo/pay
Version:
Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.
158 lines (155 loc) • 5.91 kB
JavaScript
import { jsx, jsxs } from 'react/jsx-runtime';
import { getChainExplorerTxUrl } from '@daimo/pay-common';
import { useState, useEffect } from 'react';
import { useChainId, useSwitchChain } from 'wagmi';
import { ROUTES } from '../../../constants/routes.js';
import { useDaimoPay } from '../../../hooks/useDaimoPay.js';
import useLocales from '../../../hooks/useLocales.js';
import { usePayContext } from '../../../hooks/usePayContext.js';
import { getSupportUrl } from '../../../utils/supportUrl.js';
import Button from '../../Common/Button/index.js';
import { PageContent, ModalContent, ModalH1, Link } from '../../Common/Modal/styles.js';
import PaymentBreakdown from '../../Common/PaymentBreakdown/index.js';
import TokenLogoSpinner from '../../Spinners/TokenLogoSpinner/index.js';
const PayWithToken = () => {
const { triggerResize, paymentState, setRoute, log, trpc } = usePayContext();
const { payWithToken, selectedTokenOption } = paymentState;
const { order } = useDaimoPay();
const [payState, setPayStateInner] = useState(
"Waiting For Payment" /* RequestingPayment */
);
const setPayState = (state) => {
setPayStateInner(state);
log(`[PAY TOKEN] payState: ${state}`);
trpc.nav.mutate({
action: "pay-with-token-state",
data: { state }
});
};
const [txURL, setTxURL] = useState();
const locales = useLocales();
const walletChainId = useChainId();
const { switchChainAsync } = useSwitchChain();
const trySwitchingChain = async (option, forceSwitch = false) => {
if (walletChainId !== option.required.token.chainId || forceSwitch) {
const resultChain = await (async () => {
try {
return await switchChainAsync({
chainId: option.required.token.chainId
});
} catch (e) {
console.error("Failed to switch chain", e);
return null;
}
})();
if (resultChain?.id !== option.required.token.chainId) {
return false;
}
}
return true;
};
const handleTransfer = async (option) => {
setPayState("Switching Chain" /* SwitchingChain */);
const switchChain = await trySwitchingChain(option);
if (!switchChain) {
console.error("Switching chain failed");
setPayState("Payment Cancelled" /* RequestCancelled */);
return;
}
setPayState("Waiting For Payment" /* RequestingPayment */);
try {
const result = await payWithToken(option);
if (!result.txHash) {
return;
}
setTxURL(
getChainExplorerTxUrl(option.required.token.chainId, result.txHash)
);
if (result.success) {
setPayState("Payment Successful" /* RequestSuccessful */);
setTimeout(() => {
setRoute(ROUTES.CONFIRMATION, { event: "wait-pay-with-token" });
}, 200);
} else {
setPayState("Payment Failed" /* RequestFailed */);
}
} catch (e) {
if (e?.name === "ConnectorChainMismatchError") {
log("Chain mismatch detected, attempting to switch and retry");
const switchSuccessful = await trySwitchingChain(option, true);
if (switchSuccessful) {
setPayState("Waiting For Payment" /* RequestingPayment */);
try {
const retryResult = await payWithToken(option);
if (!retryResult.txHash) {
return;
}
setTxURL(
getChainExplorerTxUrl(
option.required.token.chainId,
retryResult.txHash
)
);
if (retryResult.success) {
setPayState("Payment Successful" /* RequestSuccessful */);
setTimeout(() => {
setRoute(ROUTES.CONFIRMATION, { event: "wait-pay-with-token" });
}, 200);
} else {
setPayState("Payment Failed" /* RequestFailed */);
}
return;
} catch (retryError) {
console.error(
"Failed to pay with token after switching chain",
retryError
);
throw retryError;
}
}
}
setPayState("Payment Cancelled" /* RequestCancelled */);
console.error("Failed to pay with token", e);
}
};
useEffect(() => {
if (!selectedTokenOption) return;
const transferTimeout = setTimeout(() => {
handleTransfer(selectedTokenOption);
}, 100);
return () => {
clearTimeout(transferTimeout);
};
}, [selectedTokenOption]);
useEffect(() => {
triggerResize();
}, [payState]);
if (selectedTokenOption == null) {
return /* @__PURE__ */ jsx(PageContent, {});
}
return /* @__PURE__ */ jsxs(PageContent, { children: [
/* @__PURE__ */ jsx(TokenLogoSpinner, { token: selectedTokenOption.required.token }),
/* @__PURE__ */ jsxs(ModalContent, { style: { paddingBottom: 0 }, $preserveDisplay: true, children: [
txURL ? /* @__PURE__ */ jsx(ModalH1, { children: /* @__PURE__ */ jsx(Link, { href: txURL, target: "_blank", rel: "noopener noreferrer", children: payState }) }) : /* @__PURE__ */ jsx(ModalH1, { children: payState }),
/* @__PURE__ */ jsx(PaymentBreakdown, { paymentOption: selectedTokenOption }),
payState === "Payment Cancelled" /* RequestCancelled */ && /* @__PURE__ */ jsx(Button, { onClick: () => handleTransfer(selectedTokenOption), children: locales.retryPayment }),
payState === "Payment Failed" /* RequestFailed */ && /* @__PURE__ */ jsx(
Button,
{
onClick: () => {
window.open(
getSupportUrl(
order?.id?.toString() ?? "",
`Pay with token${txURL ? ` ${txURL}` : ""}`
),
"_blank"
);
},
children: locales.contactSupport
}
)
] })
] });
};
export { PayWithToken as default };
//# sourceMappingURL=index.js.map