@b3dotfun/sdk 0.1.69-alpha.1 → 0.1.69-alpha.11

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 (161) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpendStakeB3.js +1 -1
  2. package/dist/cjs/anyspend/react/components/AnySpendStakeB3ExactIn.js +1 -1
  3. package/dist/cjs/anyspend/react/components/checkout/CheckoutPaymentPanel.js +2 -4
  4. package/dist/cjs/anyspend/react/components/checkout/CheckoutSuccess.d.ts +2 -1
  5. package/dist/cjs/anyspend/react/components/checkout/CheckoutSuccess.js +5 -3
  6. package/dist/cjs/anyspend/react/components/checkout/FiatCheckoutPanel.js +1 -2
  7. package/dist/cjs/anyspend/react/components/checkout/KycGate.js +1 -2
  8. package/dist/cjs/anyspend/react/components/common/OrderDetails.js +5 -0
  9. package/dist/cjs/anyspend/react/components/common/OrderStatus.js +37 -6
  10. package/dist/cjs/anyspend/react/components/common/StepProgress.d.ts +2 -0
  11. package/dist/cjs/anyspend/react/components/common/StepProgress.js +7 -2
  12. package/dist/cjs/anyspend/react/hooks/useAnyspendCreateOnrampOrder.js +4 -6
  13. package/dist/cjs/anyspend/react/hooks/useKycStatus.d.ts +3 -1
  14. package/dist/cjs/anyspend/react/hooks/useKycStatus.js +11 -7
  15. package/dist/cjs/app.shared.js +9 -7
  16. package/dist/cjs/global-account/bsmnt.d.ts +0 -1
  17. package/dist/cjs/global-account/bsmnt.js +0 -6
  18. package/dist/cjs/global-account/react/components/B3DynamicModal.js +5 -2
  19. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.d.ts +2 -1
  20. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.js +2 -2
  21. package/dist/cjs/global-account/react/components/B3Provider/B3Provider.native.js +2 -1
  22. package/dist/cjs/global-account/react/components/B3Provider/LocalSDKProvider.d.ts +3 -1
  23. package/dist/cjs/global-account/react/components/B3Provider/LocalSDKProvider.js +3 -1
  24. package/dist/cjs/global-account/react/components/ManageAccount/SessionDurationContent.d.ts +5 -0
  25. package/dist/cjs/global-account/react/components/ManageAccount/SessionDurationContent.js +57 -0
  26. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +12 -29
  27. package/dist/cjs/global-account/react/components/SignInWithB3/components/AuthButton.js +10 -1
  28. package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStepCustom.js +96 -15
  29. package/dist/cjs/global-account/react/components/SignInWithB3/utils/signInUtils.d.ts +5 -3
  30. package/dist/cjs/global-account/react/components/SignInWithB3/utils/signInUtils.js +15 -2
  31. package/dist/cjs/global-account/react/components/Toast/ToastContext.d.ts +3 -0
  32. package/dist/cjs/global-account/react/components/Toast/ToastContext.js +30 -7
  33. package/dist/cjs/global-account/react/hooks/useAuth.js +26 -15
  34. package/dist/cjs/global-account/react/hooks/useAuthentication.js +23 -12
  35. package/dist/cjs/global-account/react/hooks/useConnect.d.ts +2 -2
  36. package/dist/cjs/global-account/react/hooks/useFirstEOA.d.ts +8 -8
  37. package/dist/cjs/global-account/react/hooks/useTWAuth.js +0 -1
  38. package/dist/cjs/global-account/react/stores/useModalStore.d.ts +10 -1
  39. package/dist/cjs/global-account/react/utils/createWagmiConfig.d.ts +0 -18
  40. package/dist/cjs/global-account/react/utils/createWagmiConfig.js +0 -17
  41. package/dist/cjs/global-account/react/utils/index.d.ts +0 -1
  42. package/dist/cjs/global-account/react/utils/index.js +0 -1
  43. package/dist/cjs/shared/utils/session-duration.d.ts +15 -0
  44. package/dist/cjs/shared/utils/session-duration.js +69 -0
  45. package/dist/esm/anyspend/react/components/AnySpendStakeB3.js +2 -2
  46. package/dist/esm/anyspend/react/components/AnySpendStakeB3ExactIn.js +2 -2
  47. package/dist/esm/anyspend/react/components/checkout/CheckoutPaymentPanel.js +2 -4
  48. package/dist/esm/anyspend/react/components/checkout/CheckoutSuccess.d.ts +2 -1
  49. package/dist/esm/anyspend/react/components/checkout/CheckoutSuccess.js +5 -3
  50. package/dist/esm/anyspend/react/components/checkout/FiatCheckoutPanel.js +2 -3
  51. package/dist/esm/anyspend/react/components/checkout/KycGate.js +2 -3
  52. package/dist/esm/anyspend/react/components/common/OrderDetails.js +6 -1
  53. package/dist/esm/anyspend/react/components/common/OrderStatus.js +34 -3
  54. package/dist/esm/anyspend/react/components/common/StepProgress.d.ts +2 -0
  55. package/dist/esm/anyspend/react/components/common/StepProgress.js +4 -2
  56. package/dist/esm/anyspend/react/hooks/useAnyspendCreateOnrampOrder.js +5 -7
  57. package/dist/esm/anyspend/react/hooks/useKycStatus.d.ts +3 -1
  58. package/dist/esm/anyspend/react/hooks/useKycStatus.js +9 -5
  59. package/dist/esm/app.shared.js +9 -7
  60. package/dist/esm/global-account/bsmnt.d.ts +0 -1
  61. package/dist/esm/global-account/bsmnt.js +0 -5
  62. package/dist/esm/global-account/react/components/B3DynamicModal.js +5 -2
  63. package/dist/esm/global-account/react/components/B3Provider/B3Provider.d.ts +2 -1
  64. package/dist/esm/global-account/react/components/B3Provider/B3Provider.js +2 -2
  65. package/dist/esm/global-account/react/components/B3Provider/B3Provider.native.js +2 -1
  66. package/dist/esm/global-account/react/components/B3Provider/LocalSDKProvider.d.ts +3 -1
  67. package/dist/esm/global-account/react/components/B3Provider/LocalSDKProvider.js +3 -1
  68. package/dist/esm/global-account/react/components/ManageAccount/SessionDurationContent.d.ts +5 -0
  69. package/dist/esm/global-account/react/components/ManageAccount/SessionDurationContent.js +52 -0
  70. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +12 -29
  71. package/dist/esm/global-account/react/components/SignInWithB3/components/AuthButton.js +11 -2
  72. package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStepCustom.js +100 -19
  73. package/dist/esm/global-account/react/components/SignInWithB3/utils/signInUtils.d.ts +5 -3
  74. package/dist/esm/global-account/react/components/SignInWithB3/utils/signInUtils.js +14 -1
  75. package/dist/esm/global-account/react/components/Toast/ToastContext.d.ts +3 -0
  76. package/dist/esm/global-account/react/components/Toast/ToastContext.js +30 -7
  77. package/dist/esm/global-account/react/hooks/useAuth.js +28 -17
  78. package/dist/esm/global-account/react/hooks/useAuthentication.js +24 -13
  79. package/dist/esm/global-account/react/hooks/useConnect.d.ts +2 -2
  80. package/dist/esm/global-account/react/hooks/useFirstEOA.d.ts +8 -8
  81. package/dist/esm/global-account/react/hooks/useTWAuth.js +0 -1
  82. package/dist/esm/global-account/react/stores/useModalStore.d.ts +10 -1
  83. package/dist/esm/global-account/react/utils/createWagmiConfig.d.ts +0 -18
  84. package/dist/esm/global-account/react/utils/createWagmiConfig.js +0 -16
  85. package/dist/esm/global-account/react/utils/index.d.ts +0 -1
  86. package/dist/esm/global-account/react/utils/index.js +0 -1
  87. package/dist/esm/shared/utils/session-duration.d.ts +15 -0
  88. package/dist/esm/shared/utils/session-duration.js +64 -0
  89. package/dist/styles/index.css +1 -1
  90. package/dist/types/anyspend/react/components/checkout/CheckoutSuccess.d.ts +2 -1
  91. package/dist/types/anyspend/react/components/common/StepProgress.d.ts +2 -0
  92. package/dist/types/anyspend/react/hooks/useKycStatus.d.ts +3 -1
  93. package/dist/types/global-account/bsmnt.d.ts +0 -1
  94. package/dist/types/global-account/react/components/B3Provider/B3Provider.d.ts +2 -1
  95. package/dist/types/global-account/react/components/B3Provider/LocalSDKProvider.d.ts +3 -1
  96. package/dist/types/global-account/react/components/ManageAccount/SessionDurationContent.d.ts +5 -0
  97. package/dist/types/global-account/react/components/SignInWithB3/utils/signInUtils.d.ts +5 -3
  98. package/dist/types/global-account/react/components/Toast/ToastContext.d.ts +3 -0
  99. package/dist/types/global-account/react/hooks/useConnect.d.ts +2 -2
  100. package/dist/types/global-account/react/hooks/useFirstEOA.d.ts +8 -8
  101. package/dist/types/global-account/react/stores/useModalStore.d.ts +10 -1
  102. package/dist/types/global-account/react/utils/createWagmiConfig.d.ts +0 -18
  103. package/dist/types/global-account/react/utils/index.d.ts +0 -1
  104. package/dist/types/shared/utils/session-duration.d.ts +15 -0
  105. package/package.json +2 -6
  106. package/src/anyspend/react/components/AnySpendStakeB3.tsx +2 -2
  107. package/src/anyspend/react/components/AnySpendStakeB3ExactIn.tsx +2 -2
  108. package/src/anyspend/react/components/checkout/CheckoutPaymentPanel.tsx +2 -4
  109. package/src/anyspend/react/components/checkout/CheckoutSuccess.tsx +13 -3
  110. package/src/anyspend/react/components/checkout/FiatCheckoutPanel.tsx +9 -3
  111. package/src/anyspend/react/components/checkout/KycGate.tsx +8 -3
  112. package/src/anyspend/react/components/common/OrderDetails.tsx +8 -0
  113. package/src/anyspend/react/components/common/OrderStatus.tsx +38 -3
  114. package/src/anyspend/react/components/common/StepProgress.tsx +15 -5
  115. package/src/anyspend/react/hooks/useAnyspendCreateOnrampOrder.ts +5 -7
  116. package/src/anyspend/react/hooks/useKycStatus.ts +8 -5
  117. package/src/app.shared.ts +9 -8
  118. package/src/global-account/bsmnt.ts +0 -6
  119. package/src/global-account/react/components/B3DynamicModal.tsx +5 -2
  120. package/src/global-account/react/components/B3Provider/B3Provider.native.tsx +2 -1
  121. package/src/global-account/react/components/B3Provider/B3Provider.tsx +7 -1
  122. package/src/global-account/react/components/B3Provider/LocalSDKProvider.tsx +5 -0
  123. package/src/global-account/react/components/ManageAccount/SessionDurationContent.tsx +107 -0
  124. package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +28 -30
  125. package/src/global-account/react/components/SignInWithB3/components/AuthButton.tsx +21 -2
  126. package/src/global-account/react/components/SignInWithB3/steps/LoginStepCustom.tsx +207 -54
  127. package/src/global-account/react/components/SignInWithB3/utils/signInUtils.ts +19 -3
  128. package/src/global-account/react/components/Toast/ToastContext.tsx +39 -7
  129. package/src/global-account/react/hooks/useAuth.ts +28 -17
  130. package/src/global-account/react/hooks/useAuthentication.ts +24 -13
  131. package/src/global-account/react/hooks/useConnect.tsx +2 -2
  132. package/src/global-account/react/hooks/useTWAuth.tsx +0 -1
  133. package/src/global-account/react/stores/useModalStore.ts +11 -0
  134. package/src/global-account/react/utils/createWagmiConfig.tsx +0 -18
  135. package/src/global-account/react/utils/index.ts +0 -1
  136. package/src/shared/utils/session-duration.ts +64 -0
  137. package/src/types/torph.d.ts +4 -0
  138. package/dist/cjs/global-account/react/components/AvatarCreator/AvatarCreator.d.ts +0 -6
  139. package/dist/cjs/global-account/react/components/AvatarCreator/AvatarCreator.js +0 -54
  140. package/dist/cjs/global-account/react/components/ProfileAvatar.d.ts +0 -0
  141. package/dist/cjs/global-account/react/components/ProfileAvatar.js +0 -127
  142. package/dist/cjs/global-account/react/hooks/useRPMToken.d.ts +0 -7
  143. package/dist/cjs/global-account/react/hooks/useRPMToken.js +0 -11
  144. package/dist/cjs/global-account/react/utils/updateAvatar.d.ts +0 -4
  145. package/dist/cjs/global-account/react/utils/updateAvatar.js +0 -54
  146. package/dist/esm/global-account/react/components/AvatarCreator/AvatarCreator.d.ts +0 -6
  147. package/dist/esm/global-account/react/components/AvatarCreator/AvatarCreator.js +0 -51
  148. package/dist/esm/global-account/react/components/ProfileAvatar.d.ts +0 -0
  149. package/dist/esm/global-account/react/components/ProfileAvatar.js +0 -127
  150. package/dist/esm/global-account/react/hooks/useRPMToken.d.ts +0 -7
  151. package/dist/esm/global-account/react/hooks/useRPMToken.js +0 -8
  152. package/dist/esm/global-account/react/utils/updateAvatar.d.ts +0 -4
  153. package/dist/esm/global-account/react/utils/updateAvatar.js +0 -18
  154. package/dist/types/global-account/react/components/AvatarCreator/AvatarCreator.d.ts +0 -6
  155. package/dist/types/global-account/react/components/ProfileAvatar.d.ts +0 -0
  156. package/dist/types/global-account/react/hooks/useRPMToken.d.ts +0 -7
  157. package/dist/types/global-account/react/utils/updateAvatar.d.ts +0 -4
  158. package/src/global-account/react/components/AvatarCreator/AvatarCreator.tsx +0 -90
  159. package/src/global-account/react/components/ProfileAvatar.tsx +0 -138
  160. package/src/global-account/react/hooks/useRPMToken.ts +0 -17
  161. package/src/global-account/react/utils/updateAvatar.ts +0 -21
