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

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 (90) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpend.js +1 -1
  2. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +2 -1
  3. package/dist/cjs/anyspend/react/components/common/FiatPaymentMethod.js +2 -2
  4. package/dist/cjs/anyspend/react/components/common/OrderDetails.js +1 -1
  5. package/dist/cjs/anyspend/react/components/common/OrderHistory.js +1 -1
  6. package/dist/cjs/anyspend/react/components/common/OrderHistoryItem.js +1 -1
  7. package/dist/cjs/anyspend/react/components/common/PanelOnramp.js +4 -2
  8. package/dist/cjs/anyspend/react/components/common/RecipientSelection.js +1 -1
  9. package/dist/cjs/anyspend/react/hooks/useConnectedWalletDisplay.js +2 -1
  10. package/dist/cjs/global-account/react/components/AccountAssets/AccountAssets.js +9 -9
  11. package/dist/cjs/global-account/react/components/AvatarEditor/AvatarEditor.js +3 -3
  12. package/dist/cjs/global-account/react/components/B3DynamicModal.js +2 -1
  13. package/dist/cjs/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +1 -1
  14. package/dist/cjs/global-account/react/components/LinkAccount/LinkAccount.js +30 -9
  15. package/dist/cjs/global-account/react/components/ManageAccount/BottomNavigation.js +1 -1
  16. package/dist/cjs/global-account/react/components/ManageAccount/Header.js +2 -2
  17. package/dist/cjs/global-account/react/components/ManageAccount/HomeActions.js +1 -1
  18. package/dist/cjs/global-account/react/components/ManageAccount/HomeContent.js +1 -1
  19. package/dist/cjs/global-account/react/components/ManageAccount/ProfileSection.js +1 -1
  20. package/dist/cjs/global-account/react/components/ManageAccount/SettingsContent.js +5 -1
  21. package/dist/cjs/global-account/react/components/ManageAccount/SettingsMenuItem.js +1 -1
  22. package/dist/cjs/global-account/react/components/ManageAccount/SettingsProfileCard.js +1 -1
  23. package/dist/cjs/global-account/react/components/ModalHeader/ModalHeader.js +1 -1
  24. package/dist/cjs/global-account/react/components/SignInWithB3/SignIn.js +1 -1
  25. package/dist/cjs/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -1
  26. package/dist/cjs/global-account/react/components/ui/Tabs.js +1 -1
  27. package/dist/cjs/global-account/react/components/ui/dialog.js +1 -1
  28. package/dist/cjs/global-account/react/utils/profileDisplay.d.ts +1 -0
  29. package/dist/cjs/global-account/react/utils/profileDisplay.js +1 -1
  30. package/dist/esm/anyspend/react/components/AnySpend.js +1 -1
  31. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +3 -2
  32. package/dist/esm/anyspend/react/components/common/FiatPaymentMethod.js +2 -2
  33. package/dist/esm/anyspend/react/components/common/OrderDetails.js +1 -1
  34. package/dist/esm/anyspend/react/components/common/OrderHistory.js +1 -1
  35. package/dist/esm/anyspend/react/components/common/OrderHistoryItem.js +1 -1
  36. package/dist/esm/anyspend/react/components/common/PanelOnramp.js +4 -2
  37. package/dist/esm/anyspend/react/components/common/RecipientSelection.js +1 -1
  38. package/dist/esm/anyspend/react/hooks/useConnectedWalletDisplay.js +2 -1
  39. package/dist/esm/global-account/react/components/AccountAssets/AccountAssets.js +9 -9
  40. package/dist/esm/global-account/react/components/AvatarEditor/AvatarEditor.js +3 -3
  41. package/dist/esm/global-account/react/components/B3DynamicModal.js +2 -1
  42. package/dist/esm/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.js +1 -1
  43. package/dist/esm/global-account/react/components/LinkAccount/LinkAccount.js +31 -10
  44. package/dist/esm/global-account/react/components/ManageAccount/BottomNavigation.js +1 -1
  45. package/dist/esm/global-account/react/components/ManageAccount/Header.js +2 -2
  46. package/dist/esm/global-account/react/components/ManageAccount/HomeActions.js +1 -1
  47. package/dist/esm/global-account/react/components/ManageAccount/HomeContent.js +1 -1
  48. package/dist/esm/global-account/react/components/ManageAccount/ProfileSection.js +1 -1
  49. package/dist/esm/global-account/react/components/ManageAccount/SettingsContent.js +5 -1
  50. package/dist/esm/global-account/react/components/ManageAccount/SettingsMenuItem.js +1 -1
  51. package/dist/esm/global-account/react/components/ManageAccount/SettingsProfileCard.js +1 -1
  52. package/dist/esm/global-account/react/components/ModalHeader/ModalHeader.js +2 -2
  53. package/dist/esm/global-account/react/components/SignInWithB3/SignIn.js +1 -1
  54. package/dist/esm/global-account/react/components/SignInWithB3/SignInWithB3Flow.js +1 -1
  55. package/dist/esm/global-account/react/components/ui/Tabs.js +1 -1
  56. package/dist/esm/global-account/react/components/ui/dialog.js +1 -1
  57. package/dist/esm/global-account/react/utils/profileDisplay.d.ts +1 -0
  58. package/dist/esm/global-account/react/utils/profileDisplay.js +1 -1
  59. package/dist/styles/index.css +1 -1
  60. package/dist/types/global-account/react/utils/profileDisplay.d.ts +1 -0
  61. package/package.json +1 -1
  62. package/src/anyspend/react/components/AnySpend.tsx +1 -1
  63. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +7 -2
  64. package/src/anyspend/react/components/common/FiatPaymentMethod.tsx +2 -2
  65. package/src/anyspend/react/components/common/OrderDetails.tsx +4 -1
  66. package/src/anyspend/react/components/common/OrderHistory.tsx +1 -1
  67. package/src/anyspend/react/components/common/OrderHistoryItem.tsx +4 -4
  68. package/src/anyspend/react/components/common/PanelOnramp.tsx +5 -2
  69. package/src/anyspend/react/components/common/RecipientSelection.tsx +1 -1
  70. package/src/anyspend/react/hooks/useConnectedWalletDisplay.ts +2 -1
  71. package/src/global-account/react/components/AccountAssets/AccountAssets.tsx +20 -20
  72. package/src/global-account/react/components/AvatarEditor/AvatarEditor.tsx +4 -4
  73. package/src/global-account/react/components/B3DynamicModal.tsx +5 -1
  74. package/src/global-account/react/components/IPFSMediaRenderer/IPFSMediaRenderer.tsx +1 -1
  75. package/src/global-account/react/components/LinkAccount/LinkAccount.tsx +43 -15
  76. package/src/global-account/react/components/ManageAccount/BottomNavigation.tsx +1 -1
  77. package/src/global-account/react/components/ManageAccount/Header.tsx +10 -10
  78. package/src/global-account/react/components/ManageAccount/HomeActions.tsx +1 -1
  79. package/src/global-account/react/components/ManageAccount/HomeContent.tsx +2 -2
  80. package/src/global-account/react/components/ManageAccount/ProfileSection.tsx +3 -1
  81. package/src/global-account/react/components/ManageAccount/SettingsContent.tsx +8 -2
  82. package/src/global-account/react/components/ManageAccount/SettingsMenuItem.tsx +1 -1
  83. package/src/global-account/react/components/ManageAccount/SettingsProfileCard.tsx +3 -1
  84. package/src/global-account/react/components/ModalHeader/ModalHeader.tsx +6 -3
  85. package/src/global-account/react/components/SignInWithB3/SignIn.tsx +1 -1
  86. package/src/global-account/react/components/SignInWithB3/SignInWithB3Flow.tsx +1 -1
  87. package/src/global-account/react/components/ui/Tabs.tsx +1 -1
  88. package/src/global-account/react/components/ui/dialog.tsx +3 -12
  89. package/src/global-account/react/utils/profileDisplay.ts +2 -1
  90. package/src/styles/index.css +6 -0
