@b3dotfun/sdk 0.0.43-alpha.1 → 0.0.43-alpha.2

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.
@@ -59,11 +59,27 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
59
59
  const lastUrlUpdate = (0, react_4.useRef)(null);
60
60
  // Track if onSuccess has been called for the current order
61
61
  const onSuccessCalled = (0, react_4.useRef)(false);
62
+ // Track animation direction for TransitionPanel
63
+ const animationDirection = (0, react_4.useRef)(null);
64
+ // Track previous panel for proper back navigation
65
+ const previousPanel = (0, react_4.useRef)(PanelView.MAIN);
62
66
  const [activeTab, setActiveTab] = (0, react_4.useState)(defaultActiveTab);
63
67
  const [orderId, setOrderId] = (0, react_4.useState)(loadOrder);
64
68
  const { orderAndTransactions: oat, getOrderAndTransactionsError } = (0, react_1.useAnyspendOrderAndTransactions)(orderId);
65
69
  !!getOrderAndTransactionsError && console.log("getOrderAndTransactionsError", getOrderAndTransactionsError);
66
70
  const [activePanel, setActivePanel] = (0, react_4.useState)(loadOrder ? PanelView.ORDER_DETAILS : PanelView.MAIN);
71
+ // Helper functions to navigate with animation direction
72
+ const navigateToPanel = (0, react_4.useCallback)((panel, direction = "forward") => {
73
+ previousPanel.current = activePanel;
74
+ animationDirection.current = direction;
75
+ setActivePanel(panel);
76
+ }, [activePanel]);
77
+ const navigateBack = (0, react_4.useCallback)(() => {
78
+ animationDirection.current = "back";
79
+ // Navigate back to previous panel or default to MAIN
80
+ const targetPanel = previousPanel.current !== activePanel ? previousPanel.current : PanelView.MAIN;
81
+ setActivePanel(targetPanel);
82
+ }, [activePanel]);
67
83
  const [customRecipients, setCustomRecipients] = (0, react_4.useState)([]);
68
84
  // Add state for selected payment method
69
85
  const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = (0, react_4.useState)(CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE);
@@ -412,7 +428,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
412
428
  const orderId = data.data.id;
413
429
  setOrderId(orderId);
414
430
  // setNewRecipientAddress("");
415
- setActivePanel(PanelView.ORDER_DETAILS);
431
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
416
432
  // Debug: Check payment method before setting URL
417
433
  console.log("Creating order - selectedCryptoPaymentMethod:", selectedCryptoPaymentMethod);
418
434
  // Add orderId and payment method to URL for persistence
@@ -438,7 +454,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
438
454
  onSuccess: data => {
439
455
  const orderId = data.data.id;
440
456
  setOrderId(orderId);
441
- setActivePanel(PanelView.ORDER_DETAILS);
457
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
442
458
  // Add orderId and payment method to URL for persistence
443
459
  const params = new URLSearchParams(searchParams.toString());
444
460
  params.set("orderId", orderId);
@@ -501,7 +517,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
501
517
  if (btnInfo.disable)
502
518
  return;
503
519
  if (!recipientAddress) {
504
- setActivePanel(PanelView.RECIPIENT_SELECTION);
520
+ navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward");
505
521
  return;
506
522
  }
507
523
  try {
@@ -510,7 +526,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
510
526
  if (activeTab === "fiat") {
511
527
  // If no fiat payment method selected, show payment method selection
512
528
  if (selectedFiatPaymentMethod === FiatPaymentMethod_1.FiatPaymentMethod.NONE) {
513
- setActivePanel(PanelView.FIAT_PAYMENT_METHOD);
529
+ navigateToPanel(PanelView.FIAT_PAYMENT_METHOD, "forward");
514
530
  return;
515
531
  }
516
532
  // If payment method is selected, create order directly
@@ -521,7 +537,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
521
537
  // If no payment method selected, show payment method selection
522
538
  if (selectedCryptoPaymentMethod === CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE) {
523
539
  console.log("No payment method selected, showing selection panel");
524
- setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD);
540
+ navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward");
525
541
  return;
526
542
  }
527
543
  // If payment method is selected, create order with payment method info
@@ -541,7 +557,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
541
557
  };
542
558
  const onClickHistory = () => {
543
559
  setOrderId(undefined);
544
- setActivePanel(PanelView.HISTORY);
560
+ navigateToPanel(PanelView.HISTORY, "forward");
545
561
  // Remove orderId and paymentMethod from URL when going back to history
546
562
  const params = new URLSearchParams(searchParams.toString());
547
563
  params.delete("orderId");
@@ -654,8 +670,8 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
654
670
  }
655
671
  }, [searchParams, loadOrder]);
656
672
  const onSelectOrder = (selectedOrderId) => {
657
- setActivePanel(PanelView.MAIN);
658
673
  setOrderId(selectedOrderId);
674
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
659
675
  // Update URL with the new orderId and preserve existing parameters
660
676
  const params = new URLSearchParams(searchParams.toString());
661
677
  params.set("orderId", selectedOrderId);
@@ -675,13 +691,49 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
675
691
  (0, react_4.useEffect)(() => {
676
692
  window.scrollTo({ top: 0, behavior: "smooth" });
677
693
  }, [activePanel]);
678
- const historyView = ((0, jsx_runtime_1.jsx)("div", { className: "mx-auto flex w-[560px] max-w-full flex-col items-center", children: (0, jsx_runtime_1.jsx)(OrderHistory_1.OrderHistory, { mode: mode, onBack: () => setActivePanel(PanelView.MAIN), onSelectOrder: onSelectOrder }) }));
694
+ // Handle browser back button for recipient selection and payment method views
695
+ (0, react_4.useEffect)(() => {
696
+ // Push a new history state when navigating to specific panels
697
+ if (activePanel === PanelView.RECIPIENT_SELECTION) {
698
+ window.history.pushState({ panel: "recipient-selection" }, "");
699
+ }
700
+ else if (activePanel === PanelView.CRYPTO_PAYMENT_METHOD) {
701
+ window.history.pushState({ panel: "crypto-payment-method" }, "");
702
+ }
703
+ else if (activePanel === PanelView.FIAT_PAYMENT_METHOD) {
704
+ window.history.pushState({ panel: "fiat-payment-method" }, "");
705
+ }
706
+ // Listen for popstate event (browser back button)
707
+ const handlePopState = (event) => {
708
+ if (activePanel === PanelView.RECIPIENT_SELECTION ||
709
+ activePanel === PanelView.CRYPTO_PAYMENT_METHOD ||
710
+ activePanel === PanelView.FIAT_PAYMENT_METHOD) {
711
+ // User pressed back while on these panels
712
+ event.preventDefault();
713
+ navigateBack();
714
+ }
715
+ };
716
+ window.addEventListener("popstate", handlePopState);
717
+ return () => {
718
+ window.removeEventListener("popstate", handlePopState);
719
+ };
720
+ }, [activePanel, navigateBack]);
721
+ const historyView = ((0, jsx_runtime_1.jsx)("div", { className: "mx-auto flex w-[560px] max-w-full flex-col items-center", children: (0, jsx_runtime_1.jsx)(OrderHistory_1.OrderHistory, { mode: mode, onBack: navigateBack, onSelectOrder: onSelectOrder }) }));
679
722
  const orderDetailsView = ((0, jsx_runtime_1.jsx)("div", { className: "mx-auto w-[460px] max-w-full", children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex flex-col gap-4", children: oat && ((0, jsx_runtime_1.jsx)(OrderDetails_1.OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTxs: oat.data.relayTxs, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onPaymentMethodChange: setSelectedCryptoPaymentMethod, onBack: () => {
680
723
  setOrderId(undefined);
681
- setActivePanel(PanelView.MAIN);
724
+ navigateBack();
682
725
  setSelectedCryptoPaymentMethod(CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE); // Reset payment method when going back
683
726
  } })) }) }));
