@daimo/pay 1.7.4 → 1.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.d.ts CHANGED
@@ -68,6 +68,7 @@ type DaimoPayContextOptions = {
68
68
  /** Modal UI options, set on the pay button triggering that modal. */
69
69
  type DaimoPayModalOptions = {
70
70
  closeOnSuccess?: boolean;
71
+ resetOnSuccess?: boolean;
71
72
  };
72
73
  /** Additional payment options. Onchain payments are always enabled. */
73
74
  type PaymentOption = "Daimo" | "Coinbase" | "Binance" | "RampNetwork" | "Solana" | "ExternalChains" | "Lemon";
@@ -256,6 +257,8 @@ type PayButtonCommonProps = PayButtonPaymentProps & {
256
257
  closeOnSuccess?: boolean;
257
258
  /** Open the modal by default. */
258
259
  defaultOpen?: boolean;
260
+ /** Reset the payment after a successful payment. */
261
+ resetOnSuccess?: boolean;
259
262
  /** Custom message to display on confirmation page. */
260
263
  confirmationMessage?: string;
261
264
  /** Redirect URL to return to the app. E.g. after Coinbase, Binance, RampNetwork. */
@@ -303,10 +306,9 @@ declare namespace DaimoPayButtonCustom {
303
306
  * to the payment's configured refund address on the destination chain.
304
307
  */
305
308
  declare function useDaimoPayStatus(): {
306
- paymentId?: string;
307
- status?: DaimoPayIntentStatus;
308
- reset: () => void;
309
- };
309
+ paymentId: string;
310
+ status: DaimoPayIntentStatus;
311
+ } | undefined;
310
312
 
311
313
  /** Icon for an EVM chain, given chain ID. No ID shows a loading spinner. */
312
314
  declare const Chain: React$1.FC<{
@@ -479,8 +481,6 @@ interface PaymentState {
479
481
  resetOrder: () => void;
480
482
  daimoPayOrder: DaimoPayOrder | undefined;
481
483
  isDepositFlow: boolean;
482
- modalOptions: DaimoPayModalOptions;
483
- setModalOptions: (modalOptions: DaimoPayModalOptions) => void;
484
484
  paymentWaitingMessage: string | undefined;
485
485
  externalPaymentOptions: ReturnType<typeof useExternalPaymentOptions>;
486
486
  showSolanaPaymentMethod: boolean;
@@ -503,10 +503,6 @@ interface PaymentState {
503
503
  payWithDepositAddress: (option: DepositAddressPaymentOptions) => Promise<DepositAddressPaymentOptionData | null>;
504
504
  payWithSolanaToken: (inputToken: SolanaPublicKey) => Promise<string | undefined>;
505
505
  refreshOrder: () => Promise<void>;
506
- onSuccess: (args: {
507
- txHash: string;
508
- txURL?: string;
509
- }) => void;
510
506
  senderEnsName: string | undefined;
511
507
  }
512
508
 
@@ -555,6 +551,8 @@ type PayContextValue = {
555
551
  paymentState: PaymentState;
556
552
  /** TRPC API client. Internal use only. */
557
553
  trpc: any;
554
+ /** Callback to call when the payment is successful. */
555
+ onSuccess: () => void;
558
556
  /** Custom message to display on confirmation page. */
559
557
  confirmationMessage?: string;
560
558
  setConfirmationMessage: React$1.Dispatch<React$1.SetStateAction<string | undefined>>;
package/build/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { ExternalPaymentOptions, assert, assertNotNull, debugJson, supportedChains, ethereum, isCCTPV1Chain, getOrderDestChainId, readDaimoPayOrderID, getChainName, arbitrum as arbitrum$1, base as base$2, blast as blast$1, bsc as bsc$1, linea as linea$1, mantle as mantle$1, optimism as optimism$1, polygon as polygon$1, worldchain as worldchain$1, getAddressContraction, writeDaimoPayOrderID, DaimoPayOrderMode, DaimoPayOrderStatusDest, getChainExplorerTxUrl, DaimoPayIntentStatus, retryBackoff, DaimoPayOrderStatusSource, getDaimoPayOrderView } from '@daimo/pay-common';
3
3
  import { Buffer } from 'buffer';
4
- import React, { useState, useEffect, createContext, useCallback, useRef, useLayoutEffect, useMemo, createElement } from 'react';
4
+ import React, { useState, useEffect, createContext, useRef, useCallback, useLayoutEffect, useMemo, createElement } from 'react';
5
5
  import styled$1, { css, keyframes, ThemeProvider } from 'styled-components';
6
6
  import { http, useConfig, useAccountEffect, useWriteContract, useSendTransaction, useAccount, useEnsName, useConnectors as useConnectors$1, useSwitchChain, useConnect as useConnect$1, useDisconnect, useChainId, WagmiContext, createConfig, useEnsAddress, useEnsAvatar } from 'wagmi';
7
7
  import { mainnet, base as base$1, polygon, optimism, arbitrum, linea, bsc, sepolia, baseSepolia, worldchain, blast, mantle } from 'wagmi/chains';
@@ -22,7 +22,7 @@ import { WalletSignTransactionError, WalletSendTransactionError } from '@solana/
22
22
  import { normalize } from 'viem/ens';
23
23
 
24
24
  var name = "@daimo/pay";
25
- var version = "1.7.4";
25
+ var version = "1.7.5";
26
26
  var author = "Daimo";
27
27
  var homepage = "https://pay.daimo.com";
28
28
  var license = "BSD-2-Clause license";
@@ -61,7 +61,7 @@ var keywords = [
61
61
  "crypto"
62
62
  ];
63
63
  var dependencies = {
64
- "@daimo/pay-common": "1.7.4",
64
+ "@daimo/pay-common": "1.7.5",
65
65
  "@rollup/plugin-typescript": "^12.1.2",
66
66
  "@solana/wallet-adapter-base": "^0.9.23",
67
67
  "@solana/wallet-adapter-react": "^0.15.35",
@@ -94,6 +94,7 @@ var devDependencies = {
94
94
  "@types/react-dom": "^18.2.18",
95
95
  "@types/rollup-plugin-peer-deps-external": "^2.2.5",
96
96
  "@types/styled-components": "^5.1.25",
97
+ "eslint-plugin-react-hooks": "^5.2.0",
97
98
  rollup: "^3.29.5",
98
99
  "rollup-plugin-dts": "^6.1.1",
99
100
  "rollup-plugin-peer-deps-external": "^2.2.4",
@@ -244,14 +245,6 @@ const defaultConfig = ({ appName = "Daimo Pay", appIcon, appDescription, appUrl,
244
245
  return config;
245
246
  };
246
247
 
247
- /** Determines whether the current wagmi configuration supports a given chain. */
248
- function useChainIsSupported(chainId) {
249
- const { chains } = useConfig();
250
- if (!chainId)
251
- return false;
252
- return chains.some((x) => x.id === chainId);
253
- }
254
-
255
248
  /** Returns currently configured wagmi chains. */
256
249
  function useChains() {
257
250
  const wagmi = useConfig();
@@ -843,47 +836,6 @@ function extractWcWalletFromProvider(p, log) {
843
836
  return wallet;
844
837
  }
845
838
 
846
- function useGoogleFont(font) {
847
- useEffect(() => {
848
- if (!font)
849
- return;
850
- font = font.replace(/ /g, "+");
851
- const googleapis = document.createElement("link");
852
- googleapis.href = `https://fonts.googleapis.com`;
853
- googleapis.rel = "preconnect";
854
- const gstatic = document.createElement("link");
855
- gstatic.href = `https://fonts.gstatic.com`;
856
- gstatic.rel = "preconnect";
857
- gstatic.crossOrigin = "true";
858
- const link = document.createElement("link");
859
- link.href = `https://fonts.googleapis.com/css2?family=${font}:wght@400;500;600&display=swap`;
860
- link.rel = "stylesheet";
861
- document.head.appendChild(googleapis);
862
- document.head.appendChild(gstatic);
863
- document.head.appendChild(link);
864
- return () => {
865
- try {
866
- document.head.removeChild(googleapis);
867
- document.head.removeChild(gstatic);
868
- document.head.removeChild(link);
869
- }
870
- catch { }
871
- };
872
- }, [font]);
873
- }
874
- // TODO: This could be dynamic if theming wasn't set up as css variables
875
- function useThemeFont(theme) {
876
- const themeFonts = {
877
- web95: "Lato",
878
- retro: "Nunito",
879
- midnight: "Inter",
880
- minimal: "Inter",
881
- rounded: "Nunito",
882
- };
883
- const font = themeFonts[theme] ?? null;
884
- useGoogleFont(font ?? "");
885
- }
886
-
887
839
  /** Daimo Pay internal context. */
888
840
  const usePayContext = () => {
889
841
  const context = React.useContext(PayContext);
@@ -1175,7 +1127,7 @@ function useWalletPaymentOptions({ trpc, address, usdRequired, destChainId, pref
1175
1127
  };
1176
1128
  }
1177
1129
 
1178
- function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log, redirectReturnUrl, }) {
1130
+ function usePaymentState({ trpc, lockPayParams, daimoPayOrder, setDaimoPayOrder, setRoute, log, redirectReturnUrl, }) {
1179
1131
  // Browser state.
1180
1132
  const [platform, setPlatform] = useState();
1181
1133
  useEffect(() => {
@@ -1198,12 +1150,14 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
1198
1150
  paymentOptions.includes(ExternalPaymentOptions.Solana)) &&
1199
1151
  daimoPayOrder != null &&
1200
1152
  isCCTPV1Chain(getOrderDestChainId(daimoPayOrder));
1201
- // Daimo Pay order state.
1153
+ // Refs the survive re-renders and stores any updated param values while
1154
+ // lockPayParams is true
1155
+ const latestPayParamsRef = useRef();
1156
+ const latestPayIdRef = useRef();
1157
+ // Current pay params to do processing off of
1202
1158
  const [payParams, setPayParamsState] = useState();
1203
1159
  const [paymentWaitingMessage, setPaymentWaitingMessage] = useState();
1204
1160
  const [isDepositFlow, setIsDepositFlow] = useState(false);
1205
- // Payment UI config.
1206
- const [modalOptions, setModalOptions] = useState({});
1207
1161
  // UI state. Selection for external payment (Binance, etc) vs wallet payment.
1208
1162
  const externalPaymentOptions = useExternalPaymentOptions({
1209
1163
  trpc,
@@ -1341,7 +1295,7 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
1341
1295
  else {
1342
1296
  log(`[CHECKOUT] IGNORING refreshOrder, wrong ID: ${order.id} vs ${daimoPayOrder.id}`);
1343
1297
  }
1344
- }, [daimoPayOrder?.id]);
1298
+ }, [daimoPayOrder, trpc, setDaimoPayOrder, log]);
1345
1299
  /** User picked a different deposit amount. */
1346
1300
  const setChosenUsd = (usd) => {
1347
1301
  assert(!!daimoPayOrder, "[SET CHOSEN USD] daimoPayOrder cannot be null");
@@ -1361,7 +1315,8 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
1361
1315
  });
1362
1316
  };
1363
1317
  const setPayId = useCallback(async (payId) => {
1364
- if (!payId)
1318
+ latestPayIdRef.current = payId;
1319
+ if (lockPayParams || !payId)
1365
1320
  return;
1366
1321
  const id = readDaimoPayOrderID(payId).toString();
1367
1322
  if (daimoPayOrder && BigInt(id) == daimoPayOrder.id) {
@@ -1375,15 +1330,19 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
1375
1330
  }
1376
1331
  log(`[CHECKOUT] setPayId: fetched order: ${JSON.stringify(order)}`);
1377
1332
  setDaimoPayOrder(order);
1378
- }, [daimoPayOrder]);
1333
+ }, [daimoPayOrder, lockPayParams, trpc, log, setDaimoPayOrder]);
1379
1334
  /** Called whenever params change. */
1380
1335
  const setPayParams = async (payParams) => {
1336
+ latestPayParamsRef.current = payParams;
1337
+ if (lockPayParams)
1338
+ return;
1381
1339
  assert(payParams != null, "[SET PAY PARAMS] payParams cannot be null");
1340
+ console.log("[SET PAY PARAMS] setting payParams");
1382
1341
  setPayParamsState(payParams);
1383
1342
  setIsDepositFlow(payParams.toUnits == null);
1384
1343
  generatePreviewOrder(payParams);
1385
1344
  };
1386
- const generatePreviewOrder = async (payParams) => {
1345
+ const generatePreviewOrder = useCallback(async (payParams) => {
1387
1346
  // toUnits is undefined if and only if we're in deposit flow.
1388
1347
  // Set dummy value for deposit flow, since user can edit the amount.
1389
1348
  const toUnits = payParams.toUnits == null ? "0" : payParams.toUnits;
@@ -1411,16 +1370,28 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
1411
1370
  });
1412
1371
  log(`[CHECKOUT] generated preview: ${JSON.stringify(orderPreview)}`);
1413
1372
  setDaimoPayOrder(orderPreview);
1414
- };
1415
- const onSuccess = ({ txHash, txURL }) => {
1416
- if (modalOptions?.closeOnSuccess) {
1417
- log(`[CHECKOUT] transaction succeeded, closing: ${txHash} ${txURL}`);
1418
- setTimeout(() => setOpen(false, { event: "wait-success" }), 1000);
1419
- }
1420
- };
1421
- const resetOrder = () => {
1373
+ }, [trpc, log, setDaimoPayOrder]);
1374
+ const resetOrder = useCallback(() => {
1375
+ // Clear the old order & UI
1422
1376
  setDaimoPayOrder(undefined);
1423
- };
1377
+ setRoute(ROUTES.SELECT_METHOD);
1378
+ // Prefer an explicit payId, otherwise use the queued payParams
1379
+ if (latestPayIdRef.current) {
1380
+ setPayId(latestPayIdRef.current);
1381
+ latestPayIdRef.current = undefined;
1382
+ }
1383
+ else if (latestPayParamsRef.current) {
1384
+ const p = latestPayParamsRef.current;
1385
+ setPayParamsState(p);
1386
+ generatePreviewOrder(p);
1387
+ }
1388
+ }, [
1389
+ setDaimoPayOrder,
1390
+ setRoute,
1391
+ setPayId,
1392
+ setPayParamsState,
1393
+ generatePreviewOrder,
1394
+ ]);
1424
1395
  return {
1425
1396
  setPayId,
1426
1397
  payParams,
@@ -1428,8 +1399,6 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
1428
1399
  generatePreviewOrder,
1429
1400
  daimoPayOrder,
1430
1401
  isDepositFlow,
1431
- modalOptions,
1432
- setModalOptions,
1433
1402
  paymentWaitingMessage,
1434
1403
  selectedExternalOption,
1435
1404
  selectedTokenOption,
@@ -1453,7 +1422,6 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
1453
1422
  payWithDepositAddress,
1454
1423
  payWithSolanaToken,
1455
1424
  refreshOrder,
1456
- onSuccess,
1457
1425
  senderEnsName: senderEnsName ?? undefined,
1458
1426
  };
1459
1427
  }
@@ -6889,6 +6857,14 @@ function useWalletConnectUri({ enabled } = {
6889
6857
  };
6890
6858
  }
6891
6859
 
6860
+ /** Determines whether the current wagmi configuration supports a given chain. */
6861
+ function useChainIsSupported(chainId) {
6862
+ const { chains } = useConfig();
6863
+ if (!chainId)
6864
+ return false;
6865
+ return chains.some((x) => x.id === chainId);
6866
+ }
6867
+
6892
6868
  const Web3Context = React.createContext({
6893
6869
  connect: {
6894
6870
  getUri: () => "",
@@ -9610,20 +9586,17 @@ const Underline = styled(motion.span) `
9610
9586
  `;
9611
9587
 
9612
9588
  const Confirmation = () => {
9613
- const { paymentState, confirmationMessage } = usePayContext();
9589
+ const { paymentState, confirmationMessage, onSuccess } = usePayContext();
9614
9590
  const { daimoPayOrder } = paymentState;
9615
- const { done, txURL } = (() => {
9591
+ const { done, txURL } = useMemo(() => {
9616
9592
  if (daimoPayOrder && daimoPayOrder.mode === DaimoPayOrderMode.HYDRATED) {
9617
- // Frontends are optimistic, assume submits will be successful
9618
9593
  const { destStatus } = daimoPayOrder;
9619
- if (destStatus === DaimoPayOrderStatusDest.FAST_FINISH_SUBMITTED ||
9620
- destStatus === DaimoPayOrderStatusDest.FAST_FINISHED ||
9594
+ if (destStatus === DaimoPayOrderStatusDest.FAST_FINISHED ||
9621
9595
  destStatus === DaimoPayOrderStatusDest.CLAIM_SUCCESSFUL) {
9622
9596
  const txHash = daimoPayOrder.destFastFinishTxHash ?? daimoPayOrder.destClaimTxHash;
9623
- const chainId = daimoPayOrder.destFinalCallTokenAmount.token.chainId;
9597
+ const destChainId = getOrderDestChainId(daimoPayOrder);
9624
9598
  assert(txHash != null, `[CONFIRMATION] dest status: ${destStatus}, but missing txHash`);
9625
- const txURL = getChainExplorerTxUrl(chainId, txHash);
9626
- paymentState.onSuccess({ txHash, txURL });
9599
+ const txURL = getChainExplorerTxUrl(destChainId, txHash);
9627
9600
  return {
9628
9601
  done: true,
9629
9602
  txURL,
@@ -9634,7 +9607,12 @@ const Confirmation = () => {
9634
9607
  done: false,
9635
9608
  txURL: undefined,
9636
9609
  };
9637
- })();
9610
+ }, [daimoPayOrder]);
9611
+ useEffect(() => {
9612
+ if (done) {
9613
+ onSuccess();
9614
+ }
9615
+ }, [done, onSuccess]);
9638
9616
  return (jsx(PageContent, { style: {
9639
9617
  display: "flex",
9640
9618
  justifyContent: "center",
@@ -9678,8 +9656,6 @@ const Link = styled.a `
9678
9656
  `;
9679
9657
  const SuccessIcon = styled(TickIcon) `
9680
9658
  color: var(--ck-body-color-valid);
9681
-
9682
- transform: scale(0.5);
9683
9659
  transition: all 0.2s ease-in-out;
9684
9660
  position: absolute;
9685
9661
  opacity: ${(props) => (props.$status ? 1 : 0)};
@@ -9690,7 +9666,6 @@ const Spinner$1 = styled(LoadingCircleIcon) `
9690
9666
  transition: all 0.2s ease-in-out;
9691
9667
  animation: rotateSpinner 400ms linear infinite;
9692
9668
  opacity: ${(props) => (props.$status ? 0 : 1)};
9693
- transform: ${(props) => (props.$status ? "scale(0.5)" : "scale(1)")};
9694
9669
 
9695
9670
  @keyframes rotateSpinner {
9696
9671
  0% {
@@ -11229,9 +11204,9 @@ const WaitingExternal = () => {
11229
11204
  }, children: selectedExternalOption.cta })] }));
11230
11205
  };
11231
11206
 
11232
- const customThemeDefault = {};
11233
- const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThemeDefault, lang = "en-US", }) => {
11207
+ const DaimoPayModal = ({ mode, theme, customTheme, lang, }) => {
11234
11208
  const context = usePayContext();
11209
+ const { setMode, setTheme, setCustomTheme, setLang } = context;
11235
11210
  const paymentState = context.paymentState;
11236
11211
  const { payParams, generatePreviewOrder, isDepositFlow, showSolanaPaymentMethod, setPaymentWaitingMessage, setSelectedExternalOption, setSelectedTokenOption, setSelectedSolanaTokenOption, setSelectedDepositAddressOption, } = paymentState;
11237
11212
  const { isConnected: isEthConnected, connector, chain, address, } = useAccount();
@@ -11387,12 +11362,16 @@ const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThem
11387
11362
  }
11388
11363
  // Don't include context.route in the dependency array otherwise the user
11389
11364
  // can't go back from the select token screen to the select method screen
11365
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11390
11366
  }, [
11391
11367
  context.open,
11392
11368
  context.wcWallet,
11393
11369
  isEthConnected,
11394
11370
  isSolanaConnected,
11395
11371
  showSolanaPaymentMethod,
11372
+ address,
11373
+ chain?.id,
11374
+ connector?.id,
11396
11375
  ]);
11397
11376
  // If we're on the connect page and the user successfully connects their
11398
11377
  // wallet, go to the select token page
@@ -11409,11 +11388,12 @@ const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThem
11409
11388
  });
11410
11389
  }
11411
11390
  }
11391
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11412
11392
  }, [isEthConnected, context.route, connector?.id, chain?.id, address]);
