@daimo/pay
Version:
Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.
92 lines (89 loc) • 4.37 kB
JavaScript
import { useContext, useSyncExternalStore, useMemo, useCallback } from 'react';
import { waitForPaymentState } from '../payment/paymentStore.js';
import { PaymentContext } from '../provider/PaymentProvider.js';
/**
* React hook for interacting with Daimo Pay orders and payments. Use this hook
* to manage the lifecycle of a Daimo Pay payment in your application.
*
* This hook provides a simple interface to create, hydrate, pay, and reset
* Daimo Pay orders.
*
* @returns {UseDaimoPay} An object with current payment state and methods to
* manage Daimo Pay orders and payments.
*/
function useDaimoPay() {
const store = useContext(PaymentContext);
if (!store) {
throw new Error("useDaimoPay must be used within <PaymentProvider>");
}
/* --------------------------------------------------
Order state
---------------------------------------------------*/
// Subscribe to the store and keep an up-to-date copy of the payment.
const paymentFsmState = useSyncExternalStore(store.subscribe, store.getState, store.getState);
// Wrap `order` in `useMemo` for reference stability. This allows downstream
// components to use `order` as a dependency to avoid unnecessary re-renders.
const order = useMemo(() => {
if (paymentFsmState.type === "idle")
return null;
return paymentFsmState.order ?? null;
}, [paymentFsmState]);
const paymentState = paymentFsmState.type;
const paymentErrorMessage = paymentFsmState.type === "error" ? paymentFsmState.message : null;
/* --------------------------------------------------
Order event dispatch helpers
---------------------------------------------------*/
// Internal helper to dispatch events to the store.
const dispatch = useCallback((e) => store.dispatch(e), [store]);
const createPreviewOrder = useCallback(async (payParams) => {
dispatch({ type: "set_pay_params", payParams });
// Wait for the order to enter the "preview" state, which means it
// has been successfully created.
const previewOrderState = await waitForPaymentState(store, "preview");
return previewOrderState;
}, [dispatch, store]);
const setPayId = useCallback(async (payId) => {
dispatch({ type: "set_pay_id", payId });
// Wait for the order to be queried from the API. Using payId could
// result in the order being in any state.
const previewOrderState = await waitForPaymentState(store, "unhydrated", "payment_unpaid", "payment_started", "payment_completed", "payment_bounced");
return previewOrderState;
}, [dispatch, store]);
const hydrateOrder = useCallback(async (refundAddress) => {
dispatch({ type: "hydrate_order", refundAddress });
// Wait for the order to enter the "payment_unpaid" state, which means it
// has been successfully hydrated.
const hydratedOrderState = await waitForPaymentState(store, "payment_unpaid");
return hydratedOrderState;
}, [dispatch, store]);
const paySource = useCallback(() => dispatch({ type: "pay_source" }), [dispatch]);
const payEthSource = useCallback(async (args) => {
dispatch({ type: "pay_ethereum_source", ...args });
// Will throw if the payment is not verified by the server.
const paidState = await waitForPaymentState(store, "payment_started", "payment_completed", "payment_bounced");
return paidState;
}, [dispatch, store]);
const paySolanaSource = useCallback(async (args) => {
dispatch({ type: "pay_solana_source", ...args });
// Will throw if the payment is not verified by the server.
const paidState = await waitForPaymentState(store, "payment_started", "payment_completed", "payment_bounced");
return paidState;
}, [dispatch, store]);
const reset = useCallback(() => dispatch({ type: "reset" }), [dispatch]);
const setChosenUsd = useCallback((usd) => dispatch({ type: "set_chosen_usd", usd }), [dispatch]);
return {
order,
paymentState,
paymentErrorMessage,
createPreviewOrder,
hydrateOrder,
setPayId,
paySource,
payEthSource,
paySolanaSource,
reset,
setChosenUsd,
};
}
export { useDaimoPay };
//# sourceMappingURL=useDaimoPay.js.map