684
- const mainView = ((0, jsx_runtime_1.jsxs)("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [isBuyMode && ((0, jsx_runtime_1.jsxs)("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: [selectedDstToken.metadata?.logoURI && ((0, jsx_runtime_1.jsx)("div", { className: "relative", children: (0, jsx_runtime_1.jsx)("img", { src: selectedDstToken.metadata.logoURI, alt: selectedDstToken.symbol, className: "border-as-stroke h-12 w-12 rounded-full border-2 shadow-md" }) })), (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsxs)("h1", { className: "text-as-primary text-xl font-bold", children: ["Buy ", selectedDstToken.symbol] }) })] })), (0, jsx_runtime_1.jsx)(TabSection_1.TabSection, { activeTab: activeTab, setActiveTab: setActiveTab, setSelectedCryptoPaymentMethod: setSelectedCryptoPaymentMethod, setSelectedFiatPaymentMethod: setSelectedFiatPaymentMethod }), (0, jsx_runtime_1.jsxs)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [activeTab === "crypto" ? ((0, jsx_runtime_1.jsx)(CryptoPaySection_1.CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : ((0, jsx_runtime_1.jsx)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: (0, jsx_runtime_1.jsx)(PanelOnramp_1.PanelOnramp, { srcAmountOnRamp: srcAmountOnRamp, setSrcAmountOnRamp: setSrcAmountOnRamp, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: setActivePanel, _recipientAddress: recipientAddress, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, destinationAmount: dstAmount, onDestinationTokenChange: setSelectedDstToken, onDestinationChainChange: setSelectedDstChainId, fiatPaymentMethodIndex: PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: PanelView.RECIPIENT_SELECTION, hideDstToken: isBuyMode, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL), customUsdInputValues: customUsdInputValues }) })), (0, jsx_runtime_1.jsx)(react_2.Button, { variant: "ghost", className: (0, cn_1.cn)("border-as-stroke bg-as-surface-primary absolute left-1/2 top-1/2 z-10 h-10 w-10 -translate-x-1/2 -translate-y-1/2 rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", isBuyMode && "top-[calc(50%+56px)] cursor-default", activeTab === "fiat" && "hidden"), onClick: () => {
727
+ const mainView = ((0, jsx_runtime_1.jsxs)("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [isBuyMode && ((0, jsx_runtime_1.jsxs)("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: [selectedDstToken.metadata?.logoURI && ((0, jsx_runtime_1.jsx)("div", { className: "relative", children: (0, jsx_runtime_1.jsx)("img", { src: selectedDstToken.metadata.logoURI, alt: selectedDstToken.symbol, className: "border-as-stroke h-12 w-12 rounded-full border-2 shadow-md" }) })), (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsxs)("h1", { className: "text-as-primary text-xl font-bold", children: ["Buy ", selectedDstToken.symbol] }) })] })), (0, jsx_runtime_1.jsx)(TabSection_1.TabSection, { activeTab: activeTab, setActiveTab: setActiveTab, setSelectedCryptoPaymentMethod: setSelectedCryptoPaymentMethod, setSelectedFiatPaymentMethod: setSelectedFiatPaymentMethod }), (0, jsx_runtime_1.jsxs)("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [activeTab === "crypto" ? ((0, jsx_runtime_1.jsx)(CryptoPaySection_1.CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward"), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : ((0, jsx_runtime_1.jsx)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: (0, jsx_runtime_1.jsx)(PanelOnramp_1.PanelOnramp, { srcAmountOnRamp: srcAmountOnRamp, setSrcAmountOnRamp: setSrcAmountOnRamp, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: (panelIndex) => {
728
+ // Map panel index to navigation with direction
729
+ const panelsWithForwardNav = [PanelView.FIAT_PAYMENT_METHOD, PanelView.RECIPIENT_SELECTION];
730
+ if (panelsWithForwardNav.includes(panelIndex)) {
731
+ navigateToPanel(panelIndex, "forward");
732
+ }
733
+ else {
734
+ setActivePanel(panelIndex);
735
+ }
736
+ }, _recipientAddress: recipientAddress, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, destinationAmount: dstAmount, onDestinationTokenChange: setSelectedDstToken, onDestinationChainChange: setSelectedDstChainId, fiatPaymentMethodIndex: PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: PanelView.RECIPIENT_SELECTION, hideDstToken: isBuyMode, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), customUsdInputValues: customUsdInputValues }) })), (0, jsx_runtime_1.jsx)(react_2.Button, { variant: "ghost", className: (0, cn_1.cn)("border-as-stroke bg-as-surface-primary absolute left-1/2 top-1/2 z-10 h-10 w-10 -translate-x-1/2 -translate-y-1/2 rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", isBuyMode && "top-[calc(50%+56px)] cursor-default", activeTab === "fiat" && "hidden"), onClick: () => {
685
737
  if (activeTab === "fiat" || isBuyMode) {
686
738
  return;
687
739
  }
@@ -700,13 +752,13 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
700
752
  const tempDstAmount = dstAmount;
701
753
  setSrcAmount(tempDstAmount);
702
754
  setDstAmount(tempSrcAmount);
703
- }, children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }), activeTab === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode: isBuyMode, selectedRecipientAddress: recipientAddress, recipientName: recipientName || undefined, onSelectRecipient: () => setActivePanel(PanelView.RECIPIENT_SELECTION), dstAmount: dstAmount, dstToken: selectedDstToken, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: setSelectedDstChainId, setSelectedDstToken: setSelectedDstToken, onChangeDstAmount: value => {
755
+ }, children: (0, jsx_runtime_1.jsx)("div", { className: "relative flex items-center justify-center transition-opacity", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }), activeTab === "crypto" && ((0, jsx_runtime_1.jsx)(CryptoReceiveSection_1.CryptoReceiveSection, { isDepositMode: false, isBuyMode: isBuyMode, selectedRecipientAddress: recipientAddress, recipientName: recipientName || undefined, onSelectRecipient: () => navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward"), dstAmount: dstAmount, dstToken: selectedDstToken, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: setSelectedDstChainId, setSelectedDstToken: setSelectedDstToken, onChangeDstAmount: value => {
704
756
  setIsSrcInputDirty(false);
705
757
  setDstAmount(value);
706
- }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL) }))] }), (0, jsx_runtime_1.jsx)(ErrorSection_1.ErrorSection, { error: getAnyspendQuoteError }), (0, jsx_runtime_1.jsxs)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: (0, cn_1.cn)("mt-4 flex w-full max-w-[460px] flex-col gap-2", getAnyspendQuoteError && "mt-0"), children: [(0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (0, cn_1.cn)("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: (0, cn_1.cn)(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: btnInfo.text }), !hideTransactionHistoryButton && (globalAddress || recipientAddress) ? ((0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "link", onClick: onClickHistory, className: "text-as-primary/50 hover:text-as-primary flex items-center gap-1 transition-colors", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.HistoryIcon, { className: "h-4 w-4" }), " ", (0, jsx_runtime_1.jsx)("span", { className: "pr-4", children: "Transaction History" })] })) : null] })] }));
758
+ }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward") }))] }), (0, jsx_runtime_1.jsx)(ErrorSection_1.ErrorSection, { error: getAnyspendQuoteError }), (0, jsx_runtime_1.jsxs)(react_3.motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: (0, cn_1.cn)("mt-4 flex w-full max-w-[460px] flex-col gap-2", getAnyspendQuoteError && "mt-0"), children: [(0, jsx_runtime_1.jsx)(react_2.ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: (0, cn_1.cn)("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: (0, cn_1.cn)(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: btnInfo.text }), !hideTransactionHistoryButton && (globalAddress || recipientAddress) ? ((0, jsx_runtime_1.jsxs)(react_2.Button, { variant: "link", onClick: onClickHistory, className: "text-as-primary/50 hover:text-as-primary flex items-center gap-1 transition-colors", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.HistoryIcon, { className: "h-4 w-4" }), " ", (0, jsx_runtime_1.jsx)("span", { className: "pr-4", children: "Transaction History" })] })) : null] })] }));
707
759
  const onrampPaymentView = ((0, jsx_runtime_1.jsx)(PanelOnrampPayment_1.PanelOnrampPayment, { srcAmountOnRamp: srcAmountOnRamp, recipientName: recipientName || undefined, recipientAddress: recipientAddress, isBuyMode: isBuyMode, destinationTokenChainId: destinationTokenChainId, destinationTokenAddress: destinationTokenAddress, selectedDstChainId: selectedDstChainId, selectedDstToken: selectedDstToken, orderType: "swap", anyspendQuote: anyspendQuote, globalAddress: globalAddress, onOrderCreated: orderId => {
708
760
  setOrderId(orderId);
709
- setActivePanel(PanelView.ORDER_DETAILS);
761
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
710
762
  // Add orderId and payment method to URL for persistence
711
763
  const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
712
764
  params.set("orderId", orderId);
@@ -718,20 +770,20 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
718
770
  params.set("paymentMethod", selectedCryptoPaymentMethod);
719
771
  }
720
772
  router.push(`${window.location.pathname}?${params.toString()}`);
721
- }, onBack: () => setActivePanel(PanelView.MAIN), recipientEnsName: globalWallet?.ensName, recipientImageUrl: globalWallet?.meta?.icon }));
722
- const recipientSelectionView = ((0, jsx_runtime_1.jsx)(RecipientSelection_1.RecipientSelection, { initialValue: recipientAddress || "", onBack: () => setActivePanel(PanelView.MAIN), onConfirm: address => {
773
+ }, onBack: navigateBack, recipientEnsName: globalWallet?.ensName, recipientImageUrl: globalWallet?.meta?.icon }));
774
+ const recipientSelectionView = ((0, jsx_runtime_1.jsx)(RecipientSelection_1.RecipientSelection, { initialValue: recipientAddress || "", onBack: navigateBack, onConfirm: address => {
723
775
  setRecipientAddress(address);
724
- setActivePanel(PanelView.MAIN);
776
+ navigateBack();
725
777
  } }));