@@ -6,6 +6,7 @@ import { type Profile } from "thirdweb/wallets";
6
6
  */
7
7
  export declare function validateImageUrl(url: string | null | undefined): string | null;
8
8
  export interface ExtendedProfileDetails {
9
+ fid?: string;
9
10
  id?: string;
10
11
  email?: string;
11
12
  phone?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b3dotfun/sdk",
3
- "version": "0.0.65-test.4",
3
+ "version": "0.0.65-test.6",
4
4
  "source": "src/index.ts",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "react-native": "./dist/cjs/index.native.js",
@@ -989,7 +989,7 @@ function AnySpendInner({
989
989
  );
990
990
 
991
991
  const orderDetailsView = (
992
- <div className={"mx-auto w-[460px] max-w-full px-5"}>
992
+ <div className={"mx-auto w-[460px] max-w-full p-5"}>
993
993
  <div className="relative flex flex-col gap-4">
994
994
  {oat && (
995
995
  <OrderDetails
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { useAccountWallet } from "@b3dotfun/sdk/global-account/react";
3
+ import { IPFSMediaRenderer, useAccountWallet } from "@b3dotfun/sdk/global-account/react";
4
4
  import { useAccountWalletImage } from "@b3dotfun/sdk/global-account/react/hooks/useAccountWallet";
5
5
  import { cn } from "@b3dotfun/sdk/shared/utils/cn";
6
6
  import { shortenAddress } from "@b3dotfun/sdk/shared/utils/formatAddress";
@@ -53,6 +53,7 @@ export function CryptoPaymentMethod({
53
53
 
54
54
  // Use custom hook to determine wallet display logic
55
55
  const { shouldShowConnectedEOA, shouldShowWagmiWallet } = useConnectedWalletDisplay(selectedPaymentMethod);
56
+ console.log("shouldShowWagmiWallet :", shouldShowWagmiWallet);
56
57
 
57
58
  // Map wagmi connector names to thirdweb wallet IDs
58
59
  const getThirdwebWalletId = (connectorName: string): WalletId | null => {
@@ -335,7 +336,11 @@ export function CryptoPaymentMethod({
335
336
  <div className="flex items-center justify-between">
336
337
  <div className="flex items-center gap-3">
337
338
  {walletImage ? (
338
- <img src={walletImage} alt="Global Account" className="h-10 w-10 rounded-full" />
339
+ <IPFSMediaRenderer
340
+ src={walletImage}
341
+ alt="Global Account"
342
+ className="h-10 w-10 rounded-full"
343
+ />
339
344
  ) : (
340
345
  <div className="wallet-icon flex h-10 w-10 items-center justify-center rounded-full bg-purple-100">
341
346
  <Wallet className="h-5 w-5 text-purple-600" />
@@ -81,7 +81,7 @@ export function FiatPaymentMethodComponent({
81
81
  // Show loading state while checking geo availability
82
82
  if (isLoadingGeoOnramp) {
83
83
  return (
84
- <div className="fiat-payment-method mx-auto w-[460px] max-w-full px-5">
84
+ <div className="fiat-payment-method mx-auto w-[460px] max-w-full p-5">
85
85
  <div className="flex flex-col gap-6">
86
86
  <div className="flex items-center gap-4">
87
87
  <button
@@ -104,7 +104,7 @@ export function FiatPaymentMethodComponent({
104
104
  }
105
105
 
106
106
  return (
107
- <div className="fiat-payment-method mx-auto w-[460px] max-w-full px-5">
107
+ <div className="fiat-payment-method mx-auto w-[460px] max-w-full p-5">
108
108
  <div className="flex flex-col gap-6">
109
109
  {/* Header */}
110
110
  <div className="flex items-center gap-4">
@@ -1086,7 +1086,10 @@ export const OrderDetails = memo(function OrderDetails({
1086
1086
  />
1087
1087
  )}
1088
1088
 
1089
- <button className="order-details-cancel-btn flex w-full items-center justify-center gap-2" onClick={handleBack}>
1089
+ <button
1090
+ className="text-b3-primary-blue hover:text-b3-primary-blue/50 order-details-cancel-btn flex w-full items-center justify-center gap-2 underline"
1091
+ onClick={handleBack}
1092
+ >
1090
1093
  <RefreshCcw className="ml-2 h-4 w-4" /> Cancel and start over
1091
1094
  </button>
1092
1095
 
@@ -42,7 +42,7 @@ export function OrderHistory({ mode, onBack, onSelectOrder }: OrderHistoryProps)
42
42
  <p className="text-as-secondary text-sm">No order history found</p>
43
43
  </div>
44
44
  ) : (
45
- <div className="mb-12 w-full space-y-3 px-5 pt-5">
45
+ <div className="mb-12 w-full px-5 pt-5">
46
46
  {[...orderHistory]
47
47
  .sort((a, b) => b.createdAt - a.createdAt)
48
48
  .map(order => (
@@ -1,11 +1,11 @@
1
1
  import { ALL_CHAINS, getChainName, getStatusDisplay } from "@b3dotfun/sdk/anyspend";
2
+ import { components } from "@b3dotfun/sdk/anyspend/types/api";
2
3
  import { Badge, useIsMobile } from "@b3dotfun/sdk/global-account/react";
3
4
  import { cn } from "@b3dotfun/sdk/shared/utils";
4
5
  import { formatTokenAmount } from "@b3dotfun/sdk/shared/utils/number";
5
6
  import { getVendorDisplayName } from "@b3dotfun/sdk/shared/utils/payment.utils";
6
7
  import { ArrowRight } from "lucide-react";
7
8
  import TimeAgo from "react-timeago";
8
- import { components } from "@b3dotfun/sdk/anyspend/types/api";
9
9
 
10
10
  interface OrderHistoryItemProps {
11
11
  order: components["schemas"]["Order"];
@@ -39,8 +39,8 @@ export function OrderHistoryItem({ order, onSelectOrder, mode }: OrderHistoryIte
39
39
  <div
40
40
  key={`anyspend-${order.id}`}
41
41
  className={cn(
42
- "bg-as-surface-secondary hover:bg-as-surface-tertiary rounded-xl p-4 transition-all",
43
- onSelectOrder && "cursor-pointer",
42
+ "font-inter border-as-border-secondary border-b py-5 font-medium transition-all last:border-b-0",
43
+ onSelectOrder && "hover:bg-as-surface-secondary/50 cursor-pointer",
44
44
  )}
45
45
  onClick={() => onSelectOrder?.(order.id)}
46
46
  >
@@ -49,7 +49,7 @@ export function OrderHistoryItem({ order, onSelectOrder, mode }: OrderHistoryIte
49
49
  <div className="flex items-center gap-2">
50
50
  <div
51
51
  className={cn(
52
- "text-xs font-semibold",
52
+ "text-xs",
53
53
  orderDisplayStatus === "processing" && "text-yellow-600",
54
54
  orderDisplayStatus === "success" && "text-green-600",
55
55
  orderDisplayStatus === "failure" && "text-red-600",
@@ -13,6 +13,8 @@ import { FiatPaymentMethod } from "./FiatPaymentMethod";
13
13
  import { OrderTokenAmountFiat } from "./OrderTokenAmountFiat";
14
14
  import { PointsBadge } from "./PointsBadge";
15
15
 
16
+ const ONE_CHAR_WIDTH = 30;
17
+
16
18
  export function PanelOnramp({
17
19
  srcAmountOnRamp,
18
20
  setSrcAmountOnRamp,
@@ -126,6 +128,7 @@ export function PanelOnramp({
126
128
  const handleQuickAmount = (value: string) => {
127
129
  setSrcAmountOnRamp(value);
128
130
  };
131
+ console.log("srcAmountOnRamp :", srcAmountOnRamp.length);
129
132
 
130
133
  return (
131
134
  <div className="panel-onramp bg-as-surface-primary flex w-full flex-col">
@@ -176,9 +179,9 @@ export function PanelOnramp({
176
179
  value={srcAmountOnRamp}
177
180
  onChange={handleAmountChange}
178
181
  placeholder="5"
179
- className="text-as-primary placeholder:text-as-primary/50 h-auto min-w-[70px] border-0 bg-transparent p-0 px-1 pt-1 text-4xl font-bold focus-visible:ring-0 focus-visible:ring-offset-0"
182
+ className="text-as-primary placeholder:text-as-primary/50 h-auto border-0 bg-transparent p-0 px-1 pt-1 text-4xl font-bold focus-visible:ring-0 focus-visible:ring-offset-0"
180
183
  style={{
181
- width: `${Math.max(50, srcAmountOnRamp.length * 34)}px`,
184
+ width: `${Math.max(ONE_CHAR_WIDTH, srcAmountOnRamp.length * ONE_CHAR_WIDTH)}px`,
182
185
  }}
183
186
  />
184
187
  </div>
@@ -88,7 +88,7 @@ export function RecipientSelection({
88
88
  const canConfirm = recipientAddress && isAddressValid;
89
89
 
90
90
  return (
91
- <div className="recipient-selection mx-auto w-[460px] max-w-full px-5">
91
+ <div className="recipient-selection mx-auto w-[460px] max-w-full p-5">
92
92
  <div className="flex flex-col gap-6">
93
93
  {/* Header */}
94
94
  <div className="flex justify-around">
@@ -32,7 +32,8 @@ export function useConnectedWalletDisplay(
32
32
 
33
33
  // Determine which wallet to show (prefer connectedEOAWallet if both exist and are the same)
34
34
  const shouldShowConnectedEOA = !!connectedEOAWallet;
35
- const shouldShowWagmiWallet = wagmiWalletIsConnected && (!isWalletDuplicated || !connectedEOAWallet);
35
+ // this is disabled because we don't want to display In-App Wallet as a payment method
36
+ const shouldShowWagmiWallet = false; // wagmiWalletIsConnected && (!isWalletDuplicated || !connectedEOAWallet);
36
37
 
37
38
  // Determine which address to use based on payment method
38
39
  let walletAddress: string | undefined;
@@ -15,6 +15,26 @@ interface GroupedNFTs {
15
15
 
16
16
  export function AccountAssets({ nfts, isLoading }: AccountAssetsProps) {
17
17
  // Initialize with all collections expanded
18
+ // Group NFTs by collection
19
+ const groupedNFTs = nfts?.nfts?.reduce(
20
+ (acc, nft) => {
21
+ const collectionId = nft.collection?.collection_id || "unknown";
22
+ if (!acc[collectionId]) {
23
+ acc[collectionId] = {
24
+ collection_id: collectionId,
25
+ collection_name: nft.collection?.name || "Unknown Collection",
26
+ collection_image: nft.collection?.image_url || nft.previews?.image_small_url || "",
27
+ nfts: [],
28
+ };
29
+ }
30
+ acc[collectionId].nfts.push(nft);
31
+ return acc;
32
+ },
33
+ {} as Record<string, GroupedNFTs>,
34
+ );
35
+
36
+ const collections = Object.values(groupedNFTs || {});
37
+
18
38
  const [expandedCollections, setExpandedCollections] = useState<Set<string>>(
19
39
  () => new Set(collections.map(c => c.collection_id)),
20
40
  );
@@ -39,26 +59,6 @@ export function AccountAssets({ nfts, isLoading }: AccountAssetsProps) {
39
59
  return <div className="text-b3-react-muted-foreground py-8 text-center">No NFTs found</div>;
40
60
  }
41
61
 
42
- // Group NFTs by collection
43
- const groupedNFTs = nfts.nfts.reduce(
44
- (acc, nft) => {
45
- const collectionId = nft.collection?.collection_id || "unknown";
46
- if (!acc[collectionId]) {
47
- acc[collectionId] = {
48
- collection_id: collectionId,
49
- collection_name: nft.collection?.name || "Unknown Collection",
50
- collection_image: nft.collection?.image_url || nft.previews?.image_small_url || "",
51
- nfts: [],
52
- };
53
- }
54
- acc[collectionId].nfts.push(nft);
55
- return acc;
56
- },
57
- {} as Record<string, GroupedNFTs>,
58
- );
59
-
60
- const collections = Object.values(groupedNFTs);
61
-
62
62
  const toggleCollection = (collectionId: string) => {
63
63
  setExpandedCollections(prev => {
64
64
  const next = new Set(prev);
@@ -359,7 +359,7 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
359
359
  .filter(p => p.avatar !== null) || []; // Filter out profiles with invalid avatars
360
360
 
361
361
  return (
362
- <div className={cn("flex w-full max-w-md flex-col bg-white", className)}>
362
+ <div className={cn("b3-modal-avatar-editor flex w-full max-w-md flex-col bg-white", className)}>
363
363
  {/* Header */}
364
364
  {viewStep === "upload" && <ModalHeader title="Upload Image" />}
365
365
 
@@ -449,7 +449,7 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
449
449
  {/* Link More Account */}
450
450
  <button
451
451
  onClick={handleLinkMoreAccount}
452
- className="font-inter flex items-center gap-2 text-sm font-semibold text-[#3368ef] hover:underline"
452
+ className="b3-modal-link-more-account font-inter flex items-center gap-2 text-sm font-semibold text-[#3368ef] hover:underline"
453
453
  >
454
454
  <svg
455
455
  width="16"
@@ -479,7 +479,7 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
479
479
  onDragOver={handleDragOver}
480
480
  onDrop={handleDrop}
481
481
  className={cn(
482
- "mb-6 flex w-full cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-16 transition-colors",
482
+ "b3-modal-upload-view mb-6 flex w-full cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed p-16 transition-colors",
483
483
  isDragging
484
484
  ? "border-[#3368ef] bg-[#f0f5ff]"
485
485
  : "border-[#e4e4e7] hover:border-[#3368ef] hover:bg-[#f0f5ff]",
@@ -565,7 +565,7 @@ export function AvatarEditor({ onSetAvatar, className }: AvatarEditorProps) {
565
565
  <Button
566
566
  onClick={handleSaveChanges}
567
567
  disabled={isLoading || (!selectedFile && !selectedProfileType)}
568
- className="flex-1 rounded-xl bg-[#3368ef] text-white hover:bg-[#2952cc]"
568
+ className="b3-modal-save-button flex-1 rounded-xl bg-[#3368ef] text-white hover:bg-[#2952cc]"
569
569
  >
570
570
  {isLoading ? (
571
571
  <>
@@ -90,6 +90,7 @@ export function B3DynamicModal() {
90
90
 
91
91
  // Check if current content type is in freestyle types
92
92
  const isFreestyleType = freestyleTypes.includes(contentType?.type as string);
93
+ console.log("contentType :", contentType);
93
94
  const hideCloseButton = true;
94
95
 
95
96
  // Build content class using cn utility
@@ -100,7 +101,10 @@ export function B3DynamicModal() {
100
101
  fullWidthTypes.includes(contentType?.type as string) && "w-full",
101
102
  isFreestyleType && "b3-modal-freestyle",
102
103
  contentType?.type === "signInWithB3" && "p-0",
103
- contentType?.type === "anySpend" && "md:px-6",
104
+ contentType?.type === "anySpend" && "md:p-0",
105
+ contentType?.type === "send" && "p-0",
106
+ contentType?.type === "manageAccount" && " md:p-0 md:pt-2",
107
+ contentType?.type === "linkAccount" && "md:p-0",
104
108
  // Add specific styles for avatar editor
105
109
  // contentType?.type === "avatarEditor_disabled" &&
106
110
  // "h-[90dvh] w-[90vw] bg-black p-0 overflow-y-auto overflow-x-hidden max-md:-mt-8 max-md:rounded-t-xl",
@@ -59,7 +59,7 @@ export function IPFSMediaRenderer({
59
59
  if (!src) {
60
60
  return (
61
61
  <div className={className} style={style} aria-label={alt}>
62
- <div className="bg-b3-primary-wash flex h-full w-full items-center justify-center">
62
+ <div className="bg-b3-primary-wash flex h-full w-full items-center justify-center rounded-full">
63
63
  <span className="text-b3-grey font-neue-montreal-semibold text-xs">{alt.charAt(0).toUpperCase()}</span>
64
64
  </div>
65
65
  </div>
@@ -3,7 +3,7 @@ import { Button, ManageAccountModalProps, useB3, useModalStore, useQueryB3 } fro
3
3
  import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
4
4
  import { truncateAddress } from "@b3dotfun/sdk/shared/utils/truncateAddress";
5
5
  import { Copy, Loader2, Pencil, UnlinkIcon } from "lucide-react";
6
- import { useRef, useState } from "react";
6
+ import { useEffect, useRef, useState } from "react";
7
7
  import { toast } from "sonner";
8
8
  import { useProfiles, useUnlinkProfile } from "thirdweb/react";
9
9
 
@@ -41,6 +41,7 @@ export const LinkAccount = ({
41
41
  chain: Chain;
42
42
  }) => {
43
43
  const [unlinkingAccountId, setUnlinkingAccountId] = useState<string | null>(null);
44
+ const [profileToUnlink, setProfileToUnlink] = useState<any>(null);
44
45
  const { data: profilesRaw = [], isLoading: isLoadingProfiles } = useProfiles({ client });
45
46
  const { mutate: unlinkProfile, isPending: isUnlinking } = useUnlinkProfile();
46
47
  const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
@@ -115,15 +116,33 @@ export const LinkAccount = ({
115
116
  ...getProfileDisplayInfo(profile),
116
117
  originalProfile: profile,
117
118
  }));
119
+ console.log("profiles :", profiles);
118
120
 
119
- const handleUnlink = async (profile: any) => {
120
- setUnlinkingAccountId(profile.title);
121
- try {
122
- unlinkProfile({ client, profileToUnlink: profile.originalProfile }, mutationOptions);
123
- } catch (error) {
124
- console.error("Error unlinking account:", error);
125
- } finally {
126
- setUnlinkingAccountId(null);
121
+ // Reset confirmation state after 3 seconds
122
+ useEffect(() => {
123
+ if (profileToUnlink) {
124
+ const timer = setTimeout(() => {
125
+ setProfileToUnlink(null);
126
+ }, 5000);
127
+ return () => clearTimeout(timer);
128
+ }
129
+ }, [profileToUnlink]);
130
+
131
+ const handleUnlinkClick = (profile: any) => {
132
+ // If this profile is already pending confirmation, perform the unlink
133
+ if (profileToUnlink?.title === profile.title) {
134
+ setUnlinkingAccountId(profile.title);
135
+ try {
136
+ unlinkProfile({ client, profileToUnlink: profile.originalProfile }, mutationOptions);
137
+ } catch (error) {
138
+ console.error("Error unlinking account:", error);
139
+ } finally {
140
+ setUnlinkingAccountId(null);
141
+ setProfileToUnlink(null);
142
+ }
143
+ } else {
144
+ // First click - set pending confirmation
145
+ setProfileToUnlink(profile);
127
146
  }
128
147
  };
129
148
 
@@ -225,13 +244,22 @@ export const LinkAccount = ({
225
244
  </div>
226
245
  <Button
227
246
  variant="ghost"
228
- size="icon"
229
- className="linked-account-unlink-button text-b3-grey hover:text-b3-negative"
230
- onClick={() => handleUnlink(profile)}
247
+ size={profileToUnlink?.title === profile.title ? "sm" : "icon"}
248
+ className={`linked-account-unlink-button transition-all ${
249
+ profileToUnlink?.title === profile.title
250
+ ? "bg-b3-negative hover:bg-b3-negative/90 text-white"
251
+ : "text-b3-grey hover:text-b3-negative"
252
+ }`}
253
+ onClick={() => handleUnlinkClick(profile)}
231
254
  disabled={unlinkingAccountId === profile.title || isUnlinking}
232
255
  >
233
256
  {unlinkingAccountId === profile.title || isUnlinking ? (
234
- <Loader2 className="linked-account-unlink-loading animate-spin" />
257
+ <Loader2 className="linked-account-unlink-loading h-4 w-4 animate-spin" />
258
+ ) : profileToUnlink?.title === profile.title ? (
259
+ <div className="flex items-center gap-1.5">
260
+ <UnlinkIcon size={14} className="linked-account-unlink-icon" />
261
+ <span className="text-xs font-semibold">Unlink</span>
262
+ </div>
235
263
  ) : (
236
264
  <UnlinkIcon size={16} className="linked-account-unlink-icon" />
237
265
  )}
@@ -240,7 +268,7 @@ export const LinkAccount = ({
240
268
  ))}
241
269
  </div>
242
270
  ) : (
243
- <div className="linked-accounts-empty text-b3-foreground-muted py-8 text-center">
271
+ <div className="linked-accounts-empty font-neue-montreal-medium text-b3-foreground-muted py-8 text-center">
244
272
  No linked accounts found
245
273
  </div>
246
274
  )}
@@ -249,7 +277,7 @@ export const LinkAccount = ({
249
277
  <Button
250
278
  onClick={handleOpenLinkModal}
251
279
  disabled={isLinking}
252
- className="bg-b3-primary-blue hover:bg-b3-primary-blue/90 border-white/12 group relative h-12 w-full rounded-xl border-2 px-[18px] text-base font-semibold text-white shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18),inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] transition-all"
280
+ className="b3-modal-link-new-account-button bg-b3-primary-blue hover:bg-b3-primary-blue/90 border-white/12 group relative h-12 w-full rounded-xl border-2 px-[18px] text-base font-semibold text-white shadow-[inset_0px_0px_0px_1px_rgba(10,13,18,0.18),inset_0px_-2px_0px_0px_rgba(10,13,18,0.05)] transition-all"
253
281
  >
254
282
  <div className="flex items-center justify-center gap-1.5">
255
283
  <svg
@@ -44,7 +44,7 @@ const BottomNavigation = () => {
44
44
  const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
45
45
 
46
46
  return (
47
- <div className="sticky bottom-0 left-0 w-full rounded-b-xl border-t border-gray-200 bg-[#FAFAFA]">
47
+ <div className="b3-modal-bottom-navigation sticky bottom-0 left-0 w-full rounded-b-xl border-t border-gray-200 bg-[#FAFAFA]">
48
48
  <TabsListPrimitive className="flex h-[68px] w-full items-center justify-center gap-4 border-none bg-transparent">
49
49
  <TabTriggerPrimitive
50
50
  value="home"
@@ -58,9 +58,9 @@ function WalletItem({ wallet, isActive, onClick }: { wallet: Wallet; isActive: b
58
58
 
59
59
  return (
60
60
  <div
61
- className={`box-border flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 transition-colors ${
62
- isActive ? "bg-[#F4F4F5]" : "hover:bg-b3-line/50"
63
- }`}
61
+ className={`b3-modal-wallet-item ${
62
+ isActive ? "b3-modal-wallet-item-active bg-[#F4F4F5]" : "hover:bg-b3-line/50"
63
+ } box-border flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 transition-colors`}
64
64
  onClick={onClick}
65
65
  >
66
66
  <div className="relative size-10 shrink-0 overflow-clip rounded-full">
@@ -137,11 +137,11 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
137
137
  type="single"
138
138
  collapsible
139
139
  value={isExpanded ? "wallet-switcher" : ""}
140
- className="bg-b3-background border-b3-line relative border-b"
140
+ className="b3-modal-wallet-switcher bg-b3-background border-b3-line relative border-b"
141
141
  onValueChange={(value: string) => setIsExpanded(value === "wallet-switcher")}
142
142
  >
143
143
  <AccordionPrimitive.Item value="wallet-switcher" className="border-none">
144
- <AccordionPrimitive.Trigger className="group flex w-full items-center justify-between border-none bg-transparent px-5 py-3 outline-none">
144
+ <AccordionPrimitive.Trigger className="b3-modal-wallet-switcher-trigger group flex w-full items-center justify-between border-none bg-transparent px-5 py-3 outline-none">
145
145
  <div className="flex items-center gap-2">
146
146
  <div className="relative size-10 shrink-0 overflow-clip rounded-full">
147
147
  {isActiveGlobalAccount ? (
@@ -157,7 +157,7 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
157
157
  )}
158
158
  </div>
159
159
  <div className="flex flex-col gap-0.5">
160
- <p className="text-b3-grey font-neue-montreal-semibold text-sm">Active Wallet</p>
160
+ <p className="text-b3-grey font-neue-montreal-semibold text-left text-sm">Active Wallet</p>
161
161
  <div className="flex items-center gap-1">
162
162
  <p className="text-b3-foreground-muted font-neue-montreal-medium text-sm">
163
163
  {centerTruncate(address, 4)}
@@ -166,7 +166,7 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
166
166
  </div>
167
167
  </div>
168
168
  </div>
169
- <ChevronDownIcon className="text-b3-grey transition-transform duration-200 group-data-[state=open]:rotate-180" />
169
+ <ChevronDownIcon className="b3-modal-wallet-switcher-chevron text-b3-grey transition-transform duration-200 group-data-[state=open]:rotate-180" />
170
170
  </AccordionPrimitive.Trigger>
171
171
 
172
172
  <AnimatePresence>
@@ -177,7 +177,7 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
177
177
  animate={{ opacity: 1, y: 0 }}
178
178
  exit={{ opacity: 0, y: -10 }}
179
179
  transition={{ duration: 0.2, ease: "easeInOut" }}
180
- className="flex flex-col gap-3 rounded-bl-3xl rounded-br-3xl bg-white px-2 pb-5 pt-3 shadow-[0px_32px_64px_-12px_rgba(10,13,18,0.14),0px_5px_5px_-2.5px_rgba(10,13,18,0.04)]"
180
+ className="b3-modal-wallet-switcher-content flex flex-col gap-3 rounded-bl-3xl rounded-br-3xl bg-white px-2 pb-5 pt-3 shadow-[0px_32px_64px_-12px_rgba(10,13,18,0.14),0px_5px_5px_-2.5px_rgba(10,13,18,0.04)]"
181
181
  >
182
182
  {/* Connected Wallets */}
183
183
  <div className="flex flex-col gap-3">
@@ -192,7 +192,7 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
192
192
 
193
193
  {/* Link Another Wallet */}
194
194
  <div
195
- className="hover:bg-b3-line/50 box-border flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 transition-colors"
195
+ className="b3-modal-link-another-wallet hover:bg-b3-line/50 box-border flex cursor-pointer items-center gap-2 rounded-xl px-3 py-2 transition-colors"
196
196
  onClick={handleLinkWallet}
197
197
  >
198
198
  <div className="bg-b3-line flex size-10 shrink-0 items-center justify-center rounded-full">
@@ -206,7 +206,7 @@ export function Header({ onLogout }: { onLogout?: () => void }) {
206
206
 
207
207
  {/* Sign Out Button */}
208
208
  <button
209
- className="border-b3-line hover:bg-b3-line bg-b3-background flex items-center justify-center gap-1.5 rounded-xl border border-solid p-2.5 transition-colors"
209
+ className="b3-modal-sign-out-button border-b3-line hover:bg-b3-line bg-b3-background flex items-center justify-center gap-1.5 rounded-xl border border-solid p-2.5 transition-colors"
210
210
  onClick={onLogoutEnhanced}
211
211
  disabled={logoutLoading}
212
212
  style={{
@@ -57,7 +57,7 @@ const HomeActions = ({ showDeposit, showSwap }: { showDeposit: boolean; showSwap
57
57
  const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
58
58
 
59
59
  return (
60
- <div className="border-b3-line grid grid-cols-4 gap-3 border-b px-5 pb-6">
60
+ <div className="b3-modal-home-actions border-b3-line grid grid-cols-4 gap-3 border-b px-5 pb-6">
61
61
  {showDeposit && (
62
62
  <HomeActionButton
63
63
  customClass="manage-account-deposit"
@@ -18,9 +18,9 @@ export function HomeContent({ showDeposit = false, showSwap = true }: HomeConten
18
18
  <ProfileSection />
19
19
 
20
20
  <HomeActions showDeposit={showDeposit} showSwap={showSwap} />
21
- <div className="space-y-2 p-5">
21
+ <div className="b3-modal-balance-content space-y-2 p-5">
22
22
  <Tabs defaultValue={"balance"}>
23
- <TabsList>
23
+ <TabsList className="b3-modal-balance-tabs-list">
24
24
  <TabTrigger value="balance" className="font-neue-montreal-semibold p-0 pr-3">
25
25
  Balance
26
26
  </TabTrigger>
@@ -67,7 +67,9 @@ const ProfileSection = () => {
67
67
  <div className="text-b3-foreground-muted"> $</div>
68
68
  <div className="text-[30px]">{formatDisplayNumber(totalBalanceUsd, { fractionDigits: 2 })}</div>
69
69
  </h2>
70
- <div className="font-neue-montreal-semibold text-base leading-none text-[#0B57C2]">{currentUsername}</div>
70
+ <div className="b3-modal-username font-neue-montreal-semibold text-base leading-none text-[#0B57C2]">
71
+ {currentUsername}
72
+ </div>
71
73
  </div>
72
74
  </div>
73
75
  </div>
@@ -1,5 +1,7 @@
1
1
  import { useModalStore } from "@b3dotfun/sdk/global-account/react";
2
+ import { client } from "@b3dotfun/sdk/shared/utils/thirdweb";
2
3
  import { Chain } from "thirdweb";
4
+ import { useProfiles } from "thirdweb/react";
3
5
  import LinkIcon from "../icons/LinkIcon";
4
6
  import ModalHeader from "../ModalHeader/ModalHeader";
5
7
  import SettingsMenuItem from "./SettingsMenuItem";
@@ -17,6 +19,10 @@ const SettingsContent = ({
17
19
  const setB3ModalContentType = useModalStore(state => state.setB3ModalContentType);
18
20
  const setB3ModalOpen = useModalStore(state => state.setB3ModalOpen);
19
21
 
22
+ const { data: profilesRaw = [] } = useProfiles({ client });
23
+
24
+ const profiles = profilesRaw.filter((profile: any) => !["custom_auth_endpoint"].includes(profile.type));
25
+
20
26
  const handleNavigate = (type: "home" | "swap" | "linkAccount" | "avatarEditor") => {
21
27
  if (type === "home") {
22
28
  setB3ModalContentType({
@@ -54,7 +60,7 @@ const SettingsContent = ({
54
60
 
55
61
  {/* Profile Section */}
56
62
  <div className="p-5">
57
- <div className="flex items-center rounded-xl border border-[#e4e4e7] bg-[#f4f4f5] p-4">
63
+ <div className="b3-modal-settings-profile-card flex items-center rounded-xl border border-[#e4e4e7] bg-[#f4f4f5] p-4">
58
64
  <SettingsProfileCard />
59
65
  </div>
60
66
  </div>
@@ -64,7 +70,7 @@ const SettingsContent = ({
64
70
  <SettingsMenuItem
65
71
  icon={<LinkIcon className="text-b3-grey-500" />}
66
72
  title="Linked Accounts"
67
- subtitle="3 connected accounts"
73
+ subtitle={`${profiles.length} connected account${profiles.length > 1 ? "s" : ""}`}
68
74
  onClick={() => handleNavigate("linkAccount")}
69
75
  />
70
76
  {/* <SettingsMenuItem
@@ -12,7 +12,7 @@ const SettingsMenuItem = ({ icon, title, subtitle, onClick }: SettingsMenuItemPr
12
12
  return (
13
13
  <button
14
14
  onClick={onClick}
15
- className="flex w-full items-center gap-2 rounded-xl px-3 py-2 transition-colors hover:bg-[#f4f4f5]"
15
+ className="b3-modal-settings-menu-item flex w-full items-center gap-2 rounded-xl px-3 py-2 transition-colors hover:bg-[#f4f4f5]"
16
16
  >
17
17
  <div className="flex size-10 items-center justify-center rounded-full bg-[#f4f4f5]">{icon}</div>
18
18
  <div className="flex flex-1 flex-col items-start gap-1 text-left">
@@ -162,7 +162,9 @@ const SettingsProfileCard = () => {
162
162
  /* Display mode */
163
163
  <>
164
164
  <div className="flex items-center gap-1">
165
- <p className="font-neue-montreal-semibold text-lg leading-none text-[#0B57C2]">{currentUsername}</p>
165
+ <p className="b3-modal-username font-neue-montreal-semibold text-lg leading-none text-[#0B57C2]">
166
+ {currentUsername}
167
+ </p>
166
168
  </div>
167
169
  <button
168
170
  onClick={handleEditUsername}
@@ -1,5 +1,5 @@
1
1
  import { cn } from "@b3dotfun/sdk/shared/utils";
2
- import { ChevronDown, X } from "lucide-react";
2
+ import { ChevronLeft, X } from "lucide-react";
3
3
  import { useModalStore } from "../../stores";
4
4
 
5
5
  const ModalHeader = ({
@@ -26,14 +26,17 @@ const ModalHeader = ({
26
26
 
27
27
  return (
28
28
  <div
29
- className={cn("flex h-16 items-center justify-between border-b border-[#e4e4e7] bg-white px-5 py-3", className)}
29
+ className={cn(
30
+ "b3-modal-header flex h-16 items-center justify-between border-b border-[#e4e4e7] bg-white px-5 py-3",
31
+ className,
32
+ )}
30
33
  >
31
34
  {showBackButton ? (
32
35
  <button
33
36
  onClick={handleBack || navigateBack}
34
37
  className="flex h-6 w-6 items-center justify-center transition-opacity hover:opacity-70"
35
38
  >
36
- <ChevronDown className="h-6 w-6 rotate-90 text-[#51525c]" />
39
+ <ChevronLeft className="h-6 w-6 text-[#51525c]" />
37
40
  {showBackWord && <span className="text-sm font-medium">Back</span>}
38
41
  </button>
39
42
  ) : (
@@ -124,7 +124,7 @@ export function SignIn(props: SignInWithB3Props) {
124
124
  <div className="ml-4 grow">
125
125
  {ensName && <div>{ensName}</div>}
126
126
  <div>{truncateAddress(globalAddress)}</div>
127
- <div>{walletInfo?.name}</div>
127
+ {/* <div>{walletInfo?.name}</div> */}
128
128
  </div>
129
129
  </div>
130
130
  {isActiveEOAWallet && <Icon className="fill-b3-react-primary" name="check" />}
@@ -217,7 +217,7 @@ export function SignInWithB3Flow({
217
217
  if (isAuthenticating || (isFetchingSigners && step === "login") || source === "requestPermissions") {
218
218
  return (
219
219
  <LoginStepContainer partnerId={partnerId}>
220
- <div className="mt-8 flex items-center justify-center">
220
+ <div className="my-8 flex min-h-[350px] items-center justify-center">
221
221
  <Loading variant="white" size="lg" />
222
222
  </div>
223
223
  </LoginStepContainer>