@b3dotfun/sdk 0.0.28-alpha.0 → 0.0.28-alpha.1

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.
Files changed (87) hide show
  1. package/dist/cjs/anyspend/abis/escrow.d.ts +987 -0
  2. package/dist/cjs/anyspend/abis/escrow.js +1275 -0
  3. package/dist/cjs/anyspend/react/components/AnySpend.js +10 -168
  4. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +2 -2
  5. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.d.ts +10 -0
  6. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +263 -0
  7. package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.d.ts +17 -0
  8. package/dist/cjs/anyspend/react/components/common/CryptoReceiveSection.js +53 -0
  9. package/dist/cjs/anyspend/react/components/common/ErrorSection.d.ts +6 -0
  10. package/dist/cjs/anyspend/react/components/common/ErrorSection.js +12 -0
  11. package/dist/cjs/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
  12. package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +2 -2
  13. package/dist/cjs/anyspend/react/components/common/PaySection.d.ts +20 -0
  14. package/dist/cjs/anyspend/react/components/common/PaySection.js +58 -0
  15. package/dist/cjs/anyspend/react/components/common/TabSection.d.ts +10 -0
  16. package/dist/cjs/anyspend/react/components/common/TabSection.js +18 -0
  17. package/dist/cjs/anyspend/react/components/index.d.ts +2 -0
  18. package/dist/cjs/anyspend/react/components/index.js +5 -1
  19. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +165 -0
  20. package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +184 -0
  21. package/dist/cjs/anyspend/react/hooks/useSigMint.d.ts +2 -2
  22. package/dist/cjs/global-account/react/components/B3DynamicModal.js +3 -0
  23. package/dist/cjs/global-account/react/components/custom/Button.d.ts +1 -1
  24. package/dist/cjs/global-account/react/components/ui/button.d.ts +1 -1
  25. package/dist/cjs/global-account/react/components/ui/command.d.ts +2 -2
  26. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +17 -1
  27. package/dist/cjs/shared/constants/chains/b3Chain.d.ts +1 -1
  28. package/dist/cjs/shared/constants/chains/supported.d.ts +3 -3
  29. package/dist/esm/anyspend/abis/escrow.d.ts +987 -0
  30. package/dist/esm/anyspend/abis/escrow.js +1272 -0
  31. package/dist/esm/anyspend/react/components/AnySpend.js +12 -170
  32. package/dist/esm/anyspend/react/components/AnySpendCustom.js +3 -3
  33. package/dist/esm/anyspend/react/components/AnyspendDepositHype.d.ts +10 -0
  34. package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +257 -0
  35. package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.d.ts +17 -0
  36. package/dist/esm/anyspend/react/components/common/CryptoReceiveSection.js +50 -0
  37. package/dist/esm/anyspend/react/components/common/ErrorSection.d.ts +6 -0
  38. package/dist/esm/anyspend/react/components/common/ErrorSection.js +9 -0
  39. package/dist/esm/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
  40. package/dist/esm/anyspend/react/components/common/PanelOnramp.js +2 -2
  41. package/dist/esm/anyspend/react/components/common/PaySection.d.ts +20 -0
  42. package/dist/esm/anyspend/react/components/common/PaySection.js +55 -0
  43. package/dist/esm/anyspend/react/components/common/TabSection.d.ts +10 -0
  44. package/dist/esm/anyspend/react/components/common/TabSection.js +15 -0
  45. package/dist/esm/anyspend/react/components/index.d.ts +2 -0
  46. package/dist/esm/anyspend/react/components/index.js +2 -0
  47. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +165 -0
  48. package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +180 -0
  49. package/dist/esm/anyspend/react/hooks/useSigMint.d.ts +2 -2
  50. package/dist/esm/global-account/react/components/B3DynamicModal.js +3 -0
  51. package/dist/esm/global-account/react/components/custom/Button.d.ts +1 -1
  52. package/dist/esm/global-account/react/components/ui/button.d.ts +1 -1
  53. package/dist/esm/global-account/react/components/ui/command.d.ts +2 -2
  54. package/dist/esm/global-account/react/stores/useModalStore.d.ts +17 -1
  55. package/dist/esm/shared/constants/chains/b3Chain.d.ts +1 -1
  56. package/dist/esm/shared/constants/chains/supported.d.ts +3 -3
  57. package/dist/styles/index.css +1 -1
  58. package/dist/types/anyspend/abis/escrow.d.ts +987 -0
  59. package/dist/types/anyspend/react/components/AnyspendDepositHype.d.ts +10 -0
  60. package/dist/types/anyspend/react/components/common/CryptoReceiveSection.d.ts +17 -0
  61. package/dist/types/anyspend/react/components/common/ErrorSection.d.ts +6 -0
  62. package/dist/types/anyspend/react/components/common/PanelOnramp.d.ts +2 -1
  63. package/dist/types/anyspend/react/components/common/PaySection.d.ts +20 -0
  64. package/dist/types/anyspend/react/components/common/TabSection.d.ts +10 -0
  65. package/dist/types/anyspend/react/components/index.d.ts +2 -0
  66. package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +165 -0
  67. package/dist/types/anyspend/react/hooks/useSigMint.d.ts +2 -2
  68. package/dist/types/global-account/react/components/custom/Button.d.ts +1 -1
  69. package/dist/types/global-account/react/components/ui/button.d.ts +1 -1
  70. package/dist/types/global-account/react/components/ui/command.d.ts +2 -2
  71. package/dist/types/global-account/react/stores/useModalStore.d.ts +17 -1
  72. package/dist/types/shared/constants/chains/b3Chain.d.ts +1 -1
  73. package/dist/types/shared/constants/chains/supported.d.ts +3 -3
  74. package/package.json +1 -1
  75. package/src/anyspend/abis/escrow.ts +1272 -0
  76. package/src/anyspend/react/components/AnySpend.tsx +48 -389
  77. package/src/anyspend/react/components/AnySpendCustom.tsx +2 -10
  78. package/src/anyspend/react/components/AnyspendDepositHype.tsx +525 -0
  79. package/src/anyspend/react/components/common/CryptoReceiveSection.tsx +152 -0
  80. package/src/anyspend/react/components/common/ErrorSection.tsx +21 -0
  81. package/src/anyspend/react/components/common/PanelOnramp.tsx +4 -2
  82. package/src/anyspend/react/components/common/PaySection.tsx +222 -0
  83. package/src/anyspend/react/components/common/TabSection.tsx +58 -0
  84. package/src/anyspend/react/components/index.ts +2 -0
  85. package/src/anyspend/react/hooks/useAnyspendFlow.ts +226 -0
  86. package/src/global-account/react/components/B3DynamicModal.tsx +3 -0
  87. package/src/global-account/react/stores/useModalStore.ts +19 -1
