@b3dotfun/sdk 0.0.65-test.1 → 0.0.65-test.4

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 (105) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.js +5 -3
  2. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +1 -1
  3. package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +1 -1
  4. package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +1 -1
  5. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.d.ts +0 -6
  6. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +5 -3
  7. package/dist/cjs/anyspend/react/components/common/PanelOnrampPayment.js +1 -1
  8. package/dist/cjs/anyspend/react/hooks/useSigMint.d.ts +1 -1
  9. package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +1 -0
  10. package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.js +149 -39
  11. package/dist/cjs/global-account/react/components/B3DynamicModal.js +1 -9
  12. package/dist/cjs/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.d.ts +39 -0
  13. package/dist/cjs/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +37 -0
  14. package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.js +4 -3
  15. package/dist/cjs/global-account/react/components/ManageAccount/HomeActions.js +1 -1
  16. package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +1 -1
  17. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.js +6 -3
  18. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +1 -1
  19. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.js +77 -9
  20. package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.d.ts +2 -1
  21. package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.js +2 -2
  22. package/dist/cjs/global-account/react/components/SignInWithB3/SignIn.js +3 -1
  23. package/dist/cjs/global-account/react/components/index.d.ts +1 -2
  24. package/dist/cjs/global-account/react/components/index.js +6 -8
  25. package/dist/cjs/global-account/react/components/ui/drawer.js +1 -1
  26. package/dist/cjs/global-account/react/hooks/useAccountWallet.d.ts +1 -0
  27. package/dist/cjs/global-account/react/hooks/useAccountWallet.js +18 -0
  28. package/dist/cjs/global-account/react/hooks/useAuthentication.d.ts +2 -2
  29. package/dist/cjs/global-account/react/hooks/useUserQuery.d.ts +2 -2
  30. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +1 -7
  31. package/dist/cjs/shared/constants/chains/supported.d.ts +1 -1
  32. package/dist/cjs/shared/utils/ipfs.js +10 -3
  33. package/dist/esm/anyspend/react/components/AnySpend.js +5 -3
  34. package/dist/esm/anyspend/react/components/AnySpendCustom.js +1 -1
  35. package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +1 -1
  36. package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +1 -1
  37. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.d.ts +0 -6
  38. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +5 -3
  39. package/dist/esm/anyspend/react/components/common/PanelOnrampPayment.js +1 -1
  40. package/dist/esm/anyspend/react/hooks/useSigMint.d.ts +1 -1
  41. package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +1 -0
  42. package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.js +151 -41
  43. package/dist/esm/global-account/react/components/B3DynamicModal.js +1 -9
  44. package/dist/esm/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.d.ts +39 -0
  45. package/dist/esm/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +34 -0
  46. package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.js +4 -3
  47. package/dist/esm/global-account/react/components/ManageAccount/HomeActions.js +1 -1
  48. package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +1 -1
  49. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.js +6 -3
  50. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +1 -1
  51. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.js +74 -9
  52. package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.d.ts +2 -1
  53. package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.js +2 -2
  54. package/dist/esm/global-account/react/components/SignInWithB3/SignIn.js +4 -2
  55. package/dist/esm/global-account/react/components/index.d.ts +1 -2
  56. package/dist/esm/global-account/react/components/index.js +3 -4
  57. package/dist/esm/global-account/react/components/ui/drawer.js +1 -1
  58. package/dist/esm/global-account/react/hooks/useAccountWallet.d.ts +1 -0
  59. package/dist/esm/global-account/react/hooks/useAccountWallet.js +17 -0
  60. package/dist/esm/global-account/react/hooks/useAuthentication.d.ts +2 -2
  61. package/dist/esm/global-account/react/hooks/useUserQuery.d.ts +2 -2
  62. package/dist/esm/global-account/react/stores/useModalStore.d.ts +1 -7
  63. package/dist/esm/shared/constants/chains/supported.d.ts +1 -1
  64. package/dist/esm/shared/utils/ipfs.js +10 -3
  65. package/dist/styles/index.css +1 -1
  66. package/dist/types/anyspend/react/components/common/CryptoPaymentMethod.d.ts +0 -6
  67. package/dist/types/anyspend/react/hooks/useSigMint.d.ts +1 -1
  68. package/dist/types/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +1 -0
  69. package/dist/types/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.d.ts +39 -0
  70. package/dist/types/global-account/react/components/ModalHeader/ModalHeader.d.ts +2 -1
  71. package/dist/types/global-account/react/components/index.d.ts +1 -2
  72. package/dist/types/global-account/react/hooks/useAccountWallet.d.ts +1 -0
  73. package/dist/types/global-account/react/hooks/useAuthentication.d.ts +2 -2
  74. package/dist/types/global-account/react/hooks/useUserQuery.d.ts +2 -2
  75. package/dist/types/global-account/react/stores/useModalStore.d.ts +1 -7
  76. package/dist/types/shared/constants/chains/supported.d.ts +1 -1
  77. package/package.json +2 -1
  78. package/src/anyspend/react/components/AnySpend.tsx +5 -4
  79. package/src/anyspend/react/components/AnySpendCustom.tsx +0 -2
  80. package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +0 -2
  81. package/src/anyspend/react/components/AnyspendDepositHype.tsx +0 -2
  82. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +7 -14
  83. package/src/anyspend/react/components/common/PanelOnrampPayment.tsx +1 -1
  84. package/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +251 -79
  85. package/src/global-account/react/components/B3DynamicModal.tsx +3 -11
  86. package/src/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.tsx +84 -0
  87. package/src/global-account/react/components/ManageAccount/BalanceContent.tsx +4 -7
  88. package/src/global-account/react/components/ManageAccount/HomeActions.tsx +1 -1
  89. package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +2 -2
  90. package/src/global-account/react/components/ManageAccount/ProfileSection.tsx +14 -11
  91. package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +1 -1
  92. package/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx +129 -23
  93. package/src/global-account/react/components/ModalHeader/ModalHeader.tsx +16 -8
  94. package/src/global-account/react/components/SignInWithB3/SignIn.tsx +11 -7
  95. package/src/global-account/react/components/index.ts +3 -4
  96. package/src/global-account/react/components/ui/drawer.tsx +1 -1
  97. package/src/global-account/react/hooks/useAccountWallet.tsx +26 -0
  98. package/src/global-account/react/stores/useModalStore.ts +1 -9
  99. package/src/shared/utils/ipfs.ts +10 -3
  100. package/dist/cjs/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +0 -6
  101. package/dist/cjs/global-account/react/components/ProfileEditor/ProfileEditor.js +0 -141
  102. package/dist/esm/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +0 -6
  103. package/dist/esm/global-account/react/components/ProfileEditor/ProfileEditor.js +0 -135
  104. package/dist/types/global-account/react/components/ProfileEditor/ProfileEditor.d.ts +0 -6
  105. package/src/global-account/react/components/ProfileEditor/ProfileEditor.tsx +0 -265
@@ -11,6 +11,7 @@ const anyspend_1 = require("../../../anyspend");
11
11
  const react_1 = require("../../../anyspend/react");
12
12
  const react_2 = require("../../../global-account/react");
13
13
  const BottomNavigation_1 = __importDefault(require("../../../global-account/react/components/ManageAccount/BottomNavigation"));