726
- const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: globalWallet, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(PanelView.MAIN), onSelectPaymentMethod: (method) => {
778
+ const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: globalWallet, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: navigateBack, onSelectPaymentMethod: (method) => {
727
779
  setSelectedCryptoPaymentMethod(method);
728
- setActivePanel(PanelView.MAIN);
780
+ navigateBack();
729
781
  } }));
730
- const fiatPaymentMethodView = ((0, jsx_runtime_1.jsx)(FiatPaymentMethod_1.FiatPaymentMethodComponent, { selectedPaymentMethod: selectedFiatPaymentMethod, setSelectedPaymentMethod: setSelectedFiatPaymentMethod, onBack: () => setActivePanel(PanelView.MAIN), onSelectPaymentMethod: (method) => {
782
+ const fiatPaymentMethodView = ((0, jsx_runtime_1.jsx)(FiatPaymentMethod_1.FiatPaymentMethodComponent, { selectedPaymentMethod: selectedFiatPaymentMethod, setSelectedPaymentMethod: setSelectedFiatPaymentMethod, onBack: navigateBack, onSelectPaymentMethod: (method) => {
731
783
  setSelectedFiatPaymentMethod(method);
732
- setActivePanel(PanelView.MAIN); // Go back to main panel to show updated pricing
784
+ navigateBack(); // Go back to main panel to show updated pricing
733
785
  }, srcAmountOnRamp: srcAmountOnRamp }));
734
- const pointsDetailView = ((0, jsx_runtime_1.jsx)(PointsDetailPanel_1.PointsDetailPanel, { pointsAmount: anyspendQuote?.data?.pointsAmount || 0, onBack: () => setActivePanel(PanelView.MAIN) }));
786
+ const pointsDetailView = ((0, jsx_runtime_1.jsx)(PointsDetailPanel_1.PointsDetailPanel, { pointsAmount: anyspendQuote?.data?.pointsAmount || 0, onBack: navigateBack }));
735
787
  // Add tabs to the main component when no order is loaded
736
788
  return ((0, jsx_runtime_1.jsx)(react_2.StyleRoot, { children: (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)("anyspend-container font-inter mx-auto w-full max-w-[460px]", mode === "page" &&
737
789
  "bg-as-surface-primary border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: (0, jsx_runtime_1.jsx)(react_2.TransitionPanel, { activeIndex: orderId
@@ -742,10 +794,16 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
742
794
  ? PanelView.MAIN
743
795
  : activePanel, className: (0, cn_1.cn)("rounded-2xl", {
744
796
  "mt-0": mode === "modal",
745
- }), variants: {
746
- enter: { x: 300, opacity: 0 },
797
+ }), custom: animationDirection.current, variants: {
798
+ enter: direction => ({
799
+ x: direction === "back" ? -300 : 300,
800
+ opacity: 0,
801
+ }),
747
802
  center: { x: 0, opacity: 1 },
748
- exit: { x: -300, opacity: 0 },
803
+ exit: direction => ({
804
+ x: direction === "back" ? 300 : -300,
805
+ opacity: 0,
806
+ }),
749
807
  }, transition: { type: "spring", stiffness: 300, damping: 30 }, children: [
750
808
  (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)(mode === "page" && "p-6"), children: mainView }, "main-view"),
751
809
  (0, jsx_runtime_1.jsx)("div", { className: (0, cn_1.cn)(mode === "page" && "p-6"), children: historyView }, "history-view"),
@@ -52,11 +52,27 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
52
52
  const lastUrlUpdate = useRef(null);
53
53
  // Track if onSuccess has been called for the current order
54
54
  const onSuccessCalled = useRef(false);
55
+ // Track animation direction for TransitionPanel
56
+ const animationDirection = useRef(null);
57
+ // Track previous panel for proper back navigation
58
+ const previousPanel = useRef(PanelView.MAIN);
55
59
  const [activeTab, setActiveTab] = useState(defaultActiveTab);
56
60
  const [orderId, setOrderId] = useState(loadOrder);
57
61
  const { orderAndTransactions: oat, getOrderAndTransactionsError } = useAnyspendOrderAndTransactions(orderId);
58
62
  !!getOrderAndTransactionsError && console.log("getOrderAndTransactionsError", getOrderAndTransactionsError);
59
63
  const [activePanel, setActivePanel] = useState(loadOrder ? PanelView.ORDER_DETAILS : PanelView.MAIN);
64
+ // Helper functions to navigate with animation direction
65
+ const navigateToPanel = useCallback((panel, direction = "forward") => {
66
+ previousPanel.current = activePanel;
67
+ animationDirection.current = direction;
68
+ setActivePanel(panel);
69
+ }, [activePanel]);
70
+ const navigateBack = useCallback(() => {
71
+ animationDirection.current = "back";
72
+ // Navigate back to previous panel or default to MAIN
73
+ const targetPanel = previousPanel.current !== activePanel ? previousPanel.current : PanelView.MAIN;
74
+ setActivePanel(targetPanel);
75
+ }, [activePanel]);
60
76
  const [customRecipients, setCustomRecipients] = useState([]);
61
77
  // Add state for selected payment method
62
78
  const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = useState(CryptoPaymentMethodType.NONE);
@@ -405,7 +421,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
405
421
  const orderId = data.data.id;
406
422
  setOrderId(orderId);
407
423
  // setNewRecipientAddress("");
408
- setActivePanel(PanelView.ORDER_DETAILS);
424
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
409
425
  // Debug: Check payment method before setting URL
410
426
  console.log("Creating order - selectedCryptoPaymentMethod:", selectedCryptoPaymentMethod);
411
427
  // Add orderId and payment method to URL for persistence
@@ -431,7 +447,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
431
447
  onSuccess: data => {
432
448
  const orderId = data.data.id;
433
449
  setOrderId(orderId);
434
- setActivePanel(PanelView.ORDER_DETAILS);
450
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
435
451
  // Add orderId and payment method to URL for persistence
436
452
  const params = new URLSearchParams(searchParams.toString());
437
453
  params.set("orderId", orderId);
@@ -494,7 +510,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
494
510
  if (btnInfo.disable)
495
511
  return;
496
512
  if (!recipientAddress) {
497
- setActivePanel(PanelView.RECIPIENT_SELECTION);
513
+ navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward");
498
514
  return;
499
515
  }
500
516
  try {
@@ -503,7 +519,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
503
519
  if (activeTab === "fiat") {
504
520
  // If no fiat payment method selected, show payment method selection
505
521
  if (selectedFiatPaymentMethod === FiatPaymentMethod.NONE) {
506
- setActivePanel(PanelView.FIAT_PAYMENT_METHOD);
522
+ navigateToPanel(PanelView.FIAT_PAYMENT_METHOD, "forward");
507
523
  return;
508
524
  }
509
525
  // If payment method is selected, create order directly
@@ -514,7 +530,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
514
530
  // If no payment method selected, show payment method selection
515
531
  if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
516
532
  console.log("No payment method selected, showing selection panel");
517
- setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD);
533
+ navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward");
518
534
  return;
519
535
  }
520
536
  // If payment method is selected, create order with payment method info
@@ -534,7 +550,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
534
550
  };
535
551
  const onClickHistory = () => {
536
552
  setOrderId(undefined);
537
- setActivePanel(PanelView.HISTORY);
553
+ navigateToPanel(PanelView.HISTORY, "forward");
538
554
  // Remove orderId and paymentMethod from URL when going back to history
539
555
  const params = new URLSearchParams(searchParams.toString());
540
556
  params.delete("orderId");
@@ -647,8 +663,8 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
647
663
  }
648
664
  }, [searchParams, loadOrder]);
649
665
  const onSelectOrder = (selectedOrderId) => {
650
- setActivePanel(PanelView.MAIN);
651
666
  setOrderId(selectedOrderId);
667
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
652
668
  // Update URL with the new orderId and preserve existing parameters
653
669
  const params = new URLSearchParams(searchParams.toString());
654
670
  params.set("orderId", selectedOrderId);
@@ -668,13 +684,49 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
668
684
  useEffect(() => {
669
685
  window.scrollTo({ top: 0, behavior: "smooth" });
670
686
  }, [activePanel]);
671
- const historyView = (_jsx("div", { className: "mx-auto flex w-[560px] max-w-full flex-col items-center", children: _jsx(OrderHistory, { mode: mode, onBack: () => setActivePanel(PanelView.MAIN), onSelectOrder: onSelectOrder }) }));
687
+ // Handle browser back button for recipient selection and payment method views
688
+ useEffect(() => {
689
+ // Push a new history state when navigating to specific panels
690
+ if (activePanel === PanelView.RECIPIENT_SELECTION) {
691
+ window.history.pushState({ panel: "recipient-selection" }, "");
692
+ }
693
+ else if (activePanel === PanelView.CRYPTO_PAYMENT_METHOD) {
694
+ window.history.pushState({ panel: "crypto-payment-method" }, "");
695
+ }
696
+ else if (activePanel === PanelView.FIAT_PAYMENT_METHOD) {
697
+ window.history.pushState({ panel: "fiat-payment-method" }, "");
698
+ }
699
+ // Listen for popstate event (browser back button)
700
+ const handlePopState = (event) => {
701
+ if (activePanel === PanelView.RECIPIENT_SELECTION ||
702
+ activePanel === PanelView.CRYPTO_PAYMENT_METHOD ||
703
+ activePanel === PanelView.FIAT_PAYMENT_METHOD) {
704
+ // User pressed back while on these panels
705
+ event.preventDefault();
706
+ navigateBack();
707
+ }
708
+ };
709
+ window.addEventListener("popstate", handlePopState);
710
+ return () => {
711
+ window.removeEventListener("popstate", handlePopState);
712
+ };
713
+ }, [activePanel, navigateBack]);
714
+ const historyView = (_jsx("div", { className: "mx-auto flex w-[560px] max-w-full flex-col items-center", children: _jsx(OrderHistory, { mode: mode, onBack: navigateBack, onSelectOrder: onSelectOrder }) }));
672
715
  const orderDetailsView = (_jsx("div", { className: "mx-auto w-[460px] max-w-full", children: _jsx("div", { className: "relative flex flex-col gap-4", children: oat && (_jsx(OrderDetails, { mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTxs: oat.data.relayTxs, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onPaymentMethodChange: setSelectedCryptoPaymentMethod, onBack: () => {
673
716
  setOrderId(undefined);
674
- setActivePanel(PanelView.MAIN);
717
+ navigateBack();
675
718
  setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.NONE); // Reset payment method when going back
676
719
  } })) }) }));
677
- const mainView = (_jsxs("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [isBuyMode && (_jsxs("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: [selectedDstToken.metadata?.logoURI && (_jsx("div", { className: "relative", children: _jsx("img", { src: selectedDstToken.metadata.logoURI, alt: selectedDstToken.symbol, className: "border-as-stroke h-12 w-12 rounded-full border-2 shadow-md" }) })), _jsx("div", { children: _jsxs("h1", { className: "text-as-primary text-xl font-bold", children: ["Buy ", selectedDstToken.symbol] }) })] })), _jsx(TabSection, { activeTab: activeTab, setActiveTab: setActiveTab, setSelectedCryptoPaymentMethod: setSelectedCryptoPaymentMethod, setSelectedFiatPaymentMethod: setSelectedFiatPaymentMethod }), _jsxs("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [activeTab === "crypto" ? (_jsx(CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : (_jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: _jsx(PanelOnramp, { srcAmountOnRamp: srcAmountOnRamp, setSrcAmountOnRamp: setSrcAmountOnRamp, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: setActivePanel, _recipientAddress: recipientAddress, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, destinationAmount: dstAmount, onDestinationTokenChange: setSelectedDstToken, onDestinationChainChange: setSelectedDstChainId, fiatPaymentMethodIndex: PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: PanelView.RECIPIENT_SELECTION, hideDstToken: isBuyMode, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL), customUsdInputValues: customUsdInputValues }) })), _jsx(Button, { variant: "ghost", className: cn("border-as-stroke bg-as-surface-primary absolute left-1/2 top-1/2 z-10 h-10 w-10 -translate-x-1/2 -translate-y-1/2 rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", isBuyMode && "top-[calc(50%+56px)] cursor-default", activeTab === "fiat" && "hidden"), onClick: () => {
720
+ const mainView = (_jsxs("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [isBuyMode && (_jsxs("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: [selectedDstToken.metadata?.logoURI && (_jsx("div", { className: "relative", children: _jsx("img", { src: selectedDstToken.metadata.logoURI, alt: selectedDstToken.symbol, className: "border-as-stroke h-12 w-12 rounded-full border-2 shadow-md" }) })), _jsx("div", { children: _jsxs("h1", { className: "text-as-primary text-xl font-bold", children: ["Buy ", selectedDstToken.symbol] }) })] })), _jsx(TabSection, { activeTab: activeTab, setActiveTab: setActiveTab, setSelectedCryptoPaymentMethod: setSelectedCryptoPaymentMethod, setSelectedFiatPaymentMethod: setSelectedFiatPaymentMethod }), _jsxs("div", { className: "relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2", children: [activeTab === "crypto" ? (_jsx(CryptoPaySection, { selectedSrcChainId: selectedSrcChainId, setSelectedSrcChainId: setSelectedSrcChainId, selectedSrcToken: selectedSrcToken, setSelectedSrcToken: setSelectedSrcToken, srcAmount: srcAmount, setSrcAmount: setSrcAmount, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward"), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect })) : (_jsx(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, children: _jsx(PanelOnramp, { srcAmountOnRamp: srcAmountOnRamp, setSrcAmountOnRamp: setSrcAmountOnRamp, selectedPaymentMethod: selectedFiatPaymentMethod, setActivePanel: (panelIndex) => {
721
+ // Map panel index to navigation with direction
722
+ const panelsWithForwardNav = [PanelView.FIAT_PAYMENT_METHOD, PanelView.RECIPIENT_SELECTION];
723
+ if (panelsWithForwardNav.includes(panelIndex)) {
724
+ navigateToPanel(panelIndex, "forward");
725
+ }
726
+ else {
727
+ setActivePanel(panelIndex);
728
+ }
729
+ }, _recipientAddress: recipientAddress, destinationToken: selectedDstToken, destinationChainId: selectedDstChainId, destinationAmount: dstAmount, onDestinationTokenChange: setSelectedDstToken, onDestinationChainChange: setSelectedDstChainId, fiatPaymentMethodIndex: PanelView.FIAT_PAYMENT_METHOD, recipientSelectionPanelIndex: PanelView.RECIPIENT_SELECTION, hideDstToken: isBuyMode, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward"), customUsdInputValues: customUsdInputValues }) })), _jsx(Button, { variant: "ghost", className: cn("border-as-stroke bg-as-surface-primary absolute left-1/2 top-1/2 z-10 h-10 w-10 -translate-x-1/2 -translate-y-1/2 rounded-xl border-2 sm:h-8 sm:w-8 sm:rounded-xl", isBuyMode && "top-[calc(50%+56px)] cursor-default", activeTab === "fiat" && "hidden"), onClick: () => {
678
730
  if (activeTab === "fiat" || isBuyMode) {
679
731
  return;
680
732
  }
@@ -693,13 +745,13 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
693
745
  const tempDstAmount = dstAmount;
694
746
  setSrcAmount(tempDstAmount);
695
747
  setDstAmount(tempSrcAmount);
696
- }, children: _jsx("div", { className: "relative flex items-center justify-center transition-opacity", children: _jsx(ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }), activeTab === "crypto" && (_jsx(CryptoReceiveSection, { isDepositMode: false, isBuyMode: isBuyMode, selectedRecipientAddress: recipientAddress, recipientName: recipientName || undefined, onSelectRecipient: () => setActivePanel(PanelView.RECIPIENT_SELECTION), dstAmount: dstAmount, dstToken: selectedDstToken, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: setSelectedDstChainId, setSelectedDstToken: setSelectedDstToken, onChangeDstAmount: value => {
748
+ }, children: _jsx("div", { className: "relative flex items-center justify-center transition-opacity", children: _jsx(ArrowDown, { className: "text-as-primary/50 h-5 w-5" }) }) }), activeTab === "crypto" && (_jsx(CryptoReceiveSection, { isDepositMode: false, isBuyMode: isBuyMode, selectedRecipientAddress: recipientAddress, recipientName: recipientName || undefined, onSelectRecipient: () => navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward"), dstAmount: dstAmount, dstToken: selectedDstToken, selectedDstChainId: selectedDstChainId, setSelectedDstChainId: setSelectedDstChainId, setSelectedDstToken: setSelectedDstToken, onChangeDstAmount: value => {
697
749
  setIsSrcInputDirty(false);
698
750
  setDstAmount(value);
699
- }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => setActivePanel(PanelView.POINTS_DETAIL) }))] }), _jsx(ErrorSection, { error: getAnyspendQuoteError }), _jsxs(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: cn("mt-4 flex w-full max-w-[460px] flex-col gap-2", getAnyspendQuoteError && "mt-0"), children: [_jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: cn("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: cn(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: btnInfo.text }), !hideTransactionHistoryButton && (globalAddress || recipientAddress) ? (_jsxs(Button, { variant: "link", onClick: onClickHistory, className: "text-as-primary/50 hover:text-as-primary flex items-center gap-1 transition-colors", children: [_jsx(HistoryIcon, { className: "h-4 w-4" }), " ", _jsx("span", { className: "pr-4", children: "Transaction History" })] })) : null] })] }));
751
+ }, anyspendQuote: anyspendQuote, onShowPointsDetail: () => navigateToPanel(PanelView.POINTS_DETAIL, "forward") }))] }), _jsx(ErrorSection, { error: getAnyspendQuoteError }), _jsxs(motion.div, { initial: { opacity: 0, y: 20, filter: "blur(10px)" }, animate: { opacity: 1, y: 0, filter: "blur(0px)" }, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: cn("mt-4 flex w-full max-w-[460px] flex-col gap-2", getAnyspendQuoteError && "mt-0"), children: [_jsx(ShinyButton, { accentColor: "hsl(var(--as-brand))", disabled: btnInfo.disable, onClick: onMainButtonClick, className: cn("as-main-button relative w-full", btnInfo.error ? "!bg-as-red" : btnInfo.disable ? "!bg-as-on-surface-2" : "!bg-as-brand"), textClassName: cn(btnInfo.error ? "text-white" : btnInfo.disable ? "text-as-secondary" : "text-white"), children: btnInfo.text }), !hideTransactionHistoryButton && (globalAddress || recipientAddress) ? (_jsxs(Button, { variant: "link", onClick: onClickHistory, className: "text-as-primary/50 hover:text-as-primary flex items-center gap-1 transition-colors", children: [_jsx(HistoryIcon, { className: "h-4 w-4" }), " ", _jsx("span", { className: "pr-4", children: "Transaction History" })] })) : null] })] }));
700
752
  const onrampPaymentView = (_jsx(PanelOnrampPayment, { srcAmountOnRamp: srcAmountOnRamp, recipientName: recipientName || undefined, recipientAddress: recipientAddress, isBuyMode: isBuyMode, destinationTokenChainId: destinationTokenChainId, destinationTokenAddress: destinationTokenAddress, selectedDstChainId: selectedDstChainId, selectedDstToken: selectedDstToken, orderType: "swap", anyspendQuote: anyspendQuote, globalAddress: globalAddress, onOrderCreated: orderId => {
701
753
  setOrderId(orderId);
702
- setActivePanel(PanelView.ORDER_DETAILS);
754
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
703
755
  // Add orderId and payment method to URL for persistence
704
756
  const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
705
757
  params.set("orderId", orderId);
@@ -711,20 +763,20 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
711
763
  params.set("paymentMethod", selectedCryptoPaymentMethod);
712
764
  }
713
765
  router.push(`${window.location.pathname}?${params.toString()}`);
714
- }, onBack: () => setActivePanel(PanelView.MAIN), recipientEnsName: globalWallet?.ensName, recipientImageUrl: globalWallet?.meta?.icon }));
715
- const recipientSelectionView = (_jsx(RecipientSelection, { initialValue: recipientAddress || "", onBack: () => setActivePanel(PanelView.MAIN), onConfirm: address => {
766
+ }, onBack: navigateBack, recipientEnsName: globalWallet?.ensName, recipientImageUrl: globalWallet?.meta?.icon }));
767
+ const recipientSelectionView = (_jsx(RecipientSelection, { initialValue: recipientAddress || "", onBack: navigateBack, onConfirm: address => {
716
768
  setRecipientAddress(address);
717
- setActivePanel(PanelView.MAIN);
769
+ navigateBack();
718
770
  } }));