@@ -20,12 +20,10 @@ import {
20
20
  useTokenData,
21
21
  useTokenFromUrl,
22
22
  } from "@b3dotfun/sdk/global-account/react";
23
- import { formatUsername } from "@b3dotfun/sdk/shared/utils";
24
23
  import { cn } from "@b3dotfun/sdk/shared/utils/cn";
25
- import { shortenAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
26
- import { formatDisplayNumber, formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number";
24
+ import { formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number";
27
25
  import invariant from "invariant";
28
- import { ArrowDown, ChevronRight, CircleAlert, HistoryIcon } from "lucide-react";
26
+ import { ArrowDown, HistoryIcon } from "lucide-react";
29
27
  import { motion } from "motion/react";
30
28
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
31
29
  import { toast } from "sonner";
@@ -34,15 +32,17 @@ import { base, mainnet } from "viem/chains";
34
32
  import { components } from "../../types/api";
35
33
  import { AnySpendFingerprintWrapper, getFingerprintConfig } from "./AnySpendFingerprintWrapper";
36
34
  import { CryptoPaymentMethod, CryptoPaymentMethodType } from "./common/CryptoPaymentMethod";
35
+ import { CryptoReceiveSection } from "./common/CryptoReceiveSection";
36
+ import { ErrorSection } from "./common/ErrorSection";
37
37
  import { FiatPaymentMethod, FiatPaymentMethodComponent } from "./common/FiatPaymentMethod";
38
38
  import { OrderDetails, OrderDetailsLoadingView } from "./common/OrderDetails";
39
39
  import { OrderHistory } from "./common/OrderHistory";
40
40
  import { OrderStatus } from "./common/OrderStatus";
41
- import { OrderTokenAmount } from "./common/OrderTokenAmount";
42
41
  import { PanelOnramp } from "./common/PanelOnramp";
43
42
  import { PanelOnrampPayment } from "./common/PanelOnrampPayment";
43
+ import { PaySection } from "./common/PaySection";
44
44
  import { RecipientSelection } from "./common/RecipientSelection";
45
- import { TokenBalance } from "./common/TokenBalance";
45
+ import { TabSection } from "./common/TabSection";
46
46
 
47
47
  export interface RecipientOption {
48
48
  address: string;
@@ -397,8 +397,7 @@ function AnySpendInner({
397
397
  // State for recipient selection
398
398
  const [recipientAddress, setRecipientAddress] = useState<string | undefined>();
399
399
 
400
- const { address: globalAddress, wallet: globalWallet, ensName: connectedName } = useAccountWallet();
401
- const connectedAddress = globalWallet?.address;
400
+ const { address: globalAddress, wallet: globalWallet } = useAccountWallet();
402
401
  const recipientProfile = useProfile({ address: recipientAddress, fresh: true });
403
402
  const recipientName = recipientProfile.data?.name;
404
403
 
@@ -480,125 +479,6 @@ function AnySpendInner({
480
479
  // Only run this effect once on mount
481
480
  }, [globalAddress, recipientAddress, customRecipients.length]);
482
481
 
483
- // Available recipient options
484
- // const recipientOptions = useMemo<RecipientOption[]>(() => {
485
- // const options: RecipientOption[] = [];
486
-
487
- // // Add current wallet if connected
488
- // if (globalAddress) {
489
- // options.push({
490
- // address: globalAddress,
491
- // icon: "https://gradvatar.com/" + globalAddress,
492
- // label: "Current Wallet",
493
- // ensName: walletName
494
- // });
495
- // }
496
-
497
- // // Add custom recipients with their onchain names
498
- // customRecipients.forEach((recipient, index) => {
499
- // options.push({
500
- // ...recipient,
501
- // ensName: customRecipientNames[index] || undefined
502
- // });
503
- // });
504
-
505
- // // Add current recipientAddress if it exists and isn't already in options
506
- // if (
507
- // recipientAddress &&
508
- // !options.some(opt => normalizeAddress(opt.address) === normalizeAddress(recipientAddress))
509
- // ) {
510
- // options.push({
511
- // address: recipientAddress,
512
- // label: `Custom (${centerTruncate(recipientAddress, 6)})`,
513
- // ensName: recipientName
514
- // });
515
- // }
516
-
517
- // return options;
518
- // }, [globalAddress, customRecipients, recipientAddress, recipientName, walletName, customRecipientNames]);
519
-
520
- // const handleCreateOrder = async (recipientAddress: string) => {
521
- // try {
522
- // invariant(anyspendPrice, "Relay price is not found");
523
- // const srcAmountBigInt = parseUnits(srcAmount.replace(/,/g, ""), selectedSrcToken.decimals);
524
-
525
- // createOrder({
526
- // recipientAddress,
527
- // orderType: "swap",
528
- // srcChain: selectedSrcChainId,
529
- // dstChain: selectedDstChainId,
530
- // srcToken: selectedSrcToken,
531
- // dstToken: selectedDstToken,
532
- // srcAmount: srcAmountBigInt.toString(),
533
- // expectedDstAmount: anyspendPrice?.data?.currencyOut?.amount || "0"
534
- // });
535
- // } catch (err) {
536
- // console.error(err);
537
- // toast.error((err as Error).message);
538
- // throw err; // Re-throw to handle in the calling function
539
- // }
540
- // };
541
-
542
- // const handleSaveRecipient = async () => {
543
- // if (!newRecipientAddress) {
544
- // toast.error("Please enter an address");
545
- // recipientInputRef.current?.focus();
546
- // return;
547
- // }
548
-
549
- // let normalizedAddress: string;
550
-
551
- // try {
552
- // // Handle ENS name
553
- // if (
554
- // newRecipientAddress.toLowerCase().endsWith(".eth") ||
555
- // newRecipientAddress.startsWith("@") ||
556
- // newRecipientAddress.includes(".b3")
557
- // ) {
558
- // if (!resolvedAddress) {
559
- // toast.error("Could not resolve ENS name");
560
- // return;
561
- // }
562
- // normalizedAddress = getAddress(resolvedAddress);
563
- // }
564
- // // Handle regular address
565
- // else {
566
- // if (!isEvmOrSolanaAddress(newRecipientAddress)) {
567
- // toast.error("Please enter a valid address or ENS name");
568
- // recipientInputRef.current?.focus();
569
- // return;
570
- // }
571
- // normalizedAddress = normalizeAddress(newRecipientAddress);
572
- // }
573
-
574
- // // Check for duplicate address
575
- // if (!customRecipients.some(r => normalizeAddress(r.address) === normalizedAddress)) {
576
- // // Add to custom recipients
577
- // const newRecipient = {
578
- // address: normalizedAddress,
579
- // label:
580
- // newRecipientAddress.toLowerCase().endsWith(".eth") ||
581
- // newRecipientAddress.startsWith("@") ||
582
- // newRecipientAddress.includes(".b3")
583
- // ? newRecipientAddress // Keep ENS name as label
584
- // : `Custom (${centerTruncate(normalizedAddress, 6)})`
585
- // };
586
- // setCustomRecipients(prev => [...prev, newRecipient]);
587
- // }
588
- // setRecipientAddress(normalizedAddress);
589
-
590
- // // Handle based on login state
591
- // if (!globalAddress) {
592
- // await handleCreateOrder(normalizedAddress);
593
- // } else {
594
- // setActivePanel(PanelView.MAIN);
595
- // }
596
- // } catch (err) {
597
- // // Error handling is done in handleCreateOrder
598
- // console.error("Error in handleSaveRecipient:", err);
599
- // }
600
- // };
601
-
602
482
  // Update dependent amount when relay price changes
603
483
  useEffect(() => {
604
484
  if (
@@ -913,35 +793,6 @@ function AnySpendInner({
913
793
  window.scrollTo({ top: 0, behavior: "smooth" });
914
794
  }, [activePanel]);
915
795
 
916
- const calculatePriceImpact = (inputUsd?: string | number, outputUsd?: string | number) => {
917
- if (!inputUsd || !outputUsd) {
918
- return { percentage: "0.00", isNegative: false };
919
- }
920
-
921
- const input = Number(inputUsd);
922
- const output = Number(outputUsd);
923
-
924
- // Handle edge cases
925
- if (input === 0 || isNaN(input) || isNaN(output) || input <= output) {
926
- return { percentage: "0.00", isNegative: false };
927
- }
928
-
929
- const percentageValue = ((output - input) / input) * 100;
930
-
931
- // Handle the -0.00% case
932
- if (percentageValue > -0.005 && percentageValue < 0) {
933
- return { percentage: "0.00", isNegative: false };
934
- }
935
-
936
- return {
937
- percentage: Math.abs(percentageValue).toFixed(2),
938
- isNegative: percentageValue < 0,
939
- };
940
- };
941
-
942
- // Add state for rate details toggle
943
- // const [showRateDetails, setShowRateDetails] = useState(false);
944
-
945
796
  const historyView = (
946
797
  <div className={"mx-auto flex w-[560px] max-w-full flex-col items-center"}>
947
798
  <OrderHistory mode={mode} onBack={() => setActivePanel(PanelView.MAIN)} onSelectOrder={onSelectOrder} />
@@ -995,121 +846,31 @@ function AnySpendInner({
995
846
  )}
996
847
 
997
848
  {/* Tab section */}
998
- <div className="w-full">
999
- <div className="bg-as-surface-secondary relative mb-4 grid h-10 grid-cols-2 rounded-xl">
1000
- <div
1001
- className={cn(
1002
- "bg-as-brand absolute bottom-0 left-0 top-0 z-0 rounded-xl transition-transform duration-100",
1003
- "h-full w-1/2",
1004
- activeTab === "fiat" ? "translate-x-full" : "translate-x-0",
1005
- )}
1006
- style={{ willChange: "transform" }}
1007
- />
1008
- <button
1009
- className={cn(
1010
- "relative z-10 h-full w-full rounded-xl px-3 text-sm font-medium transition-colors duration-100",
1011
- activeTab === "crypto" ? "text-white" : "text-as-primary/70 hover:bg-as-on-surface-2 bg-transparent",
1012
- )}
1013
- onClick={() => {
1014
- setActiveTab("crypto");
1015
- setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.NONE); // Reset payment method when switching to crypto
1016
- setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE); // Reset fiat payment method when switching to crypto
1017
- }}
1018
- >
1019
- Pay with crypto
1020
- </button>
1021
- <button
1022
- className={cn(
1023
- "relative z-10 h-full w-full rounded-xl px-3 text-sm font-medium transition-colors duration-100",
1024
- activeTab === "fiat" ? "text-white" : "text-as-primary/70 hover:bg-as-on-surface-2 bg-transparent",
1025
- )}
1026
- onClick={() => {
1027
- setActiveTab("fiat");
1028
- setSelectedCryptoPaymentMethod(CryptoPaymentMethodType.NONE); // Reset crypto payment method when switching to fiat
1029
- setSelectedFiatPaymentMethod(FiatPaymentMethod.NONE); // Reset fiat payment method when switching to fiat
1030
- }}
1031
- >
1032
- Pay with Fiat
1033
- </button>
1034
- </div>
1035
- </div>
1036
-
1037
- {/* {selectedSrcChainId === base.id || selectedDstChainId === base.id || activeTab === "fiat" ? (
1038
- <>
1039
- <Warning text="Base is experiencing temporary issues. Please check back later." />
1040
-
1041
- <div className="h-1" />
1042
- </>
1043
- ) : null} */}
849
+ <TabSection
850
+ activeTab={activeTab}
851
+ setActiveTab={setActiveTab}
852
+ setSelectedCryptoPaymentMethod={setSelectedCryptoPaymentMethod}
853
+ setSelectedFiatPaymentMethod={setSelectedFiatPaymentMethod}
854
+ />
1044
855
 
1045
856
  <div className="relative flex w-full max-w-[calc(100vw-32px)] flex-col gap-2">
1046
857
  {/* Send section */}
1047
858
  {activeTab === "crypto" ? (
1048
- <motion.div
1049
- initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
1050
- animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
1051
- transition={{ duration: 0.3, delay: 0, ease: "easeInOut" }}
1052
- className="bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6"
1053
- >
1054
- <div className="flex items-center justify-between">
1055
- <div className="text-as-primary/50 flex h-7 items-center text-sm">Pay</div>
1056
- <button
1057
- className="text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors"
1058
- onClick={() => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD)}
1059
- >
1060
- {selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (
1061
- <>
1062
- {connectedAddress ? (
1063
- <>
1064
- <div className="flex items-center gap-1">
1065
- {connectedName ? formatUsername(connectedName) : shortenAddress(connectedAddress || "")}
1066
- </div>
1067
- </>
1068
- ) : (
1069
- "Connect wallet"
1070
- )}
1071
- <ChevronRight className="h-4 w-4" />
1072
- </>
1073
- ) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (
1074
- <>
1075
- Transfer crypto
1076
- <ChevronRight className="h-4 w-4" />
1077
- </>
1078
- ) : (
1079
- <>
1080
- Select payment method
1081
- <ChevronRight className="h-4 w-4" />
1082
- </>
1083
- )}
1084
- </button>
1085
- </div>
1086
- <OrderTokenAmount
1087
- address={globalAddress}
1088
- context="from"
1089
- inputValue={srcAmount}
1090
- onChangeInput={value => {
1091
- setIsSrcInputDirty(true);
1092
- setSrcAmount(value);
1093
- }}
1094
- chainId={selectedSrcChainId}
1095
- setChainId={setSelectedSrcChainId}
1096
- token={selectedSrcToken}
1097
- setToken={setSelectedSrcToken}
1098
- />
1099
- <div className="flex items-center justify-between">
1100
- <div className="text-as-primary/50 flex h-5 items-center text-sm">
1101
- {formatDisplayNumber(anyspendQuote?.data?.currencyIn?.amountUsd, { style: "currency", fallback: "" })}
1102
- </div>
1103
- <TokenBalance
1104
- token={selectedSrcToken}
1105
- walletAddress={globalAddress}
1106
- onChangeInput={value => {
1107
- setIsSrcInputDirty(true);
1108
- setSrcAmount(value);
1109
- }}
1110
- />
1111
- </div>
1112
- </motion.div>
859
+ <PaySection
860
+ paymentType="crypto"
861
+ selectedSrcChainId={selectedSrcChainId}
862
+ setSelectedSrcChainId={setSelectedSrcChainId}
863
+ selectedSrcToken={selectedSrcToken}
864
+ setSelectedSrcToken={setSelectedSrcToken}
865
+ srcAmount={srcAmount}
866
+ setSrcAmount={setSrcAmount}
867
+ setIsSrcInputDirty={setIsSrcInputDirty}
868
+ selectedCryptoPaymentMethod={selectedCryptoPaymentMethod}
869
+ selectedFiatPaymentMethod={selectedFiatPaymentMethod}
870
+ onSelectCryptoPaymentMethod={() => setActivePanel(PanelView.CRYPTO_PAYMENT_METHOD)}
871
+ onSelectFiatPaymentMethod={() => setActivePanel(PanelView.FIAT_PAYMENT_METHOD)}
872
+ anyspendQuote={anyspendQuote}
873
+ />
1113
874
  ) : (
1114
875
  <motion.div
1115
876
  initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
@@ -1127,6 +888,7 @@ function AnySpendInner({
1127
888
  destinationAmount={dstAmount}
1128
889
  onDestinationTokenChange={setSelectedDstToken}
1129
890
  onDestinationChainChange={setSelectedDstChainId}
891
+ fiatPaymentMethodIndex={PanelView.FIAT_PAYMENT_METHOD}
1130
892
  />
1131
893
  </motion.div>
1132
894
  )}
@@ -1169,131 +931,28 @@ function AnySpendInner({
1169
931
  </Button>
1170
932
 
1171
933
  {/* Receive section - Hidden when fiat tab is active */}
1172
- {activeTab !== "fiat" && (
1173
- <motion.div
1174
- initial={{ opacity: 0, y: 20, filter: "blur(10px)" }}
1175
- animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
1176
- transition={{ duration: 0.3, delay: 0.1, ease: "easeInOut" }}
1177
- className="bg-as-surface-secondary border-as-border-secondary relative flex w-full flex-col gap-2 rounded-2xl border p-4 sm:p-6"
1178
- >
1179
- <div className="flex w-full items-center justify-between">
1180
- <div className="text-as-primary/50 flex h-7 items-center text-sm">Receive</div>
1181
- {recipientAddress ? (
1182
- <button
1183
- className={cn("text-as-tertiarry flex h-7 items-center gap-2 rounded-lg")}
1184
- onClick={() => setActivePanel(PanelView.RECIPIENT_SELECTION)}
1185
- >
1186
- <>
1187
- {recipientAddress ? (
1188
- <>
1189
- <span className="text-as-tertiarry flex items-center gap-1 text-sm">
1190
- {recipientName ? formatUsername(recipientName) : shortenAddress(recipientAddress || "")}
1191
- </span>
1192
- </>
1193
- ) : (
1194
- "Connect wallet"
1195
- )}
1196
- <ChevronRight className="h-4 w-4" />
1197
- </>
1198
- </button>
1199
- ) : (
1200
- <button
1201
- className="text-as-primary/70 flex items-center gap-1 rounded-lg"
1202
- onClick={() => setActivePanel(PanelView.RECIPIENT_SELECTION)}
1203
- >
1204
- <div className="text-sm font-medium">Select recipient</div>
1205
- </button>
1206
- )}
1207
- </div>
1208
- {isBuyMode ? (
1209
- // Fixed destination token display in buy mode
1210
- <div className="flex items-center justify-between">
1211
- <div className="text-as-primary text-2xl font-bold">{dstAmount || "0"}</div>
1212
- <div className="bg-as-brand/10 border-as-brand/30 flex items-center gap-3 rounded-xl border px-4 py-3">
1213
- {selectedDstToken.metadata?.logoURI && (
1214
- <img
1215
- src={selectedDstToken.metadata.logoURI}
1216
- alt={selectedDstToken.symbol}
1217
- className="h-8 w-8 rounded-full"
1218
- />
1219
- )}
1220
- <span className="text-as-brand text-lg font-bold">{selectedDstToken.symbol}</span>
1221
- </div>
1222
- </div>
1223
- ) : (
1224
- <OrderTokenAmount
1225
- address={recipientAddress}
1226
- context="to"
1227
- inputValue={dstAmount}
1228
- onChangeInput={value => {
1229
- setIsSrcInputDirty(false);
1230
- setDstAmount(value);
1231
- }}
1232
- chainId={selectedDstChainId}
1233
- setChainId={setSelectedDstChainId}
1234
- token={selectedDstToken}
1235
- setToken={setSelectedDstToken}
1236
- />
1237
- )}
1238
- <div className="text-as-primary/50 flex h-5 items-center text-sm">
1239
- {formatDisplayNumber(anyspendQuote?.data?.currencyOut?.amountUsd, { style: "currency", fallback: "" })}
1240
- {anyspendQuote?.data?.currencyIn?.amountUsd &&
1241
- anyspendQuote?.data?.currencyOut?.amountUsd &&
1242
- (() => {
1243
- const { percentage, isNegative } = calculatePriceImpact(
1244
- anyspendQuote.data.currencyIn.amountUsd,
1245
- anyspendQuote.data.currencyOut.amountUsd,
1246
- );
1247
-
1248
- // Parse the percentage as a number for comparison
1249
- const percentageNum = parseFloat(percentage);
1250
-
1251
- // Don't show if less than 1%
1252
- if (percentageNum < 1) {
1253
- return null;
1254
- }
1255
-
1256
- // Using inline style to ensure color displays
1257
- return (
1258
- <span className="ml-2" style={{ color: percentageNum >= 10 ? "red" : "#FFD700" }}>
1259
- ({isNegative ? "-" : ""}
1260
- {percentage}%)
1261
- </span>
1262
- );
1263
- })()}
1264
- </div>
1265
- </motion.div>
934
+ {activeTab === "crypto" && (
935
+ <CryptoReceiveSection
936
+ isDepositMode={false}
937
+ isBuyMode={isBuyMode}
938
+ selectedRecipientAddress={recipientAddress}
939
+ recipientName={recipientName || undefined}
940
+ onSelectRecipient={() => setActivePanel(PanelView.RECIPIENT_SELECTION)}
941
+ dstAmount={dstAmount}
942
+ dstToken={selectedDstToken}
943
+ selectedDstChainId={selectedDstChainId}
944
+ setSelectedDstChainId={setSelectedDstChainId}
945
+ setSelectedDstToken={setSelectedDstToken}
946
+ onChangeDstAmount={value => {
947
+ setIsSrcInputDirty(false);
948
+ setDstAmount(value);
949
+ }}
950
+ anyspendQuote={anyspendQuote}
951
+ />
1266
952
  )}
1267
953
  </div>
1268
-
1269
- {/* Order details section */}
1270
- {/* <div className="bg-as-on-surface-1 flex w-full max-w-[460px] items-center justify-between rounded-2xl p-4">
1271
- <div className="text-as-primary flex w-full items-center justify-between text-sm font-medium">
1272
- <div>
1273
- 1 {selectedSrcToken.symbol} = {anyspendPrice?.data?.rate} {selectedDstToken.symbol}
1274
- </div>
1275
- <div
1276
- className="ml-10 flex flex-1 cursor-pointer items-center justify-end"
1277
- onClick={() => setShowRateDetails(!showRateDetails)}
1278
- >
1279
- <motion.div
1280
- animate={{ rotate: showRateDetails ? 180 : 0 }}
1281
- transition={{ duration: 0.3 }}
1282
- className="w-fit"
1283
- >
1284
- <ChevronDown className="text-as-primary/70 h-5 w-5" />
1285
- </motion.div>
1286
- </div>
1287
- </div>
1288
- </div> */}
1289
-
1290
954
  {/* Error message section */}
1291
- {getAnyspendQuoteError && (
1292
- <div className="bg-as-on-surface-1 flex w-full max-w-[460px] items-center gap-2 rounded-2xl px-4 py-2">
1293
- <CircleAlert className="bg-as-red h-4 min-h-4 w-4 min-w-4 rounded-full p-0 text-sm font-medium text-white" />
1294
- <div className="text-as-red text-sm">{getAnyspendQuoteError.message}</div>
1295
- </div>
1296
- )}
955
+ <ErrorSection error={getAnyspendQuoteError} />
1297
956
 
1298
957
  {/* Main button section */}
1299
958
  <motion.div
@@ -605,16 +605,8 @@ function AnySpendCustomInner({
605
605
  onClick={() => setActivePanel(PanelView.RECIPIENT_SELECTION)}
606
606
  >
607
607
  <>
608
- {recipientProfile && (
609
- <img
610
- src={recipientProfile.data?.avatar || ""}
611
- alt={recipientProfile.data?.name || ""}
612
- className="bg-b3-react-foreground size-6 rounded-full object-cover opacity-100"
613
- />
614
- )}
615
608
  <div className="text-as-tertiarry flex items-center gap-1 text-sm">
616
- {recipientName && <span>{formatUsername(recipientName)}</span>}
617
- <span>{shortenAddress(recipientAddress)}</span>
609
+ <span>{recipientName ? formatUsername(recipientName) : shortenAddress(recipientAddress)}</span>
618
610
  </div>
619
611
  </>
620
612
  </button>
@@ -651,7 +643,7 @@ function AnySpendCustomInner({
651
643
  const orderDetailsView = (
652
644
  <div
653
645
  className={cn(
654
- "mx-auto flex w-full flex-col items-center gap-4 p-5",
646
+ "mx-auto flex w-full flex-col items-center gap-4",
655
647
  mode === "modal" && "bg-b3-react-background rounded-xl",
656
648
  )}
657
649
  >