14
+ const useAccountWallet_1 = require("../../../global-account/react/hooks/useAccountWallet");
14
15
  const cn_1 = require("../../../shared/utils/cn");
15
16
  const number_1 = require("../../../shared/utils/number");
16
17
  const invariant_1 = __importDefault(require("invariant"));
@@ -337,6 +338,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
337
338
  const { address: globalAddress, wallet: globalWallet, connectedEOAWallet } = (0, react_2.useAccountWallet)();
338
339
  const recipientProfile = (0, react_2.useProfile)({ address: recipientAddress, fresh: true });
339
340
  const recipientName = recipientProfile.data?.name;
341
+ const globalWalletImage = (0, useAccountWallet_1.useAccountWalletImage)();
340
342
  // Auto-set active wallet from wagmi
341
343
  (0, useAutoSetActiveWalletFromWagmi_1.useAutoSetActiveWalletFromWagmi)();
342
344
  // Check token balance for crypto payments
@@ -797,7 +799,7 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
797
799
  navigateBack();
798
800
  setSelectedCryptoPaymentMethod(CryptoPaymentMethod_1.CryptoPaymentMethodType.NONE); // Reset payment method when going back
799
801
  } })) }) }));
800
- const mainView = ((0, jsx_runtime_1.jsxs)("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex w-full max-w-full flex-col items-center gap-2 px-5", 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, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward"), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect, onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward") })) : ((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) => {
802
+ const mainView = ((0, jsx_runtime_1.jsxs)("div", { className: "mx-auto flex w-[460px] max-w-full flex-col items-center gap-2 pt-5", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex w-full max-w-full flex-col items-center gap-2 px-5", 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, isSrcInputDirty: isSrcInputDirty, setIsSrcInputDirty: setIsSrcInputDirty, selectedCryptoPaymentMethod: selectedCryptoPaymentMethod, onSelectCryptoPaymentMethod: () => navigateToPanel(PanelView.CRYPTO_PAYMENT_METHOD, "forward"), anyspendQuote: anyspendQuote, onTokenSelect: onTokenSelect, onShowFeeDetail: () => navigateToPanel(PanelView.FEE_DETAIL, "forward") })) : ((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) => {
801
803
  // Map panel index to navigation with direction
802
804
  const panelsWithForwardNav = [PanelView.FIAT_PAYMENT_METHOD, PanelView.RECIPIENT_SELECTION];
803
805
  if (panelsWithForwardNav.includes(panelIndex)) {
@@ -858,12 +860,12 @@ function AnySpendInner({ destinationTokenAddress, destinationTokenChainId, mode
858
860
  params.set("paymentMethod", selectedCryptoPaymentMethod);
859
861
  }
860
862
  router.push(`${window.location.pathname}?${params.toString()}`);
861
- }, onBack: navigateBack, recipientEnsName: globalWallet?.ensName, recipientImageUrl: globalWallet?.meta?.icon }));
863
+ }, onBack: navigateBack, recipientEnsName: globalWallet?.ensName, recipientImageUrl: globalWalletImage }));
862
864
  const recipientSelectionView = ((0, jsx_runtime_1.jsx)(RecipientSelection_1.RecipientSelection, { initialValue: recipientAddress || "", onBack: navigateBack, onConfirm: address => {
863
865
  setRecipientAddress(address);
864
866
  navigateBack();
865
867
  } }));
866
- const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: globalWallet, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: navigateBack, onSelectPaymentMethod: (method) => {
868
+ const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: navigateBack, onSelectPaymentMethod: (method) => {
867
869
  setSelectedCryptoPaymentMethod(method);
868
870
  navigateBack();
869
871
  } }));
@@ -554,7 +554,7 @@ function AnySpendCustomInner({ loadOrder, mode = "modal", activeTab: activeTabPr
554
554
  setActivePanel(PanelView.CONFIRM_ORDER);
555
555
  } }) }));
556
556
  // Crypto payment method view
557
- const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: (0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { globalAddress: currentWallet?.wallet?.address, globalWallet: currentWallet?.wallet, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(PanelView.CONFIRM_ORDER), onSelectPaymentMethod: (method) => {
557
+ const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("bg-as-surface-primary mx-auto w-[460px] max-w-full rounded-xl p-4"), children: (0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(PanelView.CONFIRM_ORDER), onSelectPaymentMethod: (method) => {
558
558
  setSelectedCryptoPaymentMethod(method);
559
559
  setActivePanel(PanelView.CONFIRM_ORDER);
560
560
  } }) }));
@@ -232,7 +232,7 @@ function AnySpendCustomExactInInner({ loadOrder, mode = "modal", recipientAddres
232
232
  setSelectedRecipientAddress(address);
233
233
  setActivePanel(useAnyspendFlow_1.PanelView.MAIN);
234
234
  } }));
235
- const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: undefined, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(useAnyspendFlow_1.PanelView.MAIN), onSelectPaymentMethod: (method) => {
235
+ const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(useAnyspendFlow_1.PanelView.MAIN), onSelectPaymentMethod: (method) => {
236
236
  setSelectedCryptoPaymentMethod(method);
237
237
  setActivePanel(useAnyspendFlow_1.PanelView.MAIN);
238
238
  } }));
@@ -223,7 +223,7 @@ function AnySpendDepositHypeInner({ loadOrder, mode = "modal", recipientAddress,
223
223
  setSelectedRecipientAddress(address);
224
224
  setActivePanel(useAnyspendFlow_1.PanelView.MAIN);
225
225
  } }));
