@b3dotfun/sdk 0.0.35 → 0.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/anyspend/react/components/AnySpend.js +5 -3
- package/dist/cjs/anyspend/react/components/AnyspendDepositHype.js +2 -2
- package/dist/cjs/anyspend/react/components/common/ConnectWalletPayment.d.ts +3 -1
- package/dist/cjs/anyspend/react/components/common/ConnectWalletPayment.js +5 -2
- package/dist/cjs/anyspend/react/components/common/CryptoPaySection.d.ts +16 -0
- package/dist/cjs/anyspend/react/components/common/CryptoPaySection.js +58 -0
- package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.d.ts +1 -0
- package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +22 -15
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +12 -4
- package/dist/cjs/anyspend/react/components/common/PaySection.d.ts +2 -6
- package/dist/cjs/anyspend/react/components/common/PaySection.js +10 -15
- package/dist/cjs/anyspend/react/components/index.d.ts +2 -2
- package/dist/cjs/anyspend/react/components/index.js +5 -5
- package/dist/cjs/global-account/bsmnt.d.ts +2 -0
- package/dist/cjs/global-account/bsmnt.js +42 -1
- package/dist/cjs/global-account/react/components/AvatarCreator/AvatarCreator.d.ts +6 -0
- package/dist/cjs/global-account/react/components/AvatarCreator/AvatarCreator.js +55 -0
- package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +6 -0
- package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.js +108 -0
- package/dist/cjs/global-account/react/components/B3DynamicModal.js +9 -1
- package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.d.ts +3 -1
- package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.js +21 -11
- package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.d.ts +3 -1
- package/dist/cjs/global-account/react/components/ManageAccount/BalanceContent.js +19 -5
- package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.d.ts +3 -1
- package/dist/cjs/global-account/react/components/ManageAccount/ManageAccount.js +6 -6
- package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3.js +2 -2
- package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -13
- package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Privy.js +1 -3
- package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStep.js +0 -3
- package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStepCustom.js +0 -3
- package/dist/cjs/global-account/react/components/icons/AppleIcon.d.ts +9 -0
- package/dist/cjs/global-account/react/components/icons/AppleIcon.js +8 -0
- package/dist/cjs/global-account/react/components/icons/DiscordIcon.d.ts +9 -0
- package/dist/cjs/global-account/react/components/icons/DiscordIcon.js +8 -0
- package/dist/cjs/global-account/react/components/icons/FarcasterIcon.d.ts +9 -0
- package/dist/cjs/global-account/react/components/icons/FarcasterIcon.js +8 -0
- package/dist/cjs/global-account/react/components/icons/GoogleIcon.d.ts +8 -0
- package/dist/cjs/global-account/react/components/icons/GoogleIcon.js +8 -0
- package/dist/cjs/global-account/react/components/icons/XIcon.d.ts +9 -0
- package/dist/cjs/global-account/react/components/icons/XIcon.js +8 -0
- package/dist/cjs/global-account/react/hooks/useAccountWallet.js +3 -2
- package/dist/cjs/global-account/react/hooks/useAuthentication.d.ts +1 -2
- package/dist/cjs/global-account/react/hooks/useAuthentication.js +16 -15
- package/dist/cjs/global-account/react/hooks/useProfile.d.ts +1 -1
- package/dist/cjs/global-account/react/hooks/useRPMToken.d.ts +7 -0
- package/dist/cjs/global-account/react/hooks/useRPMToken.js +11 -0
- package/dist/cjs/global-account/react/stores/useAuthStore.d.ts +2 -4
- package/dist/cjs/global-account/react/stores/useAuthStore.js +2 -4
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +11 -1
- package/dist/cjs/global-account/react/utils/updateAvatar.d.ts +4 -0
- package/dist/cjs/global-account/react/utils/updateAvatar.js +54 -0
- package/dist/esm/anyspend/react/components/AnySpend.js +5 -3
- package/dist/esm/anyspend/react/components/AnyspendDepositHype.js +2 -2
- package/dist/esm/anyspend/react/components/common/ConnectWalletPayment.d.ts +3 -1
- package/dist/esm/anyspend/react/components/common/ConnectWalletPayment.js +5 -2
- package/dist/esm/anyspend/react/components/common/CryptoPaySection.d.ts +16 -0
- package/dist/esm/anyspend/react/components/common/CryptoPaySection.js +55 -0
- package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.d.ts +1 -0
- package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +22 -15
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +12 -4
- package/dist/esm/anyspend/react/components/common/PaySection.d.ts +2 -6
- package/dist/esm/anyspend/react/components/common/PaySection.js +10 -15
- package/dist/esm/anyspend/react/components/index.d.ts +2 -2
- package/dist/esm/anyspend/react/components/index.js +2 -2
- package/dist/esm/global-account/bsmnt.d.ts +2 -0
- package/dist/esm/global-account/bsmnt.js +39 -0
- package/dist/esm/global-account/react/components/AvatarCreator/AvatarCreator.d.ts +6 -0
- package/dist/esm/global-account/react/components/AvatarCreator/AvatarCreator.js +52 -0
- package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +6 -0
- package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.js +102 -0
- package/dist/esm/global-account/react/components/B3DynamicModal.js +9 -1
- package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.d.ts +3 -1
- package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.js +22 -12
- package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.d.ts +3 -1
- package/dist/esm/global-account/react/components/ManageAccount/BalanceContent.js +20 -6
- package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.d.ts +3 -1
- package/dist/esm/global-account/react/components/ManageAccount/ManageAccount.js +6 -6
- package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3.js +2 -2
- package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -13
- package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Privy.js +1 -3
- package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStep.js +0 -3
- package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStepCustom.js +0 -3
- package/dist/esm/global-account/react/components/icons/AppleIcon.d.ts +9 -0
- package/dist/esm/global-account/react/components/icons/AppleIcon.js +5 -0
- package/dist/esm/global-account/react/components/icons/DiscordIcon.d.ts +9 -0
- package/dist/esm/global-account/react/components/icons/DiscordIcon.js +5 -0
- package/dist/esm/global-account/react/components/icons/FarcasterIcon.d.ts +9 -0
- package/dist/esm/global-account/react/components/icons/FarcasterIcon.js +5 -0
- package/dist/esm/global-account/react/components/icons/GoogleIcon.d.ts +8 -0
- package/dist/esm/global-account/react/components/icons/GoogleIcon.js +5 -0
- package/dist/esm/global-account/react/components/icons/XIcon.d.ts +9 -0
- package/dist/esm/global-account/react/components/icons/XIcon.js +5 -0
- package/dist/esm/global-account/react/hooks/useAccountWallet.js +3 -2
- package/dist/esm/global-account/react/hooks/useAuthentication.d.ts +1 -2
- package/dist/esm/global-account/react/hooks/useAuthentication.js +16 -15
- package/dist/esm/global-account/react/hooks/useProfile.d.ts +1 -1
- package/dist/esm/global-account/react/hooks/useRPMToken.d.ts +7 -0
- package/dist/esm/global-account/react/hooks/useRPMToken.js +8 -0
- package/dist/esm/global-account/react/stores/useAuthStore.d.ts +2 -4
- package/dist/esm/global-account/react/stores/useAuthStore.js +2 -4
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +11 -1
- package/dist/esm/global-account/react/utils/updateAvatar.d.ts +4 -0
- package/dist/esm/global-account/react/utils/updateAvatar.js +18 -0
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/react/components/common/ConnectWalletPayment.d.ts +3 -1
- package/dist/types/anyspend/react/components/common/CryptoPaySection.d.ts +16 -0
- package/dist/types/anyspend/react/components/common/CryptoPaymentMethod.d.ts +1 -0
- package/dist/types/anyspend/react/components/common/PaySection.d.ts +2 -6
- package/dist/types/anyspend/react/components/index.d.ts +2 -2
- package/dist/types/global-account/bsmnt.d.ts +2 -0
- package/dist/types/global-account/react/components/AvatarCreator/AvatarCreator.d.ts +6 -0
- package/dist/types/global-account/react/components/AvatarEditor/AvatarEditor.d.ts +6 -0
- package/dist/types/global-account/react/components/LinkAccount/LinkAccount.d.ts +3 -1
- package/dist/types/global-account/react/components/ManageAccount/BalanceContent.d.ts +3 -1
- package/dist/types/global-account/react/components/ManageAccount/ManageAccount.d.ts +3 -1
- package/dist/types/global-account/react/components/icons/AppleIcon.d.ts +9 -0
- package/dist/types/global-account/react/components/icons/DiscordIcon.d.ts +9 -0
- package/dist/types/global-account/react/components/icons/FarcasterIcon.d.ts +9 -0
- package/dist/types/global-account/react/components/icons/GoogleIcon.d.ts +8 -0
- package/dist/types/global-account/react/components/icons/XIcon.d.ts +9 -0
- package/dist/types/global-account/react/hooks/useAuthentication.d.ts +1 -2
- package/dist/types/global-account/react/hooks/useProfile.d.ts +1 -1
- package/dist/types/global-account/react/hooks/useRPMToken.d.ts +7 -0
- package/dist/types/global-account/react/stores/useAuthStore.d.ts +2 -4
- package/dist/types/global-account/react/stores/useModalStore.d.ts +11 -1
- package/dist/types/global-account/react/utils/updateAvatar.d.ts +4 -0
- package/package.json +8 -7
- package/src/anyspend/react/components/AnySpend.tsx +7 -6
- package/src/anyspend/react/components/AnyspendDepositHype.tsx +2 -5
- package/src/anyspend/react/components/common/ConnectWalletPayment.tsx +6 -1
- package/src/anyspend/react/components/common/CryptoPaySection.tsx +153 -0
- package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +80 -43
- package/src/anyspend/react/components/common/OrderDetails.tsx +13 -4
- package/src/anyspend/react/components/common/PaySection.tsx +64 -140
- package/src/anyspend/react/components/index.ts +2 -2
- package/src/global-account/bsmnt.ts +47 -0
- package/src/global-account/react/components/AvatarCreator/AvatarCreator.tsx +90 -0
- package/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +233 -0
- package/src/global-account/react/components/B3DynamicModal.tsx +27 -2
- package/src/global-account/react/components/LinkAccount/LinkAccount.tsx +40 -18
- package/src/global-account/react/components/ManageAccount/BalanceContent.tsx +63 -35
- package/src/global-account/react/components/ManageAccount/ManageAccount.tsx +106 -78
- package/src/global-account/react/components/SignInWithB3/SignInWithB3.tsx +2 -2
- package/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx +1 -13
- package/src/global-account/react/components/SignInWithB3/SignInWithB3Privy.tsx +1 -3
- package/src/global-account/react/components/SignInWithB3/steps/LoginStep.tsx +0 -3
- package/src/global-account/react/components/SignInWithB3/steps/LoginStepCustom.tsx +0 -3
- package/src/global-account/react/components/icons/AppleIcon.tsx +33 -0
- package/src/global-account/react/components/icons/DiscordIcon.tsx +32 -0
- package/src/global-account/react/components/icons/FarcasterIcon.tsx +37 -0
- package/src/global-account/react/components/icons/GoogleIcon.tsx +40 -0
- package/src/global-account/react/components/icons/XIcon.tsx +28 -0
- package/src/global-account/react/hooks/useAccountWallet.tsx +3 -2
- package/src/global-account/react/hooks/useAuthentication.ts +18 -15
- package/src/global-account/react/hooks/useProfile.ts +1 -1
- package/src/global-account/react/hooks/useRPMToken.ts +17 -0
- package/src/global-account/react/stores/useAuthStore.ts +4 -8
- package/src/global-account/react/stores/useModalStore.ts +13 -1
- package/src/global-account/react/utils/updateAvatar.ts +21 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useProfile, useTokenData } from "@b3dotfun/sdk/global-account/react";
|
|
2
2
|
import { formatUsername } from "@b3dotfun/sdk/shared/utils";
|
|
3
3
|
import { shortenAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
|
|
4
4
|
import { formatDisplayNumber } from "@b3dotfun/sdk/shared/utils/number";
|
|
@@ -8,12 +8,10 @@ import { useEffect, useRef } from "react";
|
|
|
8
8
|
import { useAccount } from "wagmi";
|
|
9
9
|
import { components } from "../../../types/api";
|
|
10
10
|
import { CryptoPaymentMethodType } from "./CryptoPaymentMethod";
|
|
11
|
-
import { FiatPaymentMethod } from "./FiatPaymentMethod";
|
|
12
11
|
import { OrderTokenAmount } from "./OrderTokenAmount";
|
|
13
12
|
import { TokenBalance } from "./TokenBalance";
|
|
14
13
|
|
|
15
|
-
interface
|
|
16
|
-
paymentType: "crypto" | "fiat";
|
|
14
|
+
interface CryptoPaySectionProps {
|
|
17
15
|
// Token state
|
|
18
16
|
selectedSrcChainId: number;
|
|
19
17
|
setSelectedSrcChainId: (chainId: number) => void;
|
|
@@ -24,15 +22,12 @@ interface PaySectionProps {
|
|
|
24
22
|
setIsSrcInputDirty: (dirty: boolean) => void;
|
|
25
23
|
// Payment method state
|
|
26
24
|
selectedCryptoPaymentMethod: CryptoPaymentMethodType;
|
|
27
|
-
selectedFiatPaymentMethod: FiatPaymentMethod;
|
|
28
25
|
onSelectCryptoPaymentMethod: () => void;
|
|
29
|
-
onSelectFiatPaymentMethod: () => void;
|
|
30
26
|
// Quote data
|
|
31
27
|
anyspendQuote?: any;
|
|
32
28
|
}
|
|
33
29
|
|
|
34
|
-
export function
|
|
35
|
-
paymentType,
|
|
30
|
+
export function CryptoPaySection({
|
|
36
31
|
selectedSrcChainId,
|
|
37
32
|
setSelectedSrcChainId,
|
|
38
33
|
selectedSrcToken,
|
|
@@ -41,11 +36,9 @@ export function PaySection({
|
|
|
41
36
|
setSrcAmount,
|
|
42
37
|
setIsSrcInputDirty,
|
|
43
38
|
selectedCryptoPaymentMethod,
|
|
44
|
-
selectedFiatPaymentMethod,
|
|
45
39
|
onSelectCryptoPaymentMethod,
|
|
46
|
-
onSelectFiatPaymentMethod,
|
|
47
40
|
anyspendQuote,
|
|
48
|
-
}:
|
|
41
|
+
}: CryptoPaySectionProps) {
|
|
49
42
|
const { address: connectedAddress, isConnected } = useAccount();
|
|
50
43
|
const { data: profileData } = useProfile({ address: connectedAddress });
|
|
51
44
|
const connectedName = profileData?.displayName;
|
|
@@ -88,137 +81,68 @@ export function PaySection({
|
|
|
88
81
|
>
|
|
89
82
|
<div className="flex items-center justify-between">
|
|
90
83
|
<div className="text-as-primary/50 flex h-7 items-center text-sm">Pay</div>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{connectedName ? formatUsername(connectedName) : shortenAddress(connectedAddress || "")}
|
|
101
|
-
</div>
|
|
102
|
-
) : (
|
|
103
|
-
"Connect wallet"
|
|
104
|
-
)}
|
|
105
|
-
<ChevronRight className="h-4 w-4" />
|
|
106
|
-
</>
|
|
107
|
-
) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (
|
|
108
|
-
<>
|
|
109
|
-
Transfer crypto
|
|
110
|
-
<ChevronRight className="h-4 w-4" />
|
|
111
|
-
</>
|
|
112
|
-
) : (
|
|
113
|
-
<>
|
|
114
|
-
Select payment method
|
|
115
|
-
<ChevronRight className="h-4 w-4" />
|
|
116
|
-
</>
|
|
117
|
-
)}
|
|
118
|
-
</button>
|
|
119
|
-
) : (
|
|
120
|
-
<button
|
|
121
|
-
className="text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors"
|
|
122
|
-
onClick={onSelectFiatPaymentMethod}
|
|
123
|
-
>
|
|
124
|
-
{selectedFiatPaymentMethod === FiatPaymentMethod.COINBASE_PAY ? (
|
|
125
|
-
<>
|
|
126
|
-
<div className="flex items-center gap-2">
|
|
127
|
-
<div className="flex h-5 w-5 items-center justify-center rounded-full bg-blue-600">
|
|
128
|
-
<span className="text-xs font-bold text-white">C</span>
|
|
129
|
-
</div>
|
|
130
|
-
Coinbase Pay
|
|
84
|
+
<button
|
|
85
|
+
className="text-as-tertiarry flex h-7 items-center gap-2 text-sm transition-colors focus:!outline-none"
|
|
86
|
+
onClick={onSelectCryptoPaymentMethod}
|
|
87
|
+
>
|
|
88
|
+
{selectedCryptoPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET ? (
|
|
89
|
+
<>
|
|
90
|
+
{isConnected ? (
|
|
91
|
+
<div className="flex items-center gap-1">
|
|
92
|
+
{connectedName ? formatUsername(connectedName) : shortenAddress(connectedAddress || "")}
|
|
131
93
|
</div>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
94
|
+
) : (
|
|
95
|
+
"Connect wallet"
|
|
96
|
+
)}
|
|
97
|
+
<ChevronRight className="h-4 w-4" />
|
|
98
|
+
</>
|
|
99
|
+
) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.GLOBAL_WALLET ? (
|
|
100
|
+
<>
|
|
101
|
+
Global Account
|
|
102
|
+
<ChevronRight className="h-4 w-4" />
|
|
103
|
+
</>
|
|
104
|
+
) : selectedCryptoPaymentMethod === CryptoPaymentMethodType.TRANSFER_CRYPTO ? (
|
|
105
|
+
<>
|
|
106
|
+
Transfer crypto
|
|
107
|
+
<ChevronRight className="h-4 w-4" />
|
|
108
|
+
</>
|
|
109
|
+
) : (
|
|
110
|
+
<>
|
|
111
|
+
Select payment method
|
|
112
|
+
<ChevronRight className="h-4 w-4" />
|
|
113
|
+
</>
|
|
114
|
+
)}
|
|
115
|
+
</button>
|
|
116
|
+
</div>
|
|
117
|
+
<OrderTokenAmount
|
|
118
|
+
address={connectedAddress}
|
|
119
|
+
context="from"
|
|
120
|
+
inputValue={srcAmount}
|
|
121
|
+
onChangeInput={value => {
|
|
122
|
+
setIsSrcInputDirty(true);
|
|
123
|
+
setSrcAmount(value);
|
|
124
|
+
}}
|
|
125
|
+
chainId={selectedSrcChainId}
|
|
126
|
+
setChainId={setSelectedSrcChainId}
|
|
127
|
+
token={selectedSrcToken}
|
|
128
|
+
setToken={setSelectedSrcToken}
|
|
129
|
+
/>
|
|
130
|
+
<div className="flex items-center justify-between">
|
|
131
|
+
<div className="text-as-primary/50 flex h-5 items-center text-sm">
|
|
132
|
+
{formatDisplayNumber(anyspendQuote?.data?.currencyIn?.amountUsd, {
|
|
133
|
+
style: "currency",
|
|
134
|
+
fallback: "",
|
|
135
|
+
})}
|
|
136
|
+
</div>
|
|
137
|
+
<TokenBalance
|
|
138
|
+
token={selectedSrcToken}
|
|
139
|
+
walletAddress={connectedAddress}
|
|
140
|
+
onChangeInput={value => {
|
|
141
|
+
setIsSrcInputDirty(true);
|
|
142
|
+
setSrcAmount(value);
|
|
143
|
+
}}
|
|
144
|
+
/>
|
|
152
145
|
</div>
|
|
153
|
-
{paymentType === "crypto" ? (
|
|
154
|
-
<>
|
|
155
|
-
<OrderTokenAmount
|
|
156
|
-
address={connectedAddress}
|
|
157
|
-
context="from"
|
|
158
|
-
inputValue={srcAmount}
|
|
159
|
-
onChangeInput={value => {
|
|
160
|
-
setIsSrcInputDirty(true);
|
|
161
|
-
setSrcAmount(value);
|
|
162
|
-
}}
|
|
163
|
-
chainId={selectedSrcChainId}
|
|
164
|
-
setChainId={setSelectedSrcChainId}
|
|
165
|
-
token={selectedSrcToken}
|
|
166
|
-
setToken={setSelectedSrcToken}
|
|
167
|
-
/>
|
|
168
|
-
<div className="flex items-center justify-between">
|
|
169
|
-
<div className="text-as-primary/50 flex h-5 items-center text-sm">
|
|
170
|
-
{formatDisplayNumber(anyspendQuote?.data?.currencyIn?.amountUsd, {
|
|
171
|
-
style: "currency",
|
|
172
|
-
fallback: "",
|
|
173
|
-
})}
|
|
174
|
-
</div>
|
|
175
|
-
<TokenBalance
|
|
176
|
-
token={selectedSrcToken}
|
|
177
|
-
walletAddress={connectedAddress}
|
|
178
|
-
onChangeInput={value => {
|
|
179
|
-
setIsSrcInputDirty(true);
|
|
180
|
-
setSrcAmount(value);
|
|
181
|
-
}}
|
|
182
|
-
/>
|
|
183
|
-
</div>
|
|
184
|
-
</>
|
|
185
|
-
) : (
|
|
186
|
-
<>
|
|
187
|
-
{/* Fiat amount input - styled like PanelOnramp */}
|
|
188
|
-
<div className="flex items-center justify-center pb-2 pt-8">
|
|
189
|
-
<div className="flex gap-1">
|
|
190
|
-
<span className="text-as-tertiarry text-2xl font-bold">$</span>
|
|
191
|
-
<Input
|
|
192
|
-
type="text"
|
|
193
|
-
value={srcAmount}
|
|
194
|
-
onChange={e => setSrcAmount(e.target.value.replace(/[^0-9.]/g, ""))}
|
|
195
|
-
placeholder="5"
|
|
196
|
-
className="text-as-primary placeholder:text-as-primary/50 h-auto min-w-[70px] border-0 bg-transparent p-0 px-3 pt-1 text-4xl font-bold focus-visible:ring-0 focus-visible:ring-offset-0"
|
|
197
|
-
style={{
|
|
198
|
-
width: `${Math.max(50, srcAmount.length * 34)}px`,
|
|
199
|
-
}}
|
|
200
|
-
/>
|
|
201
|
-
</div>
|
|
202
|
-
</div>
|
|
203
|
-
|
|
204
|
-
{/* Quick Amount Buttons */}
|
|
205
|
-
<div className="mx-auto mb-6 inline-grid grid-cols-4 gap-2">
|
|
206
|
-
{["5", "10", "20", "25"].map(value => (
|
|
207
|
-
<button
|
|
208
|
-
key={value}
|
|
209
|
-
onClick={() => setSrcAmount(value)}
|
|
210
|
-
className={`bg-as-surface-secondary border-as-border-secondary hover:border-as-border-secondary h-7 w-14 rounded-lg border text-sm font-medium transition-all duration-200 ${
|
|
211
|
-
srcAmount === value
|
|
212
|
-
? "border-as-border-secondary bg-as-surface-secondary"
|
|
213
|
-
: "bg-as-surface-secondary hover:bg-as-surface-secondary"
|
|
214
|
-
}`}
|
|
215
|
-
>
|
|
216
|
-
${value}
|
|
217
|
-
</button>
|
|
218
|
-
))}
|
|
219
|
-
</div>
|
|
220
|
-
</>
|
|
221
|
-
)}
|
|
222
146
|
</motion.div>
|
|
223
147
|
);
|
|
224
148
|
}
|
|
@@ -5,13 +5,14 @@ export { AnySpendBuySpin } from "./AnySpendBuySpin";
|
|
|
5
5
|
export { AnySpendCustom } from "./AnySpendCustom";
|
|
6
6
|
export * from "./AnySpendFingerprintWrapper";
|
|
7
7
|
export { AnySpendNFT } from "./AnySpendNFT";
|
|
8
|
-
export { AnyspendSignatureMint } from "./AnyspendSignatureMint";
|
|
9
8
|
export { AnySpendStakeB3 } from "./AnySpendStakeB3";
|
|
10
9
|
export { AnySpendTournament } from "./AnySpendTournament";
|
|
10
|
+
export { AnyspendSignatureMint } from "./AnyspendSignatureMint";
|
|
11
11
|
export { AnySpendNFTButton } from "./common/AnySpendNFTButton";
|
|
12
12
|
|
|
13
13
|
// Common Components
|
|
14
14
|
export { ChainTokenIcon } from "./common/ChainTokenIcon";
|
|
15
|
+
export { CryptoPaySection } from "./common/CryptoPaySection";
|
|
15
16
|
export { CryptoReceiveSection } from "./common/CryptoReceiveSection";
|
|
16
17
|
export { OrderDetails } from "./common/OrderDetails";
|
|
17
18
|
export { OrderDetailsCollapsible } from "./common/OrderDetailsCollapsible";
|
|
@@ -20,7 +21,6 @@ export { OrderHistoryItem } from "./common/OrderHistoryItem";
|
|
|
20
21
|
export { OrderStatus } from "./common/OrderStatus";
|
|
21
22
|
export { OrderToken } from "./common/OrderToken";
|
|
22
23
|
export { OrderTokenAmount } from "./common/OrderTokenAmount";
|
|
23
|
-
export { PaySection } from "./common/PaySection";
|
|
24
24
|
export { RecipientSelection } from "./common/RecipientSelection";
|
|
25
25
|
export { StepProgress } from "./common/StepProgress";
|
|
26
26
|
export { TokenBalance } from "./common/TokenBalance";
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { createClient } from "@b3dotfun/basement-api";
|
|
2
|
+
import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
|
|
2
3
|
import { AuthenticationClient } from "@feathersjs/authentication-client";
|
|
3
4
|
import socketio from "@feathersjs/socketio-client";
|
|
4
5
|
import Cookies from "js-cookie";
|
|
5
6
|
import io from "socket.io-client";
|
|
6
7
|
|
|
8
|
+
const debug = debugB3React("bsmnt");
|
|
9
|
+
|
|
7
10
|
// Also use b3 auth token since we are using b3-jwt strategy
|
|
8
11
|
const BSMNT_AUTH_COOKIE_NAME = "b3-auth";
|
|
9
12
|
|
|
@@ -70,4 +73,48 @@ export const resetSocket = () => {
|
|
|
70
73
|
// reset the socket connection
|
|
71
74
|
};
|
|
72
75
|
|
|
76
|
+
export function extractAvatarIdFromUrl(url: string): string | null {
|
|
77
|
+
const regex = /https:\/\/models\.readyplayer\.me\/([a-f0-9]{24})\.[a-zA-Z0-9]+/;
|
|
78
|
+
const match = url.match(regex);
|
|
79
|
+
return match ? match[1] : null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const authenticateWithB3JWT = async (fullToken: string, params?: Record<string, any>) => {
|
|
83
|
+
// Do not authenticate if there is no token
|
|
84
|
+
if (!fullToken) {
|
|
85
|
+
console.log("No token found, not authenticating");
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
debug("Authenticating with token:12", fullToken);
|
|
90
|
+
try {
|
|
91
|
+
const response = await app.authenticate(
|
|
92
|
+
{
|
|
93
|
+
strategy: "b3-jwt",
|
|
94
|
+
accessToken: fullToken,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
query: params || {},
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
debug("Authenticated", response);
|
|
101
|
+
|
|
102
|
+
// Store streamToken if it exists in the response
|
|
103
|
+
if (response?.streamToken) {
|
|
104
|
+
Cookies.set("stream-token", response.streamToken, {
|
|
105
|
+
expires: new Date(response.authExpires),
|
|
106
|
+
secure: process.env.NODE_ENV === "production",
|
|
107
|
+
sameSite: "strict",
|
|
108
|
+
});
|
|
109
|
+
debug("Stream token stored in cookies");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return response;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
debug(`Authentication error:5`, error);
|
|
115
|
+
debug("Authentication JWT", fullToken);
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
73
120
|
export default app;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useProfile } from "@b3dotfun/sdk/global-account/react";
|
|
4
|
+
import { useRPMToken } from "@b3dotfun/sdk/global-account/react/hooks/useRPMToken";
|
|
5
|
+
import { updateAvatar } from "@b3dotfun/sdk/global-account/react/utils/updateAvatar";
|
|
6
|
+
import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
7
|
+
import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
|
|
8
|
+
import {
|
|
9
|
+
AvatarCreatorConfig,
|
|
10
|
+
AvatarCreator as AvatarCreatorRPM,
|
|
11
|
+
AvatarExportedEvent,
|
|
12
|
+
} from "@readyplayerme/react-avatar-creator";
|
|
13
|
+
import { useState } from "react";
|
|
14
|
+
import { toast } from "sonner";
|
|
15
|
+
import { useActiveAccount } from "thirdweb/react";
|
|
16
|
+
|
|
17
|
+
const debug = debugB3React("AvatarCreator");
|
|
18
|
+
|
|
19
|
+
const config: AvatarCreatorConfig = {
|
|
20
|
+
clearCache: true,
|
|
21
|
+
bodyType: "fullbody",
|
|
22
|
+
quickStart: true,
|
|
23
|
+
language: "en",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
interface AvatarCreatorProps {
|
|
27
|
+
onSetAvatar?: () => void;
|
|
28
|
+
className?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function AvatarCreator({ onSetAvatar, className }: AvatarCreatorProps) {
|
|
32
|
+
const { token, refetch: refetchRPMToken } = useRPMToken();
|
|
33
|
+
const [loading, setIsLoading] = useState(false);
|
|
34
|
+
const account = useActiveAccount();
|
|
35
|
+
const { data: profile, refetch: refreshProfile } = useProfile({
|
|
36
|
+
address: account?.address,
|
|
37
|
+
fresh: true,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const hasAvatar = profile?.avatar;
|
|
41
|
+
|
|
42
|
+
const handleOnAvatarExported = async (event: AvatarExportedEvent) => {
|
|
43
|
+
setIsLoading(true);
|
|
44
|
+
debug("@@AvatarExportedEvent", event);
|
|
45
|
+
try {
|
|
46
|
+
const avatarUpload = await updateAvatar(event.data.url);
|
|
47
|
+
debug("@@avatarUpload", avatarUpload);
|
|
48
|
+
|
|
49
|
+
await refreshProfile();
|
|
50
|
+
toast.success(
|
|
51
|
+
hasAvatar ? "Nice look! Your avatar has been updated!" : "Looks great! Your avatar has been saved!",
|
|
52
|
+
);
|
|
53
|
+
onSetAvatar?.();
|
|
54
|
+
await refetchRPMToken(undefined);
|
|
55
|
+
} catch (e) {
|
|
56
|
+
debug("@@error:AvatarCreator", e);
|
|
57
|
+
toast.error("Failed to update avatar. Please try again.");
|
|
58
|
+
}
|
|
59
|
+
setIsLoading(false);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (loading) {
|
|
63
|
+
return (
|
|
64
|
+
<div className="flex h-[80vh] w-full flex-col items-center justify-center gap-4">
|
|
65
|
+
<div className="border-primary h-8 w-8 animate-spin rounded-full border-4 border-t-transparent" />
|
|
66
|
+
<p className="text-muted-foreground text-sm font-medium">Saving your avatar</p>
|
|
67
|
+
</div>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!token) {
|
|
72
|
+
return (
|
|
73
|
+
<div className="flex h-[80vh] w-full flex-col items-center justify-center gap-4">
|
|
74
|
+
<div className="border-primary h-8 w-8 animate-spin rounded-full border-4 border-t-transparent" />
|
|
75
|
+
<p className="text-muted-foreground text-sm font-medium">Loading avatar creator</p>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div className={cn("h-[calc(90vh-2px)] w-full", className)}>
|
|
82
|
+
<AvatarCreatorRPM
|
|
83
|
+
className="h-full w-full"
|
|
84
|
+
subdomain="b3"
|
|
85
|
+
config={{ ...config, token }}
|
|
86
|
+
onAvatarExported={handleOnAvatarExported}
|
|
87
|
+
/>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import app from "@b3dotfun/sdk/global-account/app";
|
|
4
|
+
import { Button, useB3, useProfile } from "@b3dotfun/sdk/global-account/react";
|
|
5
|
+
import { cn } from "@b3dotfun/sdk/shared/utils/cn";
|
|
6
|
+
import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
|
|
7
|
+
import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
|
|
8
|
+
import { Check, Loader2, Upload, X } from "lucide-react";
|
|
9
|
+
import { useRef, useState } from "react";
|
|
10
|
+
import { toast } from "sonner";
|
|
11
|
+
import { useActiveAccount } from "thirdweb/react";
|
|
12
|
+
import { upload } from "thirdweb/storage";
|
|
13
|
+
|
|
14
|
+
const debug = debugB3React("AvatarEditor");
|
|
15
|
+
|
|
16
|
+
interface AvatarEditorProps {
|
|
17
|
+
onSetAvatar?: () => void;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
|
|
22
|
+
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
|
23
|
+
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
|
|
24
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
25
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
26
|
+
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
27
|
+
const { setUser } = useB3();
|
|
28
|
+
|
|
29
|
+
const account = useActiveAccount();
|
|
30
|
+
const { data: profile, refetch: refreshProfile } = useProfile({
|
|
31
|
+
address: account?.address,
|
|
32
|
+
fresh: true,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Thirdweb upload function
|
|
36
|
+
|
|
37
|
+
const hasAvatar = profile?.avatar;
|
|
38
|
+
|
|
39
|
+
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
40
|
+
const file = event.target.files?.[0];
|
|
41
|
+
if (file) {
|
|
42
|
+
// Validate file type
|
|
43
|
+
if (!file.type.startsWith("image/")) {
|
|
44
|
+
toast.error("Please select an image file");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Validate file size (max 5MB)
|
|
49
|
+
if (file.size > 5 * 1024 * 1024) {
|
|
50
|
+
toast.error("File size must be less than 5MB");
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
setSelectedFile(file);
|
|
55
|
+
|
|
56
|
+
// Create preview URL
|
|
57
|
+
const url = URL.createObjectURL(file);
|
|
58
|
+
setPreviewUrl(url);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const handleRemoveFile = () => {
|
|
63
|
+
setSelectedFile(null);
|
|
64
|
+
if (previewUrl) {
|
|
65
|
+
URL.revokeObjectURL(previewUrl);
|
|
66
|
+
setPreviewUrl(null);
|
|
67
|
+
}
|
|
68
|
+
if (fileInputRef.current) {
|
|
69
|
+
fileInputRef.current.value = "";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const handleUpload = async () => {
|
|
74
|
+
if (!selectedFile) {
|
|
75
|
+
toast.error("Please select an image first");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
setIsUploading(true);
|
|
80
|
+
try {
|
|
81
|
+
debug("Starting upload to IPFS", selectedFile);
|
|
82
|
+
|
|
83
|
+
// Upload to IPFS using Thirdweb
|
|
84
|
+
const ipfsUrl = await upload({
|
|
85
|
+
client,
|
|
86
|
+
files: [selectedFile],
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
debug("Upload successful", ipfsUrl);
|
|
90
|
+
|
|
91
|
+
// Save avatar URL using profiles service
|
|
92
|
+
setIsSaving(true);
|
|
93
|
+
const user = await app.service("users").setAvatar(
|
|
94
|
+
{
|
|
95
|
+
avatar: ipfsUrl,
|
|
96
|
+
},
|
|
97
|
+
// @ts-expect-error - our typed client is expecting context even though it's set elsewhere
|
|
98
|
+
{},
|
|
99
|
+
);
|
|
100
|
+
// update user
|
|
101
|
+
// @ts-expect-error this resolved fine, look into why expect-error needed
|
|
102
|
+
setUser(user);
|
|
103
|
+
|
|
104
|
+
// Refresh profile to get updated avatar
|
|
105
|
+
await refreshProfile();
|
|
106
|
+
|
|
107
|
+
toast.success(
|
|
108
|
+
hasAvatar ? "Nice look! Your avatar has been updated!" : "Looks great! Your avatar has been saved!",
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
onSetAvatar?.();
|
|
112
|
+
|
|
113
|
+
// Clean up
|
|
114
|
+
handleRemoveFile();
|
|
115
|
+
} catch (error) {
|
|
116
|
+
debug("Error uploading avatar:", error);
|
|
117
|
+
toast.error("Failed to upload avatar. Please try again.");
|
|
118
|
+
} finally {
|
|
119
|
+
setIsUploading(false);
|
|
120
|
+
setIsSaving(false);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const handleFileInputClick = () => {
|
|
125
|
+
fileInputRef.current?.click();
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const isLoading = isUploading || isSaving;
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<div className={cn("flex flex-col items-center justify-center space-y-6 p-8", className)}>
|
|
132
|
+
<div className="space-y-2 text-center">
|
|
133
|
+
<h2 className="font-neue-montreal-semibold text-b3-grey text-2xl">
|
|
134
|
+
{hasAvatar ? "Update Your Avatar" : "Set Your Avatar"}
|
|
135
|
+
</h2>
|
|
136
|
+
<p className="text-b3-foreground-muted font-neue-montreal-medium">
|
|
137
|
+
Upload an image to personalize your profile
|
|
138
|
+
</p>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
{/* Current Avatar Display */}
|
|
142
|
+
{hasAvatar && !previewUrl && (
|
|
143
|
+
<div className="relative">
|
|
144
|
+
<div className="border-b3-primary-blue h-32 w-32 overflow-hidden rounded-full border-4">
|
|
145
|
+
<img src={profile.avatar} alt="Current avatar" className="h-full w-full object-cover" />
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
{/* File Upload Area */}
|
|
151
|
+
<div className="w-full max-w-md">
|
|
152
|
+
{!selectedFile ? (
|
|
153
|
+
<div
|
|
154
|
+
onClick={handleFileInputClick}
|
|
155
|
+
className="border-b3-line hover:border-b3-primary-blue hover:bg-b3-primary-wash/20 cursor-pointer rounded-xl border-2 border-dashed p-8 text-center transition-colors"
|
|
156
|
+
>
|
|
157
|
+
<Upload className="text-b3-grey mx-auto mb-4 h-12 w-12" />
|
|
158
|
+
<p className="text-b3-grey font-neue-montreal-semibold mb-2">Click to select an image</p>
|
|
159
|
+
<p className="text-b3-foreground-muted font-neue-montreal-medium text-sm">PNG, JPG, or GIF up to 5MB</p>
|
|
160
|
+
</div>
|
|
161
|
+
) : (
|
|
162
|
+
<div className="space-y-4">
|
|
163
|
+
{/* Preview */}
|
|
164
|
+
<div className="relative">
|
|
165
|
+
<div className="border-b3-primary-blue mx-auto h-32 w-32 overflow-hidden rounded-full border-4">
|
|
166
|
+
{previewUrl ? (
|
|
167
|
+
<img src={previewUrl} alt="Preview" className="h-full w-full object-cover" />
|
|
168
|
+
) : (
|
|
169
|
+
<div className="bg-b3-primary-wash flex h-full w-full items-center justify-center rounded-full">
|
|
170
|
+
<p className="text-b3-grey font-neue-montreal-semibold text-sm">No file selected</p>
|
|
171
|
+
</div>
|
|
172
|
+
)}
|
|
173
|
+
</div>
|
|
174
|
+
<button
|
|
175
|
+
onClick={handleRemoveFile}
|
|
176
|
+
className="bg-b3-negative absolute -right-2 -top-2 flex h-8 w-8 items-center justify-center rounded-full text-white transition-colors hover:bg-red-600"
|
|
177
|
+
disabled={isLoading}
|
|
178
|
+
>
|
|
179
|
+
<X size={16} />
|
|
180
|
+
</button>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
{/* File Info */}
|
|
184
|
+
<div className="space-y-1 text-center">
|
|
185
|
+
<p className="text-b3-grey font-neue-montreal-semibold text-sm">{selectedFile.name}</p>
|
|
186
|
+
<p className="text-b3-foreground-muted font-neue-montreal-medium text-xs">
|
|
187
|
+
{(selectedFile.size / 1024 / 1024).toFixed(2)} MB
|
|
188
|
+
</p>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
)}
|
|
192
|
+
|
|
193
|
+
{/* Hidden file input */}
|
|
194
|
+
<input ref={fileInputRef} type="file" accept="image/*" onChange={handleFileSelect} className="hidden" />
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
{/* Action Buttons */}
|
|
198
|
+
<div className="flex w-full max-w-md gap-3">
|
|
199
|
+
{selectedFile && (
|
|
200
|
+
<Button
|
|
201
|
+
onClick={handleUpload}
|
|
202
|
+
disabled={isLoading}
|
|
203
|
+
className="bg-b3-primary-blue hover:bg-b3-primary-blue/90 flex-1 text-white"
|
|
204
|
+
>
|
|
205
|
+
{isLoading ? (
|
|
206
|
+
<>
|
|
207
|
+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
208
|
+
{isUploading ? "Uploading..." : "Saving..."}
|
|
209
|
+
</>
|
|
210
|
+
) : (
|
|
211
|
+
<>
|
|
212
|
+
<Check className="mr-2 h-4 w-4" />
|
|
213
|
+
{hasAvatar ? "Update Avatar" : "Set Avatar"}
|
|
214
|
+
</>
|
|
215
|
+
)}
|
|
216
|
+
</Button>
|
|
217
|
+
)}
|
|
218
|
+
|
|
219
|
+
<Button variant="outline" onClick={handleFileInputClick} disabled={isLoading} className="flex-1">
|
|
220
|
+
<Upload className="mr-2 h-4 w-4" />
|
|
221
|
+
{selectedFile ? "Change Image" : "Select Image"}
|
|
222
|
+
</Button>
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
{/* Help Text */}
|
|
226
|
+
<div className="text-b3-foreground-muted font-neue-montreal-medium max-w-md text-center text-xs">
|
|
227
|
+
<p>
|
|
228
|
+
Your avatar will be uploaded to IPFS and stored securely. Make sure you have the rights to use this image.
|
|
229
|
+
</p>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
);
|
|
233
|
+
}
|