11413
- useEffect(() => context.setMode(mode), [mode]);
11414
- useEffect(() => context.setTheme(theme), [theme]);
11415
- useEffect(() => context.setCustomTheme(customTheme), [customTheme]);
11416
- useEffect(() => context.setLang(lang), [lang]);
11393
+ useEffect(() => setMode(mode), [mode, setMode]);
11394
+ useEffect(() => setTheme(theme), [theme, setTheme]);
11395
+ useEffect(() => setCustomTheme(customTheme), [customTheme, setCustomTheme]);
11396
+ useEffect(() => setLang(lang), [lang, setLang]);
11417
11397
  /* When pulling data into WalletConnect, it prioritises the og:title tag over the title tag */
11418
11398
  useEffect(() => {
11419
11399
  const appName = getAppName();
@@ -11517,7 +11497,10 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
11517
11497
  onCloseRef.current = fn;
11518
11498
  }, []);
11519
11499
  const [open, setOpenState] = useState(false);
11500
+ const [lockPayParams, setLockPayParams] = useState(false);
11501
+ const [paymentCompleted, setPaymentCompleted] = useState(false);
11520
11502
  const [route, setRouteState] = useState(ROUTES.SELECT_METHOD);
11503
+ const [modalOptions, setModalOptions] = useState();
11521
11504
  // Daimo Pay context