226
- const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { globalAddress: globalAddress, globalWallet: undefined, selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(useAnyspendFlow_1.PanelView.MAIN), onSelectPaymentMethod: (method) => {
226
+ const cryptoPaymentMethodView = ((0, jsx_runtime_1.jsx)(CryptoPaymentMethod_1.CryptoPaymentMethod, { selectedPaymentMethod: selectedCryptoPaymentMethod, setSelectedPaymentMethod: setSelectedCryptoPaymentMethod, isCreatingOrder: isCreatingOrder, onBack: () => setActivePanel(useAnyspendFlow_1.PanelView.MAIN), onSelectPaymentMethod: (method) => {
227
227
  setSelectedCryptoPaymentMethod(method);
228
228
  setActivePanel(useAnyspendFlow_1.PanelView.MAIN);
229
229
  } }));
@@ -5,12 +5,6 @@ export declare enum CryptoPaymentMethodType {
5
5
  TRANSFER_CRYPTO = "transfer_crypto"
6
6
  }
7
7
  interface CryptoPaymentMethodProps {
8
- globalAddress?: string;
9
- globalWallet?: {
10
- meta?: {
11
- icon?: string;
12
- };
13
- };
14
8
  selectedPaymentMethod: CryptoPaymentMethodType;
15
9
  setSelectedPaymentMethod: (method: CryptoPaymentMethodType) => void;
16
10
  isCreatingOrder: boolean;
@@ -5,6 +5,7 @@ exports.CryptoPaymentMethodType = void 0;
5
5
  exports.CryptoPaymentMethod = CryptoPaymentMethod;
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const react_1 = require("../../../../global-account/react");
8
+ const useAccountWallet_1 = require("../../../../global-account/react/hooks/useAccountWallet");
8
9
  const cn_1 = require("../../../../shared/utils/cn");
9
10
  const formatAddress_1 = require("../../../../shared/utils/formatAddress");
10
11
  const thirdweb_1 = require("../../../../shared/utils/thirdweb");
@@ -25,7 +26,7 @@ var CryptoPaymentMethodType;
25
26
  CryptoPaymentMethodType["TRANSFER_CRYPTO"] = "transfer_crypto";
26
27
  })(CryptoPaymentMethodType || (exports.CryptoPaymentMethodType = CryptoPaymentMethodType = {}));
27
28
  function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentMethod, isCreatingOrder, onBack, onSelectPaymentMethod, }) {
28
- const { wallet: globalWallet, connectedEOAWallet: connectedEOAWallet, connectedSmartWallet: connectedSmartWallet, } = (0, react_1.useAccountWallet)();
29
+ const { connectedEOAWallet: connectedEOAWallet, connectedSmartWallet: connectedSmartWallet } = (0, react_1.useAccountWallet)();
29
30
  const { connector, address } = (0, wagmi_1.useAccount)();
30
31
  const { connect, connectors, isPending } = (0, wagmi_1.useConnect)();
31
32
  const { disconnect } = (0, wagmi_1.useDisconnect)();
@@ -35,6 +36,7 @@ function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentMethod,
35
36
  const { data: eoaWalletInfo } = (0, react_4.useWalletInfo)(connectedEOAWallet?.id);
36
37
  const isConnected = !!connectedEOAWallet;
37
38
  const globalAddress = connectedSmartWallet?.getAccount()?.address;
39
+ const walletImage = (0, useAccountWallet_1.useAccountWalletImage)();
38
40
  // Use custom hook to determine wallet display logic
39
41
  const { shouldShowConnectedEOA, shouldShowWagmiWallet } = (0, useConnectedWalletDisplay_1.useConnectedWalletDisplay)(selectedPaymentMethod);
40
42
  // Map wagmi connector names to thirdweb wallet IDs
@@ -160,7 +162,7 @@ function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentMethod,
160
162
  }
161
163
  }
162
164
  };