@@ -3,6 +3,7 @@ import {
3
3
  AuthButton,
4
4
  Button,
5
5
  getConnectOptionsFromStrategy,
6
+ Input,
6
7
  isWalletType,
7
8
  LoginStepContainer,
8
9
  useAuthentication,
@@ -11,12 +12,21 @@ import {
11
12
  useConnect,
12
13
  WalletRow,
13
14
  } from "@b3dotfun/sdk/global-account/react";
15
+ import { ecosystemWalletId } from "@b3dotfun/sdk/shared/constants";
14
16
  import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
15
17
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
16
18
  import { useState } from "react";
17
19
  import { Chain } from "thirdweb";
18
- import { useConnect as useConnectTW } from "thirdweb/react";
19
- import { Account, createWallet, Wallet, WalletId } from "thirdweb/wallets";
20
+ import { useConnectedWallets, useConnect as useConnectTW } from "thirdweb/react";
21
+ import {
22
+ Account,
23
+ createWallet,
24
+ MultiStepAuthArgsType,
25
+ preAuthenticate,
26
+ SingleStepAuthArgsType,
27
+ Wallet,
28
+ WalletId,
29
+ } from "thirdweb/wallets";
20
30
 
21
31
  interface LoginStepCustomProps {
22
32
  automaticallySetFirstEoa: boolean;
@@ -28,6 +38,7 @@ interface LoginStepCustomProps {
28
38
  }
29
39
 
30
40
  const debug = debugB3React("LoginStepCustom");
41
+ const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
31
42
 
32
43
  export function LoginStepCustom({
33
44
  onSuccess,
@@ -40,32 +51,49 @@ export function LoginStepCustom({
40
51
  const { partnerId } = useB3Config();
41
52
  const [isLoading, setIsLoading] = useState(false);
42
53
  const [showAllWallets, setShowAllWallets] = useState(false);
54
+ const [showEmailFlow, setShowEmailFlow] = useState(false);
55
+ const [email, setEmail] = useState("");
56
+ const [verificationCode, setVerificationCode] = useState("");
57
+ const [emailCodeSent, setEmailCodeSent] = useState(false);
58
+ const [emailError, setEmailError] = useState<string | null>(null);
43
59
  const { connect } = useConnect(partnerId, chain);
44
60
  const setIsAuthenticating = useAuthStore(state => state.setIsAuthenticating);
45
- const setIsAuthenticated = useAuthStore(state => state.setIsAuthenticated);
46
- const { logout } = useAuthentication(partnerId, { skipAutoConnect: true });
61
+ const { connect: onAuthConnect, logout } = useAuthentication(partnerId, { skipAutoConnect: true });
47
62
  const { connect: connectTW } = useConnectTW();
63
+ const connectedWallets = useConnectedWallets();
48
64
 
49
65
  // Split strategies into auth and wallet types
50
66
  const authStrategies = strategies.filter(s => !isWalletType(s));
51
67
  const walletStrategies = strategies.filter(isWalletType);
52
68
  const initialWallets = walletStrategies.slice(0, maxInitialWallets);
53
69
  const additionalWallets = walletStrategies.slice(maxInitialWallets);
70
+ const authGridColumns = Math.max(1, Math.min(authStrategies.length, 4));
54
71
 
55
- const handleConnect = async (strategy: AllowedStrategy) => {
72
+ const resetEmailFlow = () => {
73
+ setShowEmailFlow(false);
74
+ setEmailCodeSent(false);
75
+ setVerificationCode("");
76
+ setEmailError(null);
77
+ };
78
+
79
+ const connectWithOptions = async (
80
+ strategy: AllowedStrategy,
81
+ options: MultiStepAuthArgsType | SingleStepAuthArgsType,
82
+ ) => {
56
83
  try {
57
84
  setIsLoading(true);
58
85
  debug("setIsAuthenticating:true:3");
59
86
  setIsAuthenticating(true);
60
- const options = getConnectOptionsFromStrategy(strategy);
61
87
  let connectResult: Wallet | null;
62
88
 
63
- if (automaticallySetFirstEoa) {
64
- if (!options.wallet?.id) {
89
+ if (automaticallySetFirstEoa && isWalletType(strategy) && options.strategy === "wallet") {
90
+ const walletId = options.wallet?.id as WalletId | undefined;
91
+ if (!walletId) {
65
92
  throw new Error("Wallet ID is required");
66
93
  }
94
+
67
95
  connectResult = await connectTW(async () => {
68
- const wallet = createWallet(options.wallet?.id as WalletId);
96
+ const wallet = createWallet(walletId);
69
97
  await wallet.connect({
70
98
  client,
71
99
  });
@@ -73,19 +101,27 @@ export function LoginStepCustom({
73
101
  return wallet;
74
102
  });
75
103
  } else {
76
- // @ts-expect-error we have custom strategies too and we also get things like "apple" isn't assignable to "wallet"
77
104
  connectResult = await connect(options);
78
105
  }
79
106
 
80
107
  const account = connectResult?.getAccount();
81
108
  debug("@@connectResult", { connectResult, account, options });
82
- if (!account) throw new Error("Failed to connect");
109
+ if (!account || !connectResult) throw new Error("Failed to connect");
110
+ const allConnectedWallets =
111
+ connectedWallets.length > 0 && connectedWallets.some(wallet => wallet.id === connectResult.id)
112
+ ? connectedWallets
113
+ : [connectResult, ...connectedWallets.filter(wallet => wallet.id !== connectResult.id)];
114
+ await onAuthConnect(connectResult, allConnectedWallets);
83
115
  await onSuccess(account);
84
- setIsAuthenticated(true);
116
+ if (strategy === "email") {
117
+ resetEmailFlow();
118
+ }
85
119
  } catch (error) {
120
+ if (strategy === "email") {
121
+ setEmailError(error instanceof Error ? error.message : "Failed to sign in with email");
122
+ }
86
123
  await onError?.(error as Error);
87
124
  await logout();
88
- setIsAuthenticated(false);
89
125
  } finally {
90
126
  setIsLoading(false);
91
127
  debug("setIsAuthenticating:false:3");
@@ -93,60 +129,177 @@ export function LoginStepCustom({
93
129
  }
94
130
  };
95
131
 
132
+ const handleConnect = async (strategy: AllowedStrategy) => {
133
+ if (strategy === "email") {
134
+ setShowEmailFlow(true);
135
+ setEmailCodeSent(false);
136
+ setVerificationCode("");
137
+ setEmailError(null);
138
+ return;
139
+ }
140
+
141
+ const options = getConnectOptionsFromStrategy(strategy);
142
+ await connectWithOptions(strategy, options as SingleStepAuthArgsType);
143
+ };
144
+
145
+ const handleSendEmailCode = async () => {
146
+ const normalizedEmail = email.trim().toLowerCase();
147
+ if (!normalizedEmail) {
148
+ setEmailError("Please enter your email address");
149
+ return;
150
+ }
151
+
152
+ if (!EMAIL_REGEX.test(normalizedEmail)) {
153
+ setEmailError("Please enter a valid email address");
154
+ return;
155
+ }
156
+
157
+ try {
158
+ setIsLoading(true);
159
+ setEmailError(null);
160
+ await preAuthenticate({
161
+ client,
162
+ strategy: "email",
163
+ email: normalizedEmail,
164
+ ecosystem: {
165
+ id: ecosystemWalletId,
166
+ partnerId,
167
+ },
168
+ });
169
+ setEmail(normalizedEmail);
170
+ setEmailCodeSent(true);
171
+ } catch (error) {
172
+ setEmailError(error instanceof Error ? error.message : "Failed to send verification code");
173
+ await onError?.(error as Error);
174
+ } finally {
175
+ setIsLoading(false);
176
+ }
177
+ };
178
+
179
+ const handleEmailLogin = async () => {
180
+ const normalizedEmail = email.trim().toLowerCase();
181
+ const normalizedCode = verificationCode.trim();
182
+
183
+ if (!EMAIL_REGEX.test(normalizedEmail)) {
184
+ setEmailError("Please enter a valid email address");
185
+ return;
186
+ }
187
+
188
+ if (!normalizedCode) {
189
+ setEmailError("Please enter your verification code");
190
+ return;
191
+ }
192
+
193
+ await connectWithOptions("email", {
194
+ strategy: "email",
195
+ email: normalizedEmail,
196
+ verificationCode: normalizedCode,
197
+ });
198
+ };
199
+
96
200
  return (
97
201
  <LoginStepContainer partnerId={partnerId}>
98
- {/* Auth Strategies */}
99
- {authStrategies.length > 0 && (
100
- <div className={`mb-6 w-full ${authStrategies.length <= 3 ? "space-y-3 px-3" : "grid grid-cols-4 gap-4"}`}>
101
- {authStrategies.map(strategy => {
102
- console.log("strategy", strategy);
103
- return (
104
- <AuthButton
105
- key={strategy}
106
- strategy={strategy}
107
- onClick={() => handleConnect(strategy)}
108
- isLoading={isLoading}
109
- />
110
- );
111
- })}
112
- </div>
113
- )}
114
-
115
- {/* Initial Wallet List */}
116
- <div className="mb-4 w-full space-y-2">
117
- {initialWallets.map(walletId => (
118
- <WalletRow
119
- key={walletId}
120
- walletId={walletId as WalletId}
121
- onClick={() => handleConnect(walletId)}
122
- isLoading={isLoading}
202
+ {showEmailFlow ? (
203
+ <div className="mb-6 w-full space-y-3 px-3">
204
+ <p className="text-center text-sm font-medium text-gray-900 dark:text-gray-100">Sign in with email</p>
205
+ <Input
206
+ type="email"
207
+ placeholder="you@example.com"
208
+ value={email}
209
+ onChange={event => setEmail(event.target.value)}
210
+ disabled={isLoading || emailCodeSent}
123
211
  />
124
- ))}
125
- </div>
126
212
 
127
- {/* Additional Wallets Section */}
128
- {additionalWallets.length > 0 && (
129
- <div className="w-full">
213
+ {emailCodeSent && (
214
+ <Input
215
+ type="text"
216
+ placeholder="Enter verification code"
217
+ value={verificationCode}
218
+ onChange={event => setVerificationCode(event.target.value)}
219
+ disabled={isLoading}
220
+ />
221
+ )}
222
+
223
+ {emailError && <p className="text-sm text-red-500">{emailError}</p>}
224
+
130
225
  <Button
131
- onClick={() => setShowAllWallets(!showAllWallets)}
132
- className="mb-2 w-full bg-transparent text-gray-600 hover:bg-gray-100"
226
+ onClick={emailCodeSent ? handleEmailLogin : handleSendEmailCode}
227
+ disabled={isLoading}
228
+ className="w-full"
133
229
  >
134
- {showAllWallets ? "Show less" : "More options"}
230
+ {isLoading ? "Loading..." : emailCodeSent ? "Verify code" : "Send code"}
135
231
  </Button>
136
232
 
137
- {showAllWallets && (
138
- <div className="max-h-60 space-y-2 overflow-y-auto">
139
- {additionalWallets.map(walletId => (
140
- <WalletRow
141
- key={walletId}
142
- walletId={walletId as WalletId}
143
- onClick={() => handleConnect(walletId)}
233
+ {emailCodeSent && (
234
+ <Button variant="outline" onClick={handleSendEmailCode} disabled={isLoading} className="w-full">
235
+ Resend code
236
+ </Button>
237
+ )}
238
+
239
+ <Button variant="outline" onClick={resetEmailFlow} disabled={isLoading} className="w-full">
240
+ Back
241
+ </Button>
242
+ </div>
243
+ ) : (
244
+ <>
245
+ {/* Auth Strategies */}
246
+ {authStrategies.length > 0 && (
247
+ <div
248
+ className={`mb-6 grid w-full gap-4 px-3 ${authStrategies.length > 4 ? "grid-cols-4" : ""}`}
249
+ style={
250
+ authStrategies.length <= 4
251
+ ? { gridTemplateColumns: `repeat(${authGridColumns}, minmax(0, 1fr))` }
252
+ : undefined
253
+ }
254
+ >
255
+ {authStrategies.map(strategy => (
256
+ <AuthButton
257
+ key={strategy}
258
+ strategy={strategy}
259
+ onClick={() => handleConnect(strategy)}
144
260
  isLoading={isLoading}
145
261
  />
146
262
  ))}
147
263
  </div>
148
264
  )}
149
- </div>
265
+
266
+ {/* Initial Wallet List */}
267
+ <div className="mb-4 w-full space-y-2">
268
+ {initialWallets.map(walletId => (
269
+ <WalletRow
270
+ key={walletId}
271
+ walletId={walletId as WalletId}
272
+ onClick={() => handleConnect(walletId)}
273
+ isLoading={isLoading}
274
+ />
275
+ ))}
276
+ </div>
277
+
278
+ {/* Additional Wallets Section */}
279
+ {additionalWallets.length > 0 && (
280
+ <div className="w-full">
281
+ <Button
282
+ onClick={() => setShowAllWallets(!showAllWallets)}
283
+ className="mb-2 w-full bg-transparent text-gray-600 hover:bg-gray-100"
284
+ >
285
+ {showAllWallets ? "Show less" : "More options"}
286
+ </Button>
287
+
288
+ {showAllWallets && (
289
+ <div className="max-h-60 space-y-2 overflow-y-auto">
290
+ {additionalWallets.map(walletId => (
291
+ <WalletRow
292
+ key={walletId}
293
+ walletId={walletId as WalletId}
294
+ onClick={() => handleConnect(walletId)}
295
+ isLoading={isLoading}
296
+ />
297
+ ))}
298
+ </div>
299
+ )}
300
+ </div>
301
+ )}
302
+ </>
150
303
  )}
151
304
  </LoginStepContainer>
152
305
  );
@@ -5,7 +5,8 @@ type WalletType = Wallet["id"];
5
5
  type StrategyType = SingleStepAuthArgsType["strategy"];
6
6
  type CustomStrategyType = "basement" | "privy";
7
7
 
8
- type AllowedStrategies = StrategyType | WalletType | CustomStrategyType;
8
+ type AllowedStrategies = StrategyType | WalletType | CustomStrategyType | "email";
9
+ type NonWalletStrategyType = Exclude<AllowedStrategies, WalletType>;
9
10
  const customStrategies = ["basement", "privy"] as const;
10
11
  // type CustomStrategy = (typeof customStrategies)[number];
11
12
 
@@ -13,9 +14,10 @@ export const allowedStrategies = [
13
14
  // Auth strategies
14
15
  "apple",
15
16
  "google",
17
+ "github",
16
18
  "x",
17
19
  "discord",
18
- // "github",
20
+ "email",
19
21
  "guest",
20
22
 
21
23
  // Wallet IDs
@@ -36,7 +38,7 @@ export function isWalletType(strategy: AllowedStrategies): strategy is WalletTyp
36
38
  return strategy === "walletConnect" || walletIdPattern.test(strategy);
37
39
  }
38
40
 
39
- export function isStrategyType(strategy: AllowedStrategies): strategy is StrategyType {
41
+ export function isStrategyType(strategy: AllowedStrategies): strategy is NonWalletStrategyType {
40
42
  return !isWalletType(strategy);
41
43
  }
42
44
 
@@ -49,6 +51,10 @@ export function getConnectOptionsFromStrategy(strategy: AllowedStrategy): {
49
51
  throw new Error(`Invalid strategy: ${strategy}`);
50
52
  }
51
53
 
54
+ if (strategy === "email") {
55
+ throw new Error("Email strategy requires OTP flow and cannot be connected in a single step");
56
+ }
57
+
52
58
  if (isWalletType(strategy)) {
53
59
  return { strategy: "wallet" as const, wallet: createWallet(strategy) };
54
60
  } else {
@@ -65,6 +71,16 @@ export const strategyIcons: Record<string, string> = {
65
71
  guest: "https://cdn.b3.fun/incognito.svg",
66
72
  // Add more strategies as needed
67
73
  };
74
+
75
+ export const strategyLabels: Record<string, string> = {
76
+ google: "Google",
77
+ x: "X",
78
+ discord: "Discord",
79
+ apple: "Apple",
80
+ guest: "Guest",
81
+ github: "GitHub",
82
+ email: "Email",
83
+ };
68
84
  // Test it
69
85
  // console.log(getConnectOptionsFromStrategy("io.metamask"));
70
86
  // console.log(getConnectOptionsFromStrategy("google"));
@@ -15,6 +15,9 @@ interface ToastContextType {
15
15
  addToast: (type: ToastType, message: string, duration?: number) => string;
16
16
  removeToast: (id: string) => void;
17
17
  clearAll: () => void;
18
+ headerMode: boolean;
19
+ setHeaderMode: (enabled: boolean) => void;
20
+ latestToast: ToastItem | null;
18
21
  }
19
22
 
20
23
  const ToastContext = createContext<ToastContextType | undefined>(undefined);
@@ -23,6 +26,9 @@ let globalToastCounter = 0;
23
26
 
24
27
  export function ToastProvider({ children }: { children: React.ReactNode }) {
25
28
  const [toasts, setToasts] = useState<ToastItem[]>([]);
29
+ const [headerMode, setHeaderMode] = useState(false);
30
+ const headerModeRef = useRef(false);
31
+ const [latestToast, setLatestToast] = useState<ToastItem | null>(null);
26
32
  const timeoutsRef = useRef<Map<string, NodeJS.Timeout>>(new Map());
27
33
 
28
34
  const removeToast = useCallback((id: string) => {
@@ -45,13 +51,23 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
45
51
  createdAt: Date.now(),
46
52
  };
47
53
 
48
- setToasts(prev => [...prev, newToast]);
54
+ if (headerModeRef.current) {
55
+ setLatestToast(newToast);
56
+ if (duration > 0) {
57
+ const timeout = setTimeout(() => {
58
+ setLatestToast(null);
59
+ }, duration);
60
+ timeoutsRef.current.set(id, timeout);
61
+ }
62
+ } else {
63
+ setToasts(prev => [...prev, newToast]);
49
64
 
50
- if (duration > 0) {
51
- const timeout = setTimeout(() => {
52
- removeToast(id);
53
- }, duration);
54
- timeoutsRef.current.set(id, timeout);
65
+ if (duration > 0) {
66
+ const timeout = setTimeout(() => {
67
+ removeToast(id);
68
+ }, duration);
69
+ timeoutsRef.current.set(id, timeout);
70
+ }
55
71
  }
56
72
 
57
73
  return id;
@@ -65,6 +81,16 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
65
81
  setToasts([]);
66
82
  }, []);
67
83
 
84
+ const setHeaderModeCallback = useCallback((enabled: boolean) => {
85
+ setHeaderMode(enabled);
86
+ headerModeRef.current = enabled;
87
+ if (!enabled) {
88
+ setLatestToast(null);
89
+ timeoutsRef.current.forEach(timeout => clearTimeout(timeout));
90
+ timeoutsRef.current.clear();
91
+ }
92
+ }, []);
93
+
68
94
  // Cleanup on unmount
69
95
  useEffect(() => {
70
96
  const timeouts = timeoutsRef.current;
@@ -74,7 +100,13 @@ export function ToastProvider({ children }: { children: React.ReactNode }) {
74
100
  };
75
101
  }, []);
76
102
 
77
- return <ToastContext.Provider value={{ toasts, addToast, removeToast, clearAll }}>{children}</ToastContext.Provider>;
103
+ return (
104
+ <ToastContext.Provider
105
+ value={{ toasts, addToast, removeToast, clearAll, headerMode, setHeaderMode: setHeaderModeCallback, latestToast }}
106
+ >
107
+ {children}
108
+ </ToastContext.Provider>
109
+ );
78
110
  }
79
111
 
80
112
  export function useToastContext() {
@@ -6,7 +6,7 @@ import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
6
6
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
7
7
  import { ConnectionOptions } from "@thirdweb-dev/wagmi-adapter";
8
8
  import { getConnectors } from "@wagmi/core";
9
- import { useCallback, useContext, useEffect, useRef } from "react";
9
+ import { useCallback, useContext, useEffect, useMemo, useRef } from "react";
10
10
  import {
11
11
  useActiveWallet,
12
12
  useAutoConnect,
@@ -18,7 +18,7 @@ import { Wallet, ecosystemWallet } from "thirdweb/wallets";
18
18
  import { preAuthenticate } from "thirdweb/wallets/in-app";
19
19
  import { useAccount, useConnect, useSwitchAccount } from "wagmi";
20
20
  import { LocalSDKContext } from "../components/B3Provider/LocalSDKProvider";
21
- import { getCachedWagmiConfig } from "../utils/createWagmiConfig";
21
+ import { createWagmiConfig } from "../utils/createWagmiConfig";
22
22
  import { useSearchParam } from "./useSearchParamsSSR";
23
23
  import { useUserQuery } from "./useUserQuery";
24
24
 
@@ -30,7 +30,7 @@ const debug = debugB3React("useAuth");
30
30
  * This hook provides 1:1 feature parity with useAuthentication.ts
31
31
  */
32
32
  export function useAuth() {
33
- const { onConnectCallback } = useContext(LocalSDKContext);
33
+ const { onConnectCallback, disableBSMNTAuthentication } = useContext(LocalSDKContext);
34
34
  const { disconnect } = useDisconnect();
35
35
  const wallets = useConnectedWallets();
36
36
  const activeWallet = useActiveWallet();
@@ -47,7 +47,7 @@ export function useAuth() {
47
47
  const useAutoConnectLoadingPrevious = useRef(false);
48
48
  const referralCode = useSearchParam("referralCode");
49
49
  const { partnerId } = useB3Config();
50
- const wagmiConfig = getCachedWagmiConfig({ partnerId });
50
+ const wagmiConfig = useMemo(() => createWagmiConfig({ partnerId }), [partnerId]);
51
51
  const { connect } = useConnect();
52
52
  const activeWagmiAccount = useAccount();
53
53
  const { switchAccount } = useSwitchAccount();
@@ -76,8 +76,10 @@ export function useAuth() {
76
76
 
77
77
  // Authenticate with BSMNT
78
78
  try {
79
- const b3Jwt = await authenticateWithB3JWT(response.accessToken);
80
- debug("BSMNT re-authentication successful", b3Jwt);
79
+ if (!disableBSMNTAuthentication) {
80
+ const b3Jwt = await authenticateWithB3JWT(response.accessToken);
81
+ debug("BSMNT re-authentication successful", b3Jwt);
82
+ }
81
83
  } catch (bsmntError) {
82
84
  // BSMNT authentication failure shouldn't block the main auth flow
83
85
  debug("BSMNT re-authentication failed (non-critical)", bsmntError);
@@ -88,7 +90,7 @@ export function useAuth() {
88
90
  debug("Re-authentication failed", err);
89
91
  throw err;
90
92
  }
91
- }, [setUser]);
93
+ }, [setUser, disableBSMNTAuthentication]);
92
94
 
93
95
  const syncWagmi = useCallback(async () => {
94
96
  function syncWagmiFunc() {
@@ -136,9 +138,7 @@ export function useAuth() {
136
138
  });
137
139
  }
138
140
  syncWagmiFunc();
139
- // wagmi config shouldn't change
140
- // eslint-disable-next-line react-hooks/exhaustive-deps
141
- }, [partnerId, wallets]);
141
+ }, [wagmiConfig, wallets, connect, switchAccount]);
142
142
 
143
143
  useEffect(() => {
144
144
  syncWagmi();
@@ -159,9 +159,11 @@ export function useAuth() {
159
159
  setIsAuthenticating(false);
160
160
  debug("Re-authenticated successfully", { userAuth });
161
161
 
162
- // Authenticate on BSMNT with B3 JWT
163
- const b3Jwt = await authenticateWithB3JWT(userAuth.accessToken);
164
- debug("@@b3Jwt", b3Jwt);
162
+ if (!disableBSMNTAuthentication) {
163
+ // Authenticate on BSMNT with B3 JWT
164
+ const b3Jwt = await authenticateWithB3JWT(userAuth.accessToken);
165
+ debug("@@b3Jwt", b3Jwt);
166
+ }
165
167
 
166
168
  return userAuth;
167
169
  } catch (error) {
@@ -171,7 +173,14 @@ export function useAuth() {
171
173
  setIsAuthenticating(false);
172
174
  throw new Error("Authentication required. Please authenticate.");
173
175
  }
174
- }, [reAuthenticate, setIsAuthenticated, setIsAuthenticating, setUser, setHasStartedConnecting]);
176
+ }, [
177
+ reAuthenticate,
178
+ setIsAuthenticated,
179
+ setIsAuthenticating,
180
+ setUser,
181
+ setHasStartedConnecting,
182
+ disableBSMNTAuthentication,
183
+ ]);
175
184
 
176
185
  /**
177
186
  * Authenticate with B3
@@ -208,8 +217,10 @@ export function useAuth() {
208
217
 
209
218
  // Step 3: Authenticate with BSMNT for basement integration
210
219
  try {
211
- const b3Jwt = await authenticateWithB3JWT(response.accessToken);
212
- debug("BSMNT authentication successful", b3Jwt);
220
+ if (!disableBSMNTAuthentication) {
221
+ const b3Jwt = await authenticateWithB3JWT(response.accessToken);
222
+ debug("BSMNT authentication successful", b3Jwt);
223
+ }
213
224
  } catch (bsmntError) {
214
225
  // BSMNT authentication failure shouldn't block the main auth flow
215
226
  debug("BSMNT authentication failed (non-critical)", bsmntError);
@@ -221,7 +232,7 @@ export function useAuth() {
221
232
  throw err;
222
233
  }
223
234
  },
224
- [referralCode, setUser],
235
+ [referralCode, setUser, disableBSMNTAuthentication],
225
236
  );
226
237
 
227
238
  /**