11522
11505
  const [daimoPayOrder, setDaimoPayOrderInner] = useState();
11523
11506
  const [pendingConnectorId, setPendingConnectorId] = useState(undefined);
@@ -11528,22 +11511,46 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
11528
11511
  const [errorMessage, setErrorMessage] = useState("");
11529
11512
  const [confirmationMessage, setConfirmationMessage] = useState(undefined);
11530
11513
  const [redirectReturnUrl, setRedirectReturnUrl] = useState(undefined);
11531
- const log = debugMode ? console.log : () => { };
11514
+ const log = useMemo(() => (debugMode ? console.log : () => { }), [debugMode]);
11532
11515
  // Connect to the Daimo Pay TRPC API
11533
- const trpc = useMemo(() => createTrpcClient(payApiUrl, sessionId), [payApiUrl]);
11516
+ const trpc = useMemo(() => createTrpcClient(payApiUrl, sessionId), [payApiUrl, sessionId]);
11534
11517
  const [resize, onResize] = useState(0);
11535
11518
  const setOpen = useCallback((open, meta) => {
11536
11519
  setOpenState(open);
11520
+ // Lock pay params starting from the first time the modal is opened to
11521
+ // prevent the daimo pay order from changing from under the user
11522
+ if (open) {
11523
+ setLockPayParams(true);
11524
+ }
11525
+ // Reset payment state on close if resetOnSuccess is true
11526
+ if (!open && paymentCompleted && modalOptions?.resetOnSuccess) {
11527
+ setPaymentCompleted(false);
11528
+ setLockPayParams(false);
11529
+ paymentState.resetOrder();
11530
+ }
11531
+ // Log the open/close event
11537
11532
  trpc.nav.mutate({
11538
11533
  action: open ? "navOpenPay" : "navClosePay",
11539
11534
  orderId: daimoPayOrder?.id?.toString(),
11540
11535
  data: meta ?? {},
11541
11536
  });
11537
+ // Run the onOpen and onClose callbacks
11542
11538
  if (open)
11543
11539
  onOpenRef.current?.();
11544
11540
  else
11545
11541
  onCloseRef.current?.();
11546
- }, [trpc, daimoPayOrder?.id]);
11542
+ },
11543
+ // We don't have good caching on paymentState, so don't include it as a dep
11544
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11545
+ [trpc, daimoPayOrder?.id, modalOptions?.resetOnSuccess, paymentCompleted]);
11546
+ // Callback when a payment is successfully completed (regardless of whether
11547
+ // the final call succeeded or bounced)
11548
+ const onSuccess = useCallback(() => {
11549
+ if (modalOptions?.closeOnSuccess) {
11550
+ setTimeout(() => setOpen(false, { event: "wait-success" }), 1000);
11551
+ }
11552
+ setPaymentCompleted(true);
11553
+ }, [modalOptions?.closeOnSuccess, setOpen, setPaymentCompleted]);
11547
11554
  const setRoute = useCallback((route, data) => {
11548
11555
  const action = route.replace("daimoPay", "");
11549
11556
  log(`[SET ROUTE] ${action} ${daimoPayOrder?.id} ${debugJson(data ?? {})}`);
@@ -11554,23 +11561,11 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
11554
11561
  });