163
- return ((0, jsx_runtime_1.jsxs)("div", { className: "crypto-payment-method mx-auto h-fit w-[460px] max-w-full px-5 pb-5", children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("relative flex flex-col gap-10"), children: [(0, jsx_runtime_1.jsx)("button", { onClick: onBack, className: "text-as-quaternary hover:text-as-primary absolute flex h-8 w-8 items-center justify-center rounded-lg transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronLeft, { className: "h-6 w-6" }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-around gap-4", children: (0, jsx_runtime_1.jsx)("div", { className: "flex-1 text-center", children: (0, jsx_runtime_1.jsx)("h2", { className: "text-as-primary text-lg font-semibold", children: "Select a payment method" }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "crypto-payment-methods flex flex-col gap-4", children: [(shouldShowConnectedEOA || shouldShowWagmiWallet || globalAddress) && ((0, jsx_runtime_1.jsxs)("div", { className: "installed-wallets", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-as-primary/80 mb-3 text-sm font-medium", children: "Connected wallets" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [shouldShowConnectedEOA && ((0, jsx_runtime_1.jsx)("button", { onClick: () => {
165
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "crypto-payment-method mx-auto h-fit w-[460px] max-w-full px-5 pb-5 pt-5 sm:px-0 sm:pt-5", children: [(0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("relative flex flex-col gap-10"), children: [(0, jsx_runtime_1.jsx)("button", { onClick: onBack, className: "text-as-quaternary hover:text-as-primary absolute flex h-8 w-8 items-center justify-center rounded-lg transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronLeft, { className: "h-6 w-6" }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-around gap-4", children: (0, jsx_runtime_1.jsx)("div", { className: "flex-1 text-center", children: (0, jsx_runtime_1.jsx)("h2", { className: "text-as-primary text-lg font-semibold", children: "Select a payment method" }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "crypto-payment-methods flex flex-col gap-4", children: [(shouldShowConnectedEOA || shouldShowWagmiWallet || globalAddress) && ((0, jsx_runtime_1.jsxs)("div", { className: "installed-wallets", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-as-primary/80 mb-3 text-sm font-medium", children: "Connected wallets" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [shouldShowConnectedEOA && ((0, jsx_runtime_1.jsx)("button", { onClick: () => {
164
166
  setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
165
167
  onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
166
168
  if (connectedEOAWallet) {
@@ -202,7 +204,7 @@ function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentMethod,
202
204
  sonner_1.toast.success("Selected B3 Account");
203
205
  }, className: (0, cn_1.cn)("crypto-payment-method-global-wallet w-full rounded-xl border p-4 text-left transition-all hover:shadow-md", selectedPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET
204
206
  ? "connected-wallet border-as-brand bg-as-brand/5"
205
- : "border-as-border-secondary bg-as-surface-primary hover:border-as-secondary/80"), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [globalWallet?.meta?.icon ? ((0, jsx_runtime_1.jsx)("img", { src: globalWallet.meta.icon, alt: "Global Account", className: "h-10 w-10 rounded-full" })) : ((0, jsx_runtime_1.jsx)("div", { className: "wallet-icon flex h-10 w-10 items-center justify-center rounded-full bg-purple-100", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Wallet, { className: "h-5 w-5 text-purple-600" }) })), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-as-primary font-semibold", children: "Global Account" }), (0, jsx_runtime_1.jsx)("span", { className: "text-as-primary/60 text-sm", children: (0, formatAddress_1.shortenAddress)(globalAddress || "") })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: selectedPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET && ((0, jsx_runtime_1.jsx)("div", { className: "h-2 w-2 rounded-full bg-green-500" })) })] }) }))] })] })), (0, jsx_runtime_1.jsxs)("div", { className: "other-payment-methods", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-as-primary/80 mb-3 text-sm font-medium", children: "Payment methods" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsxs)("button", { onClick: () => {
207
+ : "border-as-border-secondary bg-as-surface-primary hover:border-as-secondary/80"), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [walletImage ? ((0, jsx_runtime_1.jsx)("img", { src: walletImage, alt: "Global Account", className: "h-10 w-10 rounded-full" })) : ((0, jsx_runtime_1.jsx)("div", { className: "wallet-icon flex h-10 w-10 items-center justify-center rounded-full bg-purple-100", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Wallet, { className: "h-5 w-5 text-purple-600" }) })), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-as-primary font-semibold", children: "Global Account" }), (0, jsx_runtime_1.jsx)("span", { className: "text-as-primary/60 text-sm", children: (0, formatAddress_1.shortenAddress)(globalAddress || "") })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: selectedPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET && ((0, jsx_runtime_1.jsx)("div", { className: "h-2 w-2 rounded-full bg-green-500" })) })] }) }))] })] })), (0, jsx_runtime_1.jsxs)("div", { className: "other-payment-methods", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-as-primary/80 mb-3 text-sm font-medium", children: "Payment methods" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsxs)("button", { onClick: () => {
206
208
  // Always show wallet selection modal first
207
209
  setShowWalletModal(true);
208
210
  }, className: "crypto-payment-method-connect-wallet bg-as-surface-primary border-as-border-secondary hover:border-as-secondary/80 group flex w-full items-center justify-between gap-4 rounded-xl border px-4 py-3.5 transition-all duration-200 hover:shadow-md", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "wallet-icon flex h-8 w-8 items-center justify-center rounded-full bg-blue-100", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Wallet, { className: "h-4 w-4 text-blue-600" }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex flex-col items-start text-left", children: (0, jsx_runtime_1.jsx)("h4", { className: "text-as-primary font-semibold", children: "Connect wallet" }) })] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRightCircle, { className: "text-as-primary/40 group-hover:text-as-primary/60 h-5 w-5 transition-colors" })] }), (0, jsx_runtime_1.jsxs)("button", { onClick: () => {
@@ -88,7 +88,7 @@ function PanelOnrampPaymentInner(props) {
88
88
  sonner_1.toast.error("Failed to create order: " + err.message);
89
89
  }
90
90
  };
91
- return ((0, jsx_runtime_1.jsxs)("div", { className: "mx-auto flex w-full max-w-[460px] flex-col gap-6 px-5", children: [(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("h2", { className: "-mb-3 text-lg font-semibold", children: "Order summary" }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-react-background border-b3-react-border flex flex-col gap-3 rounded-lg border p-4", children: [recipientAddress && ((0, jsx_runtime_1.jsxs)(react_3.motion.div, { initial: false, animate: {
91
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "mx-auto flex w-full max-w-[460px] flex-col gap-6 px-5 pt-5", children: [(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("h2", { className: "-mb-3 text-lg font-semibold", children: "Order summary" }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-b3-react-background border-b3-react-border flex flex-col gap-3 rounded-lg border p-4", children: [recipientAddress && ((0, jsx_runtime_1.jsxs)(react_3.motion.div, { initial: false, animate: {
92
92
  opacity: 1,
93
93
  y: 0,
94
94
  filter: "blur(0px)",
@@ -48,8 +48,8 @@ export declare const useGenerateSigMintData: ({ recipientAddress, contractAddres
48
48
  creatorMap?: {} | undefined;
49
49
  chainId: number;
50
50
  address: string;
51
- title: string;
52
51
  _id: string | {};
52
+ title: string;
53
53
  };
54
54
  } | null;
55
55
  error: Error | null;
@@ -1,3 +1,4 @@
1
+ import "react-easy-crop/react-easy-crop.css";
1
2
  interface AvatarEditorProps {
2
3
  onSetAvatar?: () => void;
3
4
  className?: string;
@@ -8,12 +8,14 @@ exports.AvatarEditor = AvatarEditor;
8
8
  const jsx_runtime_1 = require("react/jsx-runtime");
9
9
  const app_1 = __importDefault(require("../../../../global-account/app"));
10
10
  const react_1 = require("../../../../global-account/react");
11
+ const profileDisplay_1 = require("../../../../global-account/react/utils/profileDisplay");
11
12
  const cn_1 = require("../../../../shared/utils/cn");
12
13
  const debug_1 = require("../../../../shared/utils/debug");
13
- const ipfs_1 = require("../../../../shared/utils/ipfs");
14
14
  const thirdweb_1 = require("../../../../shared/utils/thirdweb");
15
15
  const lucide_react_1 = require("lucide-react");
16
16
  const react_2 = require("react");
17
+ const react_easy_crop_1 = __importDefault(require("react-easy-crop"));
18
+ require("react-easy-crop/react-easy-crop.css");
17
19
  const sonner_1 = require("sonner");
18
20
  const react_3 = require("thirdweb/react");
19
21
  const storage_1 = require("thirdweb/storage");
@@ -21,19 +23,29 @@ const useProfile_1 = require("../../hooks/useProfile");
21
23
  const stores_1 = require("../../stores");
22
24
  const ModalHeader_1 = __importDefault(require("../ModalHeader/ModalHeader"));
23
25
  const debug = (0, debug_1.debugB3React)("AvatarEditor");
26
+ // Helper function to create an image element from a URL
27
+ const createImage = (url) => new Promise((resolve, reject) => {
28
+ const image = new Image();
29
+ image.addEventListener("load", () => resolve(image));
30
+ image.addEventListener("error", error => reject(error));
31
+ image.setAttribute("crossOrigin", "anonymous");
32
+ image.src = url;
33
+ });
24
34
  function AvatarEditor({ onSetAvatar, className }) {
25
35
  const [viewStep, setViewStep] = (0, react_2.useState)("select");
26
36
  const [selectedAvatar, setSelectedAvatar] = (0, react_2.useState)(null);
37
+ const [selectedProfileType, setSelectedProfileType] = (0, react_2.useState)(null); // Track which profile was selected
27
38
  const [hoveredProfile, setHoveredProfile] = (0, react_2.useState)(null);
28
39
  const [selectedFile, setSelectedFile] = (0, react_2.useState)(null);
29
40
  const [previewUrl, setPreviewUrl] = (0, react_2.useState)(null);
30
- const [isUploading, setIsUploading] = (0, react_2.useState)(false);
31
41
  const [isSaving, setIsSaving] = (0, react_2.useState)(false);
32
42
  const [isDragging, setIsDragging] = (0, react_2.useState)(false);
43
+ const [crop, setCrop] = (0, react_2.useState)({ x: 0, y: 0 });
44
+ const [zoom, setZoom] = (0, react_2.useState)(1);
45
+ const [croppedAreaPixels, setCroppedAreaPixels] = (0, react_2.useState)(null);
33
46
  const fileInputRef = (0, react_2.useRef)(null);
34
47
  const { setUser, user, partnerId } = (0, react_1.useB3)();
35
48
  const setB3ModalContentType = (0, stores_1.useModalStore)(state => state.setB3ModalContentType);
36
- const setB3ModalOpen = (0, stores_1.useModalStore)(state => state.setB3ModalOpen);
37
49
  const contentType = (0, stores_1.useModalStore)(state => state.contentType);
38
50
  const { setPreference } = (0, useProfile_1.useProfileSettings)();
39
51
  const account = (0, react_3.useActiveAccount)();
@@ -41,11 +53,36 @@ function AvatarEditor({ onSetAvatar, className }) {
41
53
  address: account?.address,
42
54
  fresh: true,
43
55
  });
44
- const currentAvatar = user?.avatar
45
- ? (0, ipfs_1.getIpfsUrl)(user?.avatar)
46
- : profile?.avatar
47
- ? (0, ipfs_1.getIpfsUrl)(profile.avatar)
48
- : undefined;
56
+ // Get raw avatar URLs, convert IPFS URLs, and validate them
57
+ const rawCurrentAvatar = user?.avatar || profile?.avatar;
58
+ const currentAvatar = (0, profileDisplay_1.validateImageUrl)(rawCurrentAvatar);
59
+ const safePreviewUrl = (0, profileDisplay_1.validateImageUrl)(previewUrl);
60
+ const onCropComplete = (0, react_2.useCallback)((_croppedArea, croppedAreaPixels) => {
61
+ setCroppedAreaPixels(croppedAreaPixels);
62
+ }, []);
63
+ const createCroppedImage = async (imageSrc, pixelCrop) => {
64
+ const image = await createImage(imageSrc);
65
+ const canvas = document.createElement("canvas");
66
+ const ctx = canvas.getContext("2d");
67
+ if (!ctx) {
68
+ throw new Error("Failed to get canvas context");
69
+ }
70
+ // Set canvas size to the crop area
71
+ canvas.width = pixelCrop.width;
72
+ canvas.height = pixelCrop.height;
73
+ // Draw the cropped image
74
+ ctx.drawImage(image, pixelCrop.x, pixelCrop.y, pixelCrop.width, pixelCrop.height, 0, 0, pixelCrop.width, pixelCrop.height);
75
+ // Return as blob
76
+ return new Promise((resolve, reject) => {
77
+ canvas.toBlob(blob => {
78
+ if (!blob) {
79
+ reject(new Error("Canvas is empty"));
80
+ return;
81
+ }
82
+ resolve(blob);
83
+ }, "image/jpeg");
84
+ });
85
+ };
49
86
  const handleFileSelect = (event) => {
50
87
  const file = event.target.files?.[0];
51
88
  if (file) {
@@ -60,6 +97,8 @@ function AvatarEditor({ onSetAvatar, className }) {
60
97
  return;
61
98
  }
62
99
  setSelectedFile(file);
100
+ // Clear profile type selection when uploading a new file
101
+ setSelectedProfileType(null);
63
102
  // Create preview URL
64
103
  const url = URL.createObjectURL(file);
65
104
  setPreviewUrl(url);
@@ -68,6 +107,7 @@ function AvatarEditor({ onSetAvatar, className }) {
68
107
  };
69
108
  const handleRemovePreview = () => {
70
109
  setSelectedAvatar(currentAvatar || null);
110
+ setSelectedProfileType(null);
71
111
  setSelectedFile(null);
72
112
  if (previewUrl) {
73
113
  URL.revokeObjectURL(previewUrl);
@@ -76,6 +116,10 @@ function AvatarEditor({ onSetAvatar, className }) {
76
116
  if (fileInputRef.current) {
77
117
  fileInputRef.current.value = "";
78
118
  }
119
+ // Reset crop state
120
+ setCrop({ x: 0, y: 0 });
121
+ setZoom(1);
122
+ setCroppedAreaPixels(null);
79
123
  };
80
124
  const handleSaveChanges = async () => {
81
125
  if (!account?.address) {
@@ -84,13 +128,65 @@ function AvatarEditor({ onSetAvatar, className }) {
84
128
  }
85
129
  setIsSaving(true);
86
130
  try {
87
- // If user uploaded a new file
88
- if (selectedFile) {
89
- debug("Starting upload to IPFS", selectedFile);
131
+ let fileToUpload = null;
132
+ // If user uploaded a new file and cropped it
133
+ if (selectedFile && previewUrl && croppedAreaPixels) {
134
+ try {
135
+ const croppedBlob = await createCroppedImage(previewUrl, croppedAreaPixels);
136
+ const extension = selectedFile.name.split(".").pop() || "jpg";
137
+ fileToUpload = new File([croppedBlob], `avatar-cropped.${extension}`, { type: "image/jpeg" });
138
+ }
139
+ catch (error) {
140
+ debug("Error cropping image:", error);
141
+ sonner_1.toast.error("Failed to crop image. Please try again.");
142
+ setIsSaving(false);
143
+ return;
144
+ }
145
+ }
146
+ else if (selectedFile) {
147
+ // Fallback if no crop was made
148
+ fileToUpload = selectedFile;
149
+ }
150
+ else if (selectedProfileType && selectedAvatar) {
151
+ // User selected from existing profile avatars
152
+ // Fetch the image from the URL and convert to blob
153
+ debug("Fetching image from social profile:", selectedAvatar);
154
+ try {
155
+ const response = await fetch(selectedAvatar);
156
+ if (!response.ok) {
157
+ throw new Error("Failed to fetch image");
158
+ }
159
+ const blob = await response.blob();
160
+ debug("Fetched blob with type:", blob.type);
161
+ // Determine the correct extension from the blob's MIME type
162
+ // This handles URLs without extensions (like Farcaster images)
163
+ const mimeToExtension = {
164
+ "image/jpeg": "jpg",
165
+ "image/jpg": "jpg",
166
+ "image/png": "png",
167
+ "image/gif": "gif",
168
+ "image/webp": "webp",
169
+ "image/svg+xml": "svg",
170
+ };
171
+ const extension = blob.type ? mimeToExtension[blob.type.toLowerCase()] || "jpg" : "jpg";
172
+ const mimeType = blob.type || `image/${extension}`;
173
+ fileToUpload = new File([blob], `avatar-${selectedProfileType}.${extension}`, { type: mimeType });
174
+ debug("Successfully converted social profile image to file with extension:", extension);
175
+ }
176
+ catch (fetchError) {
177
+ debug("Error fetching social profile image:", fetchError);
178
+ sonner_1.toast.error("Failed to fetch profile image. Please try uploading manually.");
179
+ setIsSaving(false);
180
+ return;
181
+ }
182
+ }
183
+ // Upload to IPFS if we have a file
184
+ if (fileToUpload) {
185
+ debug("Starting upload to IPFS", fileToUpload);
90
186
  // Upload to IPFS using Thirdweb
91
187
  const ipfsUrl = await (0, storage_1.upload)({
92
188
  client: thirdweb_1.client,
93
- files: [selectedFile],
189
+ files: [fileToUpload],
94
190
  });
95
191
  debug("Upload successful", ipfsUrl);
96
192
  // Save avatar URL using profiles service
@@ -104,21 +200,6 @@ function AvatarEditor({ onSetAvatar, className }) {
104
200
  setUser(user);
105
201
  sonner_1.toast.success("Looks great! Your avatar has been saved!");
106
202
  }
107
- else if (selectedAvatar && selectedAvatar !== currentAvatar) {
108
- // User selected from existing profile avatars
109
- // Find the profile that matches the selected avatar
110
- const selectedProfile = profile?.profiles?.find(p => p.avatar === selectedAvatar);
111
- if (selectedProfile && selectedProfile.type) {
112
- debug("Setting profile preference to:", selectedProfile.type);
113
- // Set preference for this profile type
114
- await setPreference(account.address, selectedProfile.type, account.address, async (message) => {
115
- // Sign the message using the active account
116
- const signature = await account.signMessage({ message });
117
- return signature;
118
- });
119
- sonner_1.toast.success("Avatar updated successfully!");
120
- }
121
- }
122
203
  // Refresh profile to get updated avatar
123
204
  await refreshProfile();
124
205
  onSetAvatar?.();
@@ -144,8 +225,15 @@ function AvatarEditor({ onSetAvatar, className }) {
144
225
  });
145
226
  }
146
227
  };
147
- const handleProfileAvatarSelect = (avatarUrl) => {
228
+ const handleProfileAvatarSelect = (avatarUrl, profileType) => {
148
229
  setSelectedAvatar(avatarUrl);
230
+ setSelectedProfileType(profileType);
231
+ // Clear any selected file since we're selecting from profile
232
+ setSelectedFile(null);
233
+ if (previewUrl) {
234
+ URL.revokeObjectURL(previewUrl);
235
+ setPreviewUrl(null);
236
+ }
149
237
  };
150
238
  const handleUploadImageClick = () => {
151
239
  setViewStep("upload");
@@ -184,6 +272,8 @@ function AvatarEditor({ onSetAvatar, className }) {
184
272
  return;
185
273
  }
186
274
  setSelectedFile(file);
275
+ // Clear profile type selection when uploading a new file
276
+ setSelectedProfileType(null);
187
277
  // Create preview URL
188
278
  const url = URL.createObjectURL(file);
189
279
  setPreviewUrl(url);
@@ -197,18 +287,38 @@ function AvatarEditor({ onSetAvatar, className }) {
197
287
  partnerId: partnerId,
198
288
  });
199
289
  };
200
- const isLoading = isUploading || isSaving;
201
- // Get profile avatars
290
+ const isLoading = isSaving;
291
+ // Get profile avatars with validated URLs
202
292
  const profileAvatars = profile?.profiles
203
293
  ?.filter(p => p.avatar)
204
- .map(p => ({
205
- type: p.type,
206
- avatar: (0, ipfs_1.getIpfsUrl)(p?.avatar || ""),
207
- name: p.name || p.type,
208
- })) || [];
209
- return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("flex w-full max-w-md flex-col bg-white", className), children: [viewStep === "upload" && (0, jsx_runtime_1.jsx)(ModalHeader_1.default, { title: "Upload Image" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center p-6", children: [viewStep === "select" ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative mb-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-32 w-32 overflow-hidden rounded-full", children: (0, jsx_runtime_1.jsx)("img", { src: selectedAvatar || currentAvatar || "https://via.placeholder.com/128", alt: "Avatar preview", className: "h-full w-full object-cover" }) }), selectedAvatar && ((0, jsx_runtime_1.jsx)("button", { onClick: handleRemovePreview, className: "absolute -right-1 -top-1 flex h-8 w-8 items-center justify-center rounded-full bg-[#51525c] text-white transition-colors hover:bg-[#71717a]", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-4 w-4" }) }))] }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleUploadImageClick, className: "font-inter shadow-xs mb-6 flex w-full items-center justify-center gap-2 rounded-xl border border-[#e4e4e7] bg-white px-4 py-3 text-sm font-semibold text-[#18181b] transition-colors hover:bg-[#f4f4f5]", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Upload, { className: "h-4 w-4" }), "Upload image"] }), (0, jsx_runtime_1.jsxs)("div", { className: "w-full", children: [(0, jsx_runtime_1.jsx)("h3", { className: "mb-2 text-base font-semibold text-[#18181b]", children: "Select your profile image" }), (0, jsx_runtime_1.jsx)("p", { className: "mb-4 text-sm font-semibold text-[#475467]", children: "Pick an avatar from your linked profiles, ENS or upload a new one." }), (0, jsx_runtime_1.jsx)("div", { className: "mb-4 flex gap-3", children: profileAvatars.map((profileAvatar, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "relative", onMouseEnter: () => setHoveredProfile(profileAvatar.type), onMouseLeave: () => setHoveredProfile(null), children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => handleProfileAvatarSelect(profileAvatar.avatar), className: (0, cn_1.cn)("h-16 w-16 overflow-hidden rounded-full border-2 transition-all", selectedAvatar === profileAvatar.avatar
210
- ? "border-[#3368ef] ring-2 ring-[#3368ef]/20"
211
- : "border-transparent hover:border-[#e4e4e7]"), children: (0, jsx_runtime_1.jsx)("img", { src: profileAvatar.avatar, alt: `${profileAvatar.type} avatar`, className: "h-full w-full object-cover" }) }), hoveredProfile === profileAvatar.type && ((0, jsx_runtime_1.jsx)("div", { className: "absolute -top-10 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md bg-[#18181b] px-3 py-1.5 text-xs text-white", children: profileAvatar.name }))] }, index))) }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleLinkMoreAccount, className: "font-inter flex items-center gap-2 text-sm font-semibold text-[#3368ef] hover:underline", children: [(0, jsx_runtime_1.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4", children: (0, jsx_runtime_1.jsx)("path", { d: "M8.75 2.75C8.75 2.33579 8.41421 2 8 2C7.58579 2 7.25 2.33579 7.25 2.75V7.25H2.75C2.33579 7.25 2 7.58579 2 8C2 8.41421 2.33579 8.75 2.75 8.75H7.25V13.25C7.25 13.6642 7.58579 14 8 14C8.41421 14 8.75 13.6642 8.75 13.25V8.75H13.25C13.6642 8.75 14 8.41421 14 8C14 7.58579 13.6642 7.25 13.25 7.25H8.75V2.75Z", fill: "currentColor" }) }), "Link more account"] })] })] })) : ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: !selectedFile ? ((0, jsx_runtime_1.jsxs)("div", { onClick: handleOpenFilePicker, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, className: (0, cn_1.cn)("mb-6 flex w-full cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-16 transition-colors", isDragging
294
+ .map(p => {
295
+ const rawAvatarUrl = p?.avatar || "";
296
+ const validatedUrl = (0, profileDisplay_1.validateImageUrl)(rawAvatarUrl);
297
+ return {
298
+ type: p.type,
299
+ avatar: validatedUrl,
300
+ name: p.name || p.type,
301
+ };
302
+ })
303
+ .filter(p => p.avatar !== null) || []; // Filter out profiles with invalid avatars
304
+ return ((0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("flex w-full max-w-md flex-col bg-white", className), children: [viewStep === "upload" && (0, jsx_runtime_1.jsx)(ModalHeader_1.default, { title: "Upload Image" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center p-6", children: [viewStep === "select" ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative mb-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-32 w-32 overflow-hidden rounded-full", children: safePreviewUrl || selectedAvatar || currentAvatar ? ((0, jsx_runtime_1.jsx)(react_1.IPFSMediaRenderer, { src: safePreviewUrl || selectedAvatar || currentAvatar || "", alt: "Avatar preview", className: "h-full w-full object-cover" })) : ((0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash h-full w-full" })) }), (selectedAvatar !== currentAvatar || selectedFile) && ((0, jsx_runtime_1.jsx)("button", { onClick: handleRemovePreview, className: "absolute -right-1 -top-1 flex h-8 w-8 items-center justify-center rounded-full bg-[#51525c] text-white transition-colors hover:bg-[#71717a]", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-4 w-4" }) }))] }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleUploadImageClick, className: "font-inter mb-6 flex w-full items-center justify-center gap-2 rounded-xl border border-[#e4e4e7] bg-white px-4 py-3 text-sm font-semibold text-[#18181b] shadow-sm transition-colors hover:bg-[#f4f4f5]", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Upload, { className: "h-4 w-4" }), "Upload image"] }), (0, jsx_runtime_1.jsxs)("div", { className: "w-full", children: [(0, jsx_runtime_1.jsx)("h3", { className: "mb-2 text-base font-semibold text-[#18181b]", children: "Select your profile image" }), (0, jsx_runtime_1.jsx)("p", { className: "mb-4 text-sm font-semibold text-[#475467]", children: "Pick an avatar from your linked profiles, ENS or upload a new one." }), (0, jsx_runtime_1.jsx)("div", { className: "mb-4 flex gap-3", children: profileAvatars.map((profileAvatar, index) => {
305
+ // Skip if avatar is null (should not happen due to filter, but TypeScript doesn't know that)
306
+ if (!profileAvatar.avatar)
307
+ return null;
308
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "relative", onMouseEnter: () => setHoveredProfile(profileAvatar.type), onMouseLeave: () => setHoveredProfile(null), children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => handleProfileAvatarSelect(profileAvatar.avatar || "", profileAvatar.type || ""), className: (0, cn_1.cn)("h-16 w-16 overflow-hidden rounded-full border-2 transition-all", selectedProfileType === profileAvatar.type
309
+ ? "border-[#3368ef] ring-2 ring-[#3368ef]/20"
310
+ : "border-transparent hover:border-[#e4e4e7]"), children: (0, jsx_runtime_1.jsx)("img", { src: profileAvatar.avatar, alt: `${profileAvatar.type} avatar`, className: "h-full w-full object-cover" }) }), hoveredProfile === profileAvatar.type && ((0, jsx_runtime_1.jsx)("div", { className: "absolute -top-10 left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md bg-[#18181b] px-3 py-1.5 text-xs text-white", children: profileAvatar.name }))] }, index));
311
+ }) }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleLinkMoreAccount, className: "font-inter flex items-center gap-2 text-sm font-semibold text-[#3368ef] hover:underline", children: [(0, jsx_runtime_1.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4", children: (0, jsx_runtime_1.jsx)("path", { d: "M8.75 2.75C8.75 2.33579 8.41421 2 8 2C7.58579 2 7.25 2.33579 7.25 2.75V7.25H2.75C2.33579 7.25 2 7.58579 2 8C2 8.41421 2.33579 8.75 2.75 8.75H7.25V13.25C7.25 13.6642 7.58579 14 8 14C8.41421 14 8.75 13.6642 8.75 13.25V8.75H13.25C13.6642 8.75 14 8.41421 14 8C14 7.58579 13.6642 7.25 13.25 7.25H8.75V2.75Z", fill: "currentColor" }) }), "Link more account"] })] })] })) : ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: !selectedFile ? ((0, jsx_runtime_1.jsxs)("div", { onClick: handleOpenFilePicker, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, className: (0, cn_1.cn)("mb-6 flex w-full cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-16 transition-colors", isDragging
212
312
  ? "border-[#3368ef] bg-[#f0f5ff]"
213
- : "border-[#e4e4e7] hover:border-[#3368ef] hover:bg-[#f0f5ff]"), children: [(0, jsx_runtime_1.jsxs)("p", { className: "font-inter mb-1 text-sm", children: [(0, jsx_runtime_1.jsx)("span", { className: "font-semibold text-[#3368ef]", children: "Click to upload" }), (0, jsx_runtime_1.jsx)("span", { className: "text-[#71717a]", children: " or drag and drop" })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-[#71717a]", children: "PNG, JPG or GIF (up to 5MB)" })] })) : ((0, jsx_runtime_1.jsx)("div", { className: "mb-6 w-full", children: (0, jsx_runtime_1.jsx)("div", { className: "aspect-square w-full overflow-hidden rounded-xl bg-[#f4f4f5]", children: (0, jsx_runtime_1.jsx)("img", { src: previewUrl || "", alt: "Preview", className: "h-full w-full object-cover" }) }) })) })), (0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, type: "file", accept: "image/*", onChange: handleFileSelect, className: "hidden" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "font-inter flex gap-3 border-t border-[#e4e4e7] p-6 font-semibold", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleCancel, variant: "outline", disabled: isLoading, className: "flex-1 rounded-xl border-[#e4e4e7] text-[#18181b] hover:bg-[#f4f4f5]", children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleSaveChanges, disabled: isLoading || !selectedAvatar, className: "flex-1 rounded-xl bg-[#3368ef] text-white hover:bg-[#2952cc]", children: isLoading ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Saving..."] })) : ("Save changes") })] })] }));
313
+ : "border-[#e4e4e7] hover:border-[#3368ef] hover:bg-[#f0f5ff]"), children: [(0, jsx_runtime_1.jsxs)("p", { className: "font-inter mb-1 text-sm", children: [(0, jsx_runtime_1.jsx)("span", { className: "font-semibold text-[#3368ef]", children: "Click to upload" }), (0, jsx_runtime_1.jsx)("span", { className: "text-[#71717a]", children: " or drag and drop" })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-[#71717a]", children: "PNG, JPG or GIF (up to 5MB)" })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "mb-6 w-full", children: [(0, jsx_runtime_1.jsx)("div", { className: "relative aspect-square w-full overflow-hidden rounded-xl bg-[#f4f4f5]", children: safePreviewUrl ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_easy_crop_1.default, { image: safePreviewUrl, crop: crop, zoom: zoom, aspect: 1, onCropChange: setCrop, onCropComplete: onCropComplete, onZoomChange: setZoom, cropShape: "rect", showGrid: false, style: {
314
+ containerStyle: {
315
+ width: "100%",
316
+ height: "100%",
317
+ backgroundColor: "#f4f4f5",
318
+ },
319
+ cropAreaStyle: {
320
+ border: "2px solid #3368ef",
321
+ borderRadius: "0px",
322
+ },
323
+ } }), (0, jsx_runtime_1.jsx)("button", { onClick: handleRemovePreview, className: "absolute right-4 top-4 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-[#51525c] text-white transition-colors hover:bg-[#71717a]", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-4 w-4" }) })] })) : ((0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash h-full w-full" })) }), safePreviewUrl && ((0, jsx_runtime_1.jsxs)("div", { className: "mt-4 flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("label", { className: "flex-shrink-0 text-sm font-semibold text-[#475467]", children: "Zoom" }), (0, jsx_runtime_1.jsx)("input", { type: "range", min: 1, max: 3, step: 0.1, value: zoom, onChange: e => setZoom(Number(e.target.value)), className: "flex-1 accent-[#3368ef]" })] }))] })) })), (0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, type: "file", accept: "image/*", onChange: handleFileSelect, className: "hidden" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "font-inter flex gap-3 border-t border-[#e4e4e7] p-6 font-semibold", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleCancel, variant: "outline", disabled: isLoading, className: "flex-1 rounded-xl border-[#e4e4e7] text-[#18181b] hover:bg-[#f4f4f5]", children: "Cancel" }), (0, jsx_runtime_1.jsx)(react_1.Button, { onClick: handleSaveChanges, disabled: isLoading || (!selectedFile && !selectedProfileType), className: "flex-1 rounded-xl bg-[#3368ef] text-white hover:bg-[#2952cc]", children: isLoading ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Saving..."] })) : ("Save changes") })] })] }));
214
324
  }
@@ -17,7 +17,6 @@ const Deposit_1 = require("./Deposit/Deposit");
17
17
  const LinkAccount_1 = require("./LinkAccount/LinkAccount");
18
18
  const LinkNewAccount_1 = require("./LinkAccount/LinkNewAccount");
19
19
  const ManageAccount_1 = require("./ManageAccount/ManageAccount");
20
- const ProfileEditor_1 = require("./ProfileEditor/ProfileEditor");
21
20
  const RequestPermissions_1 = require("./RequestPermissions/RequestPermissions");
22
21
  const Send_1 = require("./Send/Send");
23
22
  const SignInWithB3Flow_1 = require("./SignInWithB3/SignInWithB3Flow");
@@ -63,7 +62,6 @@ function B3DynamicModal() {
63
62
  "avatarEditor",
64
63
  "deposit",
65
64
  "send",
66
- "profileEditor",
67
65
  ];
68
66
  const freestyleTypes = [
69
67
  "anySpendNft",
@@ -132,8 +130,6 @@ function B3DynamicModal() {
132
130
  return (0, jsx_runtime_1.jsx)(Deposit_1.Deposit, {});
133
131
  case "send":
134
132
  return (0, jsx_runtime_1.jsx)(Send_1.Send, { ...contentType });
135
- case "profileEditor":
136
- return (0, jsx_runtime_1.jsx)(ProfileEditor_1.ProfileEditor, { onSuccess: contentType.onSuccess });
137
133
  // Add other modal types here
138
134
  default:
139
135
  return null;
@@ -147,9 +143,5 @@ function B3DynamicModal() {
147
143
  contentType?.type === "deposit" ||
148
144
  contentType?.type === "send" ||
149
145
  contentType?.type === "avatarEditor") &&
150
- "p-0", "mx-auto w-full max-w-md sm:max-w-lg", // TODO CHECK THIS
151
- // Remove default width classes for avatar editor and profile editor
152
- contentType?.type === "avatarEditor" || contentType?.type === "profileEditor"
153
- ? "!w-[90vw] !max-w-none" // Use !important to override default styles
154
- : "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, children: [(0, jsx_runtime_1.jsx)(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), (0, jsx_runtime_1.jsx)(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), (0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("no-scrollbar max-h-[90dvh] overflow-auto sm:max-h-[80dvh]"), children: [(!hideCloseButton || contentType?.showBackButton) && ((0, jsx_runtime_1.jsxs)("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [(0, jsx_runtime_1.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), (0, jsx_runtime_1.jsx)("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), renderContent()] })] }), (contentType?.type === "avatarEditor" || contentType?.type === "profileEditor") && ((0, jsx_runtime_1.jsx)("button", { onClick: () => setB3ModalOpen(false), className: "fixed right-5 top-5 z-[100] cursor-pointer text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: (0, jsx_runtime_1.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: (0, jsx_runtime_1.jsx)("path", { d: "M18 6L6 18M6 6L18 18", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }))] }));
146
+ "p-0", "mx-auto w-full max-w-md sm:max-w-lg"), hideCloseButton: hideCloseButton, children: [(0, jsx_runtime_1.jsx)(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), (0, jsx_runtime_1.jsx)(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), (0, jsx_runtime_1.jsxs)("div", { className: (0, cn_1.cn)("no-scrollbar max-h-[90dvh] overflow-auto sm:max-h-[80dvh]"), children: [!hideCloseButton && ((0, jsx_runtime_1.jsxs)("button", { onClick: navigateBack, className: "flex items-center gap-2 px-6 py-4 text-gray-600 transition-colors hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: [(0, jsx_runtime_1.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [(0, jsx_runtime_1.jsx)("path", { d: "M15.8337 10H4.16699", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M10.0003 15.8334L4.16699 10L10.0003 4.16669", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }), (0, jsx_runtime_1.jsx)("span", { className: "font-inter text-sm font-semibold", children: "Back" })] })), renderContent()] })] }), contentType?.type === "avatarEditor" && ((0, jsx_runtime_1.jsx)("button", { onClick: () => setB3ModalOpen(false), className: "fixed right-5 top-5 z-[100] cursor-pointer text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white", children: (0, jsx_runtime_1.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: (0, jsx_runtime_1.jsx)("path", { d: "M18 6L6 18M6 6L18 18", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }))] }));
155
147
  }
@@ -0,0 +1,39 @@
1
+ import type { ThirdwebClient } from "thirdweb";
2
+ interface IPFSMediaRendererProps {
3
+ /** The source URL - can be IPFS URL (ipfs://...) or HTTP URL */
4
+ src: string | null | undefined;
5
+ /** Alt text for the media */
6
+ alt?: string;
7
+ /** CSS class name */
8
+ className?: string;
9
+ /** Thirdweb client instance (optional, uses default if not provided) */
10
+ client?: ThirdwebClient;
11
+ /** Width of the media */
12
+ width?: string | number;
13
+ /** Height of the media */
14
+ height?: string | number;
15
+ /** Controls property for video/audio */
16
+ controls?: boolean;
17
+ /** Style object */
18
+ style?: React.CSSProperties;
19
+ }
20
+ /**
21
+ * IPFSMediaRenderer - A wrapper around Thirdweb's MediaRenderer that configures
22
+ * the IPFS gateway URL to use our validated gateway.
23
+ *
24
+ * Features:
25
+ * - Configures MediaRenderer to use cloudflare-ipfs.com gateway
26
+ * - Gateway matches our allowed list in profileDisplay.ts
27
+ * - Provides fallback for missing sources
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * <IPFSMediaRenderer
32
+ * src="ipfs://QmX..."
33
+ * alt="Profile Avatar"
34
+ * className="size-14 rounded-full"
35
+ * />
36
+ * ```
37
+ */
38
+ export declare function IPFSMediaRenderer({ src, alt, className, client, width, height, controls, style, }: IPFSMediaRendererProps): import("react/jsx-runtime").JSX.Element;
39
+ export {};
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ "use client";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.IPFSMediaRenderer = IPFSMediaRenderer;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const thirdweb_1 = require("../../../../shared/utils/thirdweb");
7
+ const react_1 = require("thirdweb/react");
8
+ // Primary IPFS gateway URL - matches our allowed list in profileDisplay.ts
9
+ // Note: MediaRenderer expects the base gateway URL without /ipfs path
10
+ const IPFS_GATEWAY_URL = "https://cloudflare-ipfs.com";
11
+ /**
12
+ * IPFSMediaRenderer - A wrapper around Thirdweb's MediaRenderer that configures
13
+ * the IPFS gateway URL to use our validated gateway.
14
+ *
15
+ * Features:
16
+ * - Configures MediaRenderer to use cloudflare-ipfs.com gateway
17
+ * - Gateway matches our allowed list in profileDisplay.ts
18
+ * - Provides fallback for missing sources
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <IPFSMediaRenderer
23
+ * src="ipfs://QmX..."
24
+ * alt="Profile Avatar"
25
+ * className="size-14 rounded-full"
26
+ * />
27
+ * ```
28
+ */
29
+ function IPFSMediaRenderer({ src, alt = "Media", className, client = thirdweb_1.client, width, height, controls, style, }) {
30
+ // If no source, render fallback
31
+ if (!src) {
32
+ return ((0, jsx_runtime_1.jsx)("div", { className: className, style: style, "aria-label": alt, children: (0, jsx_runtime_1.jsx)("div", { className: "bg-b3-primary-wash flex h-full w-full items-center justify-center", children: (0, jsx_runtime_1.jsx)("span", { className: "text-b3-grey font-neue-montreal-semibold text-xs", children: alt.charAt(0).toUpperCase() }) }) }));
33
+ }
34
+ // Convert IPFS URLs to HTTP gateway URLs if needed
35
+ // This handles both ipfs:// URLs and existing HTTP gateway URLs
36
+ return ((0, jsx_runtime_1.jsx)(react_1.MediaRenderer, { src: src, client: client, alt: alt, className: className, width: width ? width.toString() : undefined, height: height ? height.toString() : undefined, controls: controls, style: style }));
37
+ }