719
- const cryptoPaymentMethodView = (_jsx(CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: globalWallet, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(PanelView.MAIN), onSelectPaymentMethod: (method) => {
771
+ const cryptoPaymentMethodView = (_jsx(CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: globalWallet, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: navigateBack, onSelectPaymentMethod: (method) => {
720
772
  setSelectedCryptoPaymentMethod(method);
721
- setActivePanel(PanelView.MAIN);
773
+ navigateBack();
722
774
  } }));
723
- const fiatPaymentMethodView = (_jsx(FiatPaymentMethodComponent, { selectedPaymentMethod: selectedFiatPaymentMethod, setSelectedPaymentMethod: setSelectedFiatPaymentMethod, onBack: () => setActivePanel(PanelView.MAIN), onSelectPaymentMethod: (method) => {
775
+ const fiatPaymentMethodView = (_jsx(FiatPaymentMethodComponent, { selectedPaymentMethod: selectedFiatPaymentMethod, setSelectedPaymentMethod: setSelectedFiatPaymentMethod, onBack: navigateBack, onSelectPaymentMethod: (method) => {
724
776
  setSelectedFiatPaymentMethod(method);
725
- setActivePanel(PanelView.MAIN); // Go back to main panel to show updated pricing
777
+ navigateBack(); // Go back to main panel to show updated pricing
726
778
  }, srcAmountOnRamp: srcAmountOnRamp }));
727
- const pointsDetailView = (_jsx(PointsDetailPanel, { pointsAmount: anyspendQuote?.data?.pointsAmount || 0, onBack: () => setActivePanel(PanelView.MAIN) }));
779
+ const pointsDetailView = (_jsx(PointsDetailPanel, { pointsAmount: anyspendQuote?.data?.pointsAmount || 0, onBack: navigateBack }));
728
780
  // Add tabs to the main component when no order is loaded
729
781
  return (_jsx(StyleRoot, { children: _jsx("div", { className: cn("anyspend-container font-inter mx-auto w-full max-w-[460px]", mode === "page" &&
730
782
  "bg-as-surface-primary border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: _jsx(TransitionPanel, { activeIndex: orderId
@@ -735,10 +787,16 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
735
787
  ? PanelView.MAIN
736
788
  : activePanel, className: cn("rounded-2xl", {
737
789
  "mt-0": mode === "modal",
738
- }), variants: {
739
- enter: { x: 300, opacity: 0 },
790
+ }), custom: animationDirection.current, variants: {
791
+ enter: direction => ({
792
+ x: direction === "back" ? -300 : 300,
793
+ opacity: 0,
794
+ }),
740
795
  center: { x: 0, opacity: 1 },
741
- exit: { x: -300, opacity: 0 },
796
+ exit: direction => ({
797
+ x: direction === "back" ? 300 : -300,
798
+ opacity: 0,
799
+ }),
742
800
  }, transition: { type: "spring", stiffness: 300, damping: 30 }, children: [
743
801
  _jsx("div", { className: cn(mode === "page" && "p-6"), children: mainView }, "main-view"),
744
802
  _jsx("div", { className: cn(mode === "page" && "p-6"), children: historyView }, "history-view"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.0.43-alpha.1",
3
+ "version": "0.0.43-alpha.2",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -140,6 +140,11 @@ function AnySpendInner({
140
140
  // Track if onSuccess has been called for the current order
141
141
  const onSuccessCalled = useRef(false);
142
142
 
143
+ // Track animation direction for TransitionPanel
144
+ const animationDirection = useRef<"forward" | "back" | null>(null);
145
+ // Track previous panel for proper back navigation
146
+ const previousPanel = useRef<PanelView>(PanelView.MAIN);
147
+
143
148
  const [activeTab, setActiveTab] = useState<"crypto" | "fiat">(defaultActiveTab);
144
149
 
145
150
  const [orderId, setOrderId] = useState<string | undefined>(loadOrder);
@@ -147,6 +152,23 @@ function AnySpendInner({
147
152
  !!getOrderAndTransactionsError && console.log("getOrderAndTransactionsError", getOrderAndTransactionsError);
148
153
 
149
154
  const [activePanel, setActivePanel] = useState<PanelView>(loadOrder ? PanelView.ORDER_DETAILS : PanelView.MAIN);
155
+
156
+ // Helper functions to navigate with animation direction
157
+ const navigateToPanel = useCallback(
158
+ (panel: PanelView, direction: "forward" | "back" = "forward") => {
159
+ previousPanel.current = activePanel;
160
+ animationDirection.current = direction;
161
+ setActivePanel(panel);
162
+ },
163
+ [activePanel],
164
+ );
165
+
166
+ const navigateBack = useCallback(() => {
167
+ animationDirection.current = "back";
168
+ // Navigate back to previous panel or default to MAIN
169
+ const targetPanel = previousPanel.current !== activePanel ? previousPanel.current : PanelView.MAIN;
170
+ setActivePanel(targetPanel);
171
+ }, [activePanel]);
150
172
  const [customRecipients, setCustomRecipients] = useState<RecipientOption[]>([]);
151
173
  // Add state for selected payment method
152
174
  const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = useState<CryptoPaymentMethodType>(
@@ -544,7 +566,7 @@ function AnySpendInner({
544
566
  const orderId = data.data.id;
545
567
  setOrderId(orderId);
546
568
  // setNewRecipientAddress("");
547
- setActivePanel(PanelView.ORDER_DETAILS);
569
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
548
570
 
549
571
  // Debug: Check payment method before setting URL
550
572
  console.log("Creating order - selectedCryptoPaymentMethod:", selectedCryptoPaymentMethod);
@@ -572,7 +594,7 @@ function AnySpendInner({
572
594
  onSuccess: data => {
573
595
  const orderId = data.data.id;
574
596
  setOrderId(orderId);
575
- setActivePanel(PanelView.ORDER_DETAILS);
597
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
576
598
 
577
599
  // Add orderId and payment method to URL for persistence
578
600
  const params = new URLSearchParams(searchParams.toString());
@@ -638,7 +660,7 @@ function AnySpendInner({
638
660
  if (btnInfo.disable) return;
639
661
 
640
662
  if (!recipientAddress) {
641
- setActivePanel(PanelView.RECIPIENT_SELECTION);
663
+ navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward");
642
664
  return;
643
665
  }
644
666
 
@@ -649,7 +671,7 @@ function AnySpendInner({
649
671
  if (activeTab === "fiat") {
650
672
  // If no fiat payment method selected, show payment method selection
651
673
  if (selectedFiatPaymentMethod === FiatPaymentMethod.NONE) {
652
- setActivePanel(PanelView.FIAT_PAYMENT_METHOD);
674
+ navigateToPanel(PanelView.FIAT_PAYMENT_METHOD, "forward");
653
675
  return;
654
676
  }
655
677
  // If payment method is selected, create order directly
@@ -661,7 +683,7 @@ function AnySpendInner({
661
683
  // If no payment method selected, show payment method selection
662
684
  if (selectedCryptoPaymentMethod === CryptoPaymentMethodType.NONE) {
663
685
  console.log("No payment method selected, showing selection panel");
664
- setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD);
686
+ navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward");
665
687
  return;
666
688
  }
667
689
 
@@ -684,7 +706,7 @@ function AnySpendInner({
684
706
 
685
707
  const onClickHistory = () => {
686
708
  setOrderId(undefined);
687
- setActivePanel(PanelView.HISTORY);
709
+ navigateToPanel(PanelView.HISTORY, "forward");
688
710
  // Remove orderId and paymentMethod from URL when going back to history
689
711
  const params = new URLSearchParams(searchParams.toString());
690
712
  params.delete("orderId");
@@ -807,8 +829,8 @@ function AnySpendInner({
807
829
  }, [searchParams, loadOrder]);
808
830
 
809
831
  const onSelectOrder = (selectedOrderId: string) => {
810
- setActivePanel(PanelView.MAIN);
811
832
  setOrderId(selectedOrderId);
833
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
812
834
  // Update URL with the new orderId and preserve existing parameters
813
835
  const params = new URLSearchParams(searchParams.toString());
814
836
  params.set("orderId", selectedOrderId);
@@ -830,9 +852,40 @@ function AnySpendInner({
830
852
  window.scrollTo({ top: 0, behavior: "smooth" });
831
853
  }, [activePanel]);
832
854
 
855
+ // Handle browser back button for recipient selection and payment method views
856
+ useEffect(() => {
857
+ // Push a new history state when navigating to specific panels
858
+ if (activePanel === PanelView.RECIPIENT_SELECTION) {
859
+ window.history.pushState({ panel: "recipient-selection" }, "");
860
+ } else if (activePanel === PanelView.CRYPTO_PAYMENT_METHOD) {
861
+ window.history.pushState({ panel: "crypto-payment-method" }, "");
862
+ } else if (activePanel === PanelView.FIAT_PAYMENT_METHOD) {
863
+ window.history.pushState({ panel: "fiat-payment-method" }, "");
864
+ }
865
+
866
+ // Listen for popstate event (browser back button)
867
+ const handlePopState = (event: PopStateEvent) => {
868
+ if (
869
+ activePanel === PanelView.RECIPIENT_SELECTION ||
870
+ activePanel === PanelView.CRYPTO_PAYMENT_METHOD ||
871
+ activePanel === PanelView.FIAT_PAYMENT_METHOD
872
+ ) {
873
+ // User pressed back while on these panels
874
+ event.preventDefault();
875
+ navigateBack();
876
+ }
877
+ };
878
+
879
+ window.addEventListener("popstate", handlePopState);
880
+
881
+ return () => {
882
+ window.removeEventListener("popstate", handlePopState);
883
+ };
884
+ }, [activePanel, navigateBack]);
885
+
833
886
  const historyView = (
834
887
  <div className={"mx-auto flex w-[560px] max-w-full flex-col items-center"}>
835
- <OrderHistory mode={mode} onBack={() => setActivePanel(PanelView.MAIN)} onSelectOrder={onSelectOrder} />
888
+ <OrderHistory mode={mode} onBack={navigateBack} onSelectOrder={onSelectOrder} />
836
889
  </div>
837
890
  );
838
891
 
@@ -851,7 +904,7 @@ function AnySpendInner({
851
904
  onPaymentMethodChange={setSelectedCryptoPaymentMethod}
852
905
  onBack={() => {
853
906
  setOrderId(undefined);
854
- setActivePanel(PanelView.MAIN);
907
+ navigateBack();
855
908
  setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.NONE); // Reset payment method when going back
856
909
  }}
857
910
  />
@@ -901,7 +954,7 @@ function AnySpendInner({
901
954
  setSrcAmount={setSrcAmount}
902
955
  setIsSrcInputDirty={setIsSrcInputDirty}
903
956
  selectedCryptoPaymentMethod={selectedCryptoPaymentMethod}
904
- onSelectCryptoPaymentMethod={() => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD)}
957
+ onSelectCryptoPaymentMethod={() => navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward")}
905
958
  anyspendQuote={anyspendQuote}
906
959
  onTokenSelect={onTokenSelect}
907
960
  />
@@ -915,7 +968,15 @@ function AnySpendInner({
915
968
  srcAmountOnRamp={srcAmountOnRamp}
916
969
  setSrcAmountOnRamp={setSrcAmountOnRamp}
917
970
  selectedPaymentMethod={selectedFiatPaymentMethod}
918
- setActivePanel={setActivePanel}
971
+ setActivePanel={(panelIndex: number) => {
972
+ // Map panel index to navigation with direction
973
+ const panelsWithForwardNav = [PanelView.FIAT_PAYMENT_METHOD, PanelView.RECIPIENT_SELECTION];
974
+ if (panelsWithForwardNav.includes(panelIndex)) {
975
+ navigateToPanel(panelIndex, "forward");
976
+ } else {
977
+ setActivePanel(panelIndex);
978
+ }
979
+ }}
919
980
  _recipientAddress={recipientAddress}
920
981
  destinationToken={selectedDstToken}
921
982
  destinationChainId={selectedDstChainId}
@@ -926,7 +987,7 @@ function AnySpendInner({
926
987
  recipientSelectionPanelIndex={PanelView.RECIPIENT_SELECTION}
927
988
  hideDstToken={isBuyMode}
928
989
  anyspendQuote={anyspendQuote}
929
- onShowPointsDetail={() => setActivePanel(PanelView.POINTS_DETAIL)}
990
+ onShowPointsDetail={() => navigateToPanel(PanelView.POINTS_DETAIL, "forward")}
930
991
  customUsdInputValues={customUsdInputValues}
931
992
  />
932
993
  </motion.div>
@@ -976,7 +1037,7 @@ function AnySpendInner({
976
1037
  isBuyMode={isBuyMode}
977
1038
  selectedRecipientAddress={recipientAddress}
978
1039
  recipientName={recipientName || undefined}
979
- onSelectRecipient={() => setActivePanel(PanelView.RECIPIENT_SELECTION)}
1040
+ onSelectRecipient={() => navigateToPanel(PanelView.RECIPIENT_SELECTION, "forward")}
980
1041
  dstAmount={dstAmount}
981
1042
  dstToken={selectedDstToken}
982
1043
  selectedDstChainId={selectedDstChainId}
@@ -987,7 +1048,7 @@ function AnySpendInner({
987
1048
  setDstAmount(value);
988
1049
  }}
989
1050
  anyspendQuote={anyspendQuote}
990
- onShowPointsDetail={() => setActivePanel(PanelView.POINTS_DETAIL)}
1051
+ onShowPointsDetail={() => navigateToPanel(PanelView.POINTS_DETAIL, "forward")}
991
1052
  />
992
1053
  )}
993
1054
  </div>
@@ -1042,7 +1103,7 @@ function AnySpendInner({
1042
1103
  globalAddress={globalAddress}
1043
1104
  onOrderCreated={orderId => {
1044
1105
  setOrderId(orderId);
1045
- setActivePanel(PanelView.ORDER_DETAILS);
1106
+ navigateToPanel(PanelView.ORDER_DETAILS, "forward");
1046
1107
  // Add orderId and payment method to URL for persistence
1047
1108
  const params = new URLSearchParams(searchParams.toString()); // Preserve existing params
1048
1109
  params.set("orderId", orderId);
@@ -1054,7 +1115,7 @@ function AnySpendInner({
1054
1115
  }
1055
1116
  router.push(`${window.location.pathname}?${params.toString()}`);
1056
1117
  }}
1057
- onBack={() => setActivePanel(PanelView.MAIN)}
1118
+ onBack={navigateBack}
1058
1119
  recipientEnsName={globalWallet?.ensName}
1059
1120
  recipientImageUrl={globalWallet?.meta?.icon}
1060
1121
  />
@@ -1063,10 +1124,10 @@ function AnySpendInner({
1063
1124
  const recipientSelectionView = (
1064
1125
  <RecipientSelection
1065
1126
  initialValue={recipientAddress || ""}
1066
- onBack={() => setActivePanel(PanelView.MAIN)}
1127
+ onBack={navigateBack}
1067
1128
  onConfirm={address => {
1068
1129
  setRecipientAddress(address);
1069
- setActivePanel(PanelView.MAIN);
1130
+ navigateBack();
1070
1131
  }}
1071
1132
  />
1072
1133
  );
@@ -1078,10 +1139,10 @@ function AnySpendInner({
1078
1139
  selectedPaymentMethod={selectedCryptoPaymentMethod}
1079
1140
  setSelectedPaymentMethod={setSelectedCryptoPaymentMethod}
1080
1141
  isCreatingOrder={isCreatingOrder}
1081
- onBack={() => setActivePanel(PanelView.MAIN)}
1142
+ onBack={navigateBack}
1082
1143
  onSelectPaymentMethod={(method: CryptoPaymentMethodType) => {
1083
1144
  setSelectedCryptoPaymentMethod(method);
1084
- setActivePanel(PanelView.MAIN);
1145
+ navigateBack();
1085
1146
  }}
1086
1147
  />
1087
1148
  );
@@ -1090,20 +1151,17 @@ function AnySpendInner({
1090
1151
  <FiatPaymentMethodComponent
1091
1152
  selectedPaymentMethod={selectedFiatPaymentMethod}
1092
1153
  setSelectedPaymentMethod={setSelectedFiatPaymentMethod}
1093
- onBack={() => setActivePanel(PanelView.MAIN)}
1154
+ onBack={navigateBack}
1094
1155
  onSelectPaymentMethod={(method: FiatPaymentMethod) => {
1095
1156
  setSelectedFiatPaymentMethod(method);
1096
- setActivePanel(PanelView.MAIN); // Go back to main panel to show updated pricing
1157
+ navigateBack(); // Go back to main panel to show updated pricing
1097
1158
  }}
1098
1159
  srcAmountOnRamp={srcAmountOnRamp}
1099
1160
  />
1100
1161
  );
1101
1162
 
1102
1163
  const pointsDetailView = (
1103
- <PointsDetailPanel
1104
- pointsAmount={anyspendQuote?.data?.pointsAmount || 0}
1105
- onBack={() => setActivePanel(PanelView.MAIN)}
1106
- />
1164
+ <PointsDetailPanel pointsAmount={anyspendQuote?.data?.pointsAmount || 0} onBack={navigateBack} />
1107
1165
  );
1108
1166
 
1109
1167
  // Add tabs to the main component when no order is loaded
@@ -1129,10 +1187,17 @@ function AnySpendInner({
1129
1187
  className={cn("rounded-2xl", {
1130
1188
  "mt-0": mode === "modal",
1131
1189
  })}
1190
+ custom={animationDirection.current}
1132
1191
  variants={{
1133
- enter: { x: 300, opacity: 0 },
1192
+ enter: direction => ({
1193
+ x: direction === "back" ? -300 : 300,
1194
+ opacity: 0,
1195
+ }),
1134
1196
  center: { x: 0, opacity: 1 },
1135
- exit: { x: -300, opacity: 0 },
1197
+ exit: direction => ({
1198
+ x: direction === "back" ? 300 : -300,
1199
+ opacity: 0,
1200
+ }),
1136
1201
  }}
1137
1202
  transition={{ type: "spring", stiffness: 300, damping: 30 }}
1138
1203
  >