11555
11562
  setRouteState(route);
11556
11563
  }, [trpc, daimoPayOrder?.id, log]);
11557
- // Include Google Font that is needed for a themes
11558
- if (opts.embedGoogleFonts)
11559
- useThemeFont(ckTheme);
11560
11564
  // Other Configuration
11561
11565
  useEffect(() => setTheme(theme), [theme]);
11562
11566
  useEffect(() => setLang(opts.language || "en-US"), [opts.language]);
11563
11567
  useEffect(() => setErrorMessage(null), [route, open]);
11564
- // Check if chain is supported, elsewise redirect to switches page
11565
- const { chain, isConnected, connector } = useAccount();
11566
- const isChainSupported = useChainIsSupported(chain?.id);
11567
- useEffect(() => {
11568
- if (isConnected && opts.enforceSupportedChains && !isChainSupported) {
11569
- setOpen(true);
11570
- if (route !== ROUTES.SWITCHNETWORKS)
11571
- setRoute(ROUTES.SWITCHNETWORKS);
11572
- }
11573
- }, [isConnected, isChainSupported, chain, route, open]);
11568
+ const { connector } = useAccount();
11574
11569
  // Single source of truth for the currently-connected wallet is the connector
11575
11570
  // exposed by wagmi. See useAccount(). We watch this connector and use it to
11576
11571
  // extract the current WalletConnect wallet, if any.
@@ -11593,9 +11588,10 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
11593
11588
  }, [log]);
11594
11589
  const paymentState = usePaymentState({
11595
11590
  trpc,
11591
+ lockPayParams,
11596
11592
  daimoPayOrder,
11597
11593
  setDaimoPayOrder,
11598
- setOpen,
11594
+ setRoute,
11599
11595
  log,
11600
11596
  redirectReturnUrl,
11601
11597
  });
@@ -11619,11 +11615,13 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
11619
11615
  log(`[PAY] polling in ${intervalMs}ms`);
11620
11616
  const timeout = setTimeout(() => retryBackoff("refreshOrder", () => paymentState.refreshOrder()), intervalMs);
11621
11617
  return () => clearTimeout(timeout);
11622
- }, [daimoPayOrder]);
11618
+ // We don't have good caching on paymentState, so don't include it as a dep
11619
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11620
+ }, [daimoPayOrder, log]);
11623
11621
  const showPayment = async (modalOptions) => {
11624
11622
  const id = daimoPayOrder?.id;
11625
11623
  log(`[PAY] showing payment ${debugJson({ id, modalOptions })}`);
11626
- paymentState.setModalOptions(modalOptions);
11624
+ setModalOptions(modalOptions);
11627
11625
  setOpen(true);
11628
11626
  if (daimoPayOrder &&
11629
11627
  daimoPayOrder.mode === DaimoPayOrderMode.HYDRATED &&
@@ -11663,6 +11661,7 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
11663
11661
  // Other configuration
11664
11662
  options: opts,
11665
11663
  errorMessage,
11664
+ onSuccess,
11666
11665
  confirmationMessage,
11667
11666
  setConfirmationMessage,
11668
11667
  redirectReturnUrl,
@@ -11946,6 +11945,7 @@ function DaimoPayButtonCustom(props) {
11946
11945
  else if (payParams != null) {
11947
11946
  paymentState.setPayParams(payParams);
11948
11947
  }
11948
+ // eslint-disable-next-line react-hooks/exhaustive-deps
11949
11949
  }, [payId, JSON.stringify(payParams || {})]);
11950
11950
  // Set the confirmation message
11951
11951
  const { setConfirmationMessage } = context;
@@ -11977,14 +11977,14 @@ function DaimoPayButtonCustom(props) {
11977
11977
  const intentStatus = order?.intentStatus;
11978
11978
  const hydOrder = order?.mode === DaimoPayOrderMode.HYDRATED ? order : null;
11979
11979
  // Functions to show and hide the modal
11980
- const { children, closeOnSuccess } = props;
11981
- const modalOptions = { closeOnSuccess };
11982
- const show = () => {
11980
+ const { children, closeOnSuccess, resetOnSuccess } = props;
11981
+ const show = useCallback(() => {
11983
11982
  if (paymentState.daimoPayOrder == null)
11984
11983
  return;
11984
+ const modalOptions = { closeOnSuccess, resetOnSuccess };
11985
11985
  context.showPayment(modalOptions);
11986
- };
11987
- const hide = () => context.setOpen(false);
11986
+ }, [context, paymentState.daimoPayOrder, closeOnSuccess, resetOnSuccess]);
11987
+ const hide = useCallback(() => context.setOpen(false), [context]);
11988
11988
  // Emit event handlers when payment status changes
11989
11989
  const sentStart = useRef(false);
11990
11990
  useEffect(() => {
@@ -12079,12 +12079,11 @@ function DaimoPayButtonInner({ disabled }) {
12079
12079
  */
12080
12080
  function useDaimoPayStatus() {
12081
12081
  const { paymentState } = usePayContext();
12082
- const reset = paymentState.resetOrder;
12083
12082
  if (!paymentState || !paymentState.daimoPayOrder)
12084
- return { reset };
12083
+ return undefined;
12085
12084
  const order = paymentState.daimoPayOrder;
12086
12085
  const paymentId = writeDaimoPayOrderID(order.id);
12087
- return { paymentId, status: order.intentStatus, reset };
12086
+ return { paymentId, status: order.intentStatus };
12088
12087
  }
12089
12088
 
12090
12089
  function addressToNumber(address) {