@b3dotfun/sdk 0.0.58-alpha.1 → 0.0.58-alpha.3

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 (41) hide show
  1. package/dist/cjs/anyspend/react/components/common/CryptoPaymentMethod.js +4 -0
  2. package/dist/cjs/anyspend/utils/accountStore.d.ts +7 -0
  3. package/dist/cjs/anyspend/utils/accountStore.js +8 -0
  4. package/dist/cjs/anyspend/utils/index.d.ts +1 -0
  5. package/dist/cjs/anyspend/utils/index.js +1 -0
  6. package/dist/cjs/global-account/react/components/B3DynamicModal.js +17 -0
  7. package/dist/cjs/shared/react/components/CurrencySelector.js +8 -3
  8. package/dist/cjs/shared/react/components/FormattedCurrency.d.ts +3 -3
  9. package/dist/cjs/shared/react/components/FormattedCurrency.js +31 -26
  10. package/dist/cjs/shared/react/hooks/useCurrencyConversion.d.ts +8 -5
  11. package/dist/cjs/shared/react/hooks/useCurrencyConversion.js +153 -94
  12. package/dist/cjs/shared/react/stores/currencyStore.d.ts +83 -8
  13. package/dist/cjs/shared/react/stores/currencyStore.js +147 -5
  14. package/dist/esm/anyspend/react/components/common/CryptoPaymentMethod.js +5 -1
  15. package/dist/esm/anyspend/utils/accountStore.d.ts +7 -0
  16. package/dist/esm/anyspend/utils/accountStore.js +5 -0
  17. package/dist/esm/anyspend/utils/index.d.ts +1 -0
  18. package/dist/esm/anyspend/utils/index.js +1 -0
  19. package/dist/esm/global-account/react/components/B3DynamicModal.js +17 -0
  20. package/dist/esm/shared/react/components/CurrencySelector.js +10 -5
  21. package/dist/esm/shared/react/components/FormattedCurrency.d.ts +3 -3
  22. package/dist/esm/shared/react/components/FormattedCurrency.js +31 -26
  23. package/dist/esm/shared/react/hooks/useCurrencyConversion.d.ts +8 -5
  24. package/dist/esm/shared/react/hooks/useCurrencyConversion.js +154 -95
  25. package/dist/esm/shared/react/stores/currencyStore.d.ts +83 -8
  26. package/dist/esm/shared/react/stores/currencyStore.js +143 -5
  27. package/dist/types/anyspend/utils/accountStore.d.ts +7 -0
  28. package/dist/types/anyspend/utils/index.d.ts +1 -0
  29. package/dist/types/shared/react/components/FormattedCurrency.d.ts +3 -3
  30. package/dist/types/shared/react/hooks/useCurrencyConversion.d.ts +8 -5
  31. package/dist/types/shared/react/stores/currencyStore.d.ts +83 -8
  32. package/package.json +1 -1
  33. package/src/anyspend/react/components/common/CryptoPaymentMethod.tsx +6 -2
  34. package/src/anyspend/utils/accountStore.ts +12 -0
  35. package/src/anyspend/utils/index.ts +1 -0
  36. package/src/global-account/react/components/B3DynamicModal.tsx +20 -0
  37. package/src/shared/react/components/CurrencySelector.tsx +36 -5
  38. package/src/shared/react/components/FormattedCurrency.tsx +36 -30
  39. package/src/shared/react/hooks/__tests__/useCurrencyConversion.test.ts +14 -14
  40. package/src/shared/react/hooks/useCurrencyConversion.ts +163 -96
  41. package/src/shared/react/stores/currencyStore.ts +216 -10
@@ -1,8 +1,36 @@
1
1
  /**
2
- * Supported currencies for display and conversion.
2
+ * Built-in supported currencies for display and conversion.
3
3
  * Includes fiat currencies (USD, EUR, GBP, JPY, CAD, AUD, KRW) and crypto (ETH, SOL, B3).
4
4
  */
5
5
  export type SupportedCurrency = "ETH" | "USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD" | "B3" | "SOL" | "KRW";
6
+ /**
7
+ * Metadata for a custom currency including display formatting rules.
8
+ */
9
+ export interface CurrencyMetadata {
10
+ /** The currency code/symbol (e.g., "BTC", "DOGE") */
11
+ code: string;
12
+ /** Display symbol for the currency (e.g., "₿", "Ð") */
13
+ symbol: string;
14
+ /** Human-readable name (e.g., "Bitcoin", "Dogecoin") */
15
+ name: string;
16
+ /** Whether to show symbol before the value (true for $100, false for 100 ETH) */
17
+ prefixSymbol?: boolean;
18
+ /** Number of decimal places to show (undefined uses smart formatting) */
19
+ decimals?: number;
20
+ /** Whether to use subscript notation for small values */
21
+ showSubscripts?: boolean;
22
+ }
23
+ /**
24
+ * Exchange rate between two currencies.
25
+ */
26
+ export interface ExchangeRate {
27
+ /** Currency code being converted from */
28
+ from: string;
29
+ /** Currency code being converted to */
30
+ to: string;
31
+ /** Exchange rate multiplier (amount_in_to = amount_in_from * rate) */
32
+ rate: number;
33
+ }
6
34
  /**
7
35
  * Currency symbols used for display formatting.
8
36
  * Prefix currencies (USD, EUR, GBP, CAD, AUD) show symbol before the amount.
@@ -17,24 +45,51 @@ export declare const CURRENCY_NAMES: Record<SupportedCurrency, string>;
17
45
  * Currency store state interface.
18
46
  * @property selectedCurrency - The currency currently selected for display
19
47
  * @property baseCurrency - The base currency for conversion (typically B3)
48
+ * @property customCurrencies - Map of custom currency codes to their metadata
49
+ * @property customExchangeRates - Map of "FROM-TO" pairs to exchange rates
20
50
  * @property setSelectedCurrency - Update the selected display currency
21
51
  * @property setBaseCurrency - Update the base currency for conversions
52
+ * @property addCurrency - Register a new custom currency with metadata
53
+ * @property removeCurrency - Remove a custom currency
54
+ * @property setExchangeRate - Set a custom exchange rate between two currencies
55
+ * @property getExchangeRate - Get exchange rate between two currencies
56
+ * @property getAllCurrencies - Get all available currencies (built-in + custom)
22
57
  */
23
58
  interface CurrencyState {
24
- selectedCurrency: SupportedCurrency;
25
- baseCurrency: SupportedCurrency;
26
- setSelectedCurrency: (currency: SupportedCurrency) => void;
27
- setBaseCurrency: (currency: SupportedCurrency) => void;
59
+ selectedCurrency: string;
60
+ baseCurrency: string;
61
+ customCurrencies: Record<string, CurrencyMetadata>;
62
+ customExchangeRates: Record<string, number>;
63
+ setSelectedCurrency: (currency: string) => void;
64
+ setBaseCurrency: (currency: string) => void;
65
+ addCurrency: (metadata: CurrencyMetadata) => void;
66
+ removeCurrency: (code: string) => void;
67
+ setExchangeRate: (from: string, to: string, rate: number) => void;
68
+ getExchangeRate: (from: string, to: string) => number | undefined;
69
+ getAllCurrencies: () => string[];
28
70
  }
29
71
  /**
30
72
  * Zustand store for managing currency selection and conversion.
31
73
  * Persists user's selected currency preference in localStorage.
74
+ * Supports dynamic currency registration and custom exchange rates.
32
75
  *
33
76
  * @example
34
77
  * ```tsx
35
- * const { selectedCurrency, setSelectedCurrency } = useCurrencyStore();
36
- * // Change display currency to USD
37
- * setSelectedCurrency('USD');
78
+ * const { selectedCurrency, setSelectedCurrency, addCurrency, setExchangeRate } = useCurrencyStore();
79
+ *
80
+ * // Add a new currency
81
+ * addCurrency({
82
+ * code: "BTC",
83
+ * symbol: "₿",
84
+ * name: "Bitcoin",
85
+ * showSubscripts: true,
86
+ * });
87
+ *
88
+ * // Set exchange rate: 1 BTC = 50000 USD
89
+ * setExchangeRate("BTC", "USD", 50000);
90
+ *
91
+ * // Change display currency
92
+ * setSelectedCurrency('BTC');
38
93
  * ```
39
94
  */
40
95
  export declare const useCurrencyStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<CurrencyState>, "persist"> & {
@@ -48,4 +103,24 @@ export declare const useCurrencyStore: import("zustand").UseBoundStore<Omit<impo
48
103
  getOptions: () => Partial<import("zustand/middleware").PersistOptions<CurrencyState, CurrencyState>>;
49
104
  };
50
105
  }>;
106
+ /**
107
+ * Get the symbol for any currency (built-in or custom).
108
+ */
109
+ export declare function getCurrencySymbol(currency: string): string;
110
+ /**
111
+ * Get the name for any currency (built-in or custom).
112
+ */
113
+ export declare function getCurrencyName(currency: string): string;
114
+ /**
115
+ * Get metadata for a custom currency.
116
+ */
117
+ export declare function getCurrencyMetadata(currency: string): CurrencyMetadata | undefined;
118
+ /**
119
+ * Get the number of decimal places for a currency (for converting from smallest unit).
120
+ * Used when parsing amounts from wei/smallest unit format.
121
+ *
122
+ * @param currency - Currency code
123
+ * @returns Number of decimal places (e.g., 18 for ETH/wei, 2 for USD cents, 0 for JPY)
124
+ */
125
+ export declare function getCurrencyDecimalPlaces(currency: string): number;
51
126
  export {};
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useCurrencyStore = exports.CURRENCY_NAMES = exports.CURRENCY_SYMBOLS = void 0;
4
+ exports.getCurrencySymbol = getCurrencySymbol;
5
+ exports.getCurrencyName = getCurrencyName;
6
+ exports.getCurrencyMetadata = getCurrencyMetadata;
7
+ exports.getCurrencyDecimalPlaces = getCurrencyDecimalPlaces;
4
8
  const zustand_1 = require("zustand");
5
9
  const middleware_1 = require("zustand/middleware");
6
10
  /**
@@ -38,20 +42,158 @@ exports.CURRENCY_NAMES = {
38
42
  /**
39
43
  * Zustand store for managing currency selection and conversion.
40
44
  * Persists user's selected currency preference in localStorage.
45
+ * Supports dynamic currency registration and custom exchange rates.
41
46
  *
42
47
  * @example
43
48
  * ```tsx
44
- * const { selectedCurrency, setSelectedCurrency } = useCurrencyStore();
45
- * // Change display currency to USD
46
- * setSelectedCurrency('USD');
49
+ * const { selectedCurrency, setSelectedCurrency, addCurrency, setExchangeRate } = useCurrencyStore();
50
+ *
51
+ * // Add a new currency
52
+ * addCurrency({
53
+ * code: "BTC",
54
+ * symbol: "₿",
55
+ * name: "Bitcoin",
56
+ * showSubscripts: true,
57
+ * });
58
+ *
59
+ * // Set exchange rate: 1 BTC = 50000 USD
60
+ * setExchangeRate("BTC", "USD", 50000);
61
+ *
62
+ * // Change display currency
63
+ * setSelectedCurrency('BTC');
47
64
  * ```
48
65
  */
49
- exports.useCurrencyStore = (0, zustand_1.create)()((0, middleware_1.persist)(set => ({
66
+ exports.useCurrencyStore = (0, zustand_1.create)()((0, middleware_1.persist)((set, get) => ({
50
67
  selectedCurrency: "B3",
51
68
  baseCurrency: "B3",
69
+ customCurrencies: {},
70
+ customExchangeRates: {},
52
71
  setSelectedCurrency: currency => set({ selectedCurrency: currency }),
53
72
  setBaseCurrency: currency => set({ baseCurrency: currency }),
73
+ addCurrency: metadata => {
74
+ set(state => ({
75
+ customCurrencies: {
76
+ ...state.customCurrencies,
77
+ [metadata.code]: metadata,
78
+ },
79
+ }));
80
+ },
81
+ removeCurrency: code => {
82
+ set(state => {
83
+ // Remove the currency
84
+ const { [code]: _removed, ...remaining } = state.customCurrencies;
85
+ // Remove all exchange rates involving this currency
86
+ const filteredRates = {};
87
+ for (const [key, rate] of Object.entries(state.customExchangeRates)) {
88
+ // Key format is "FROM-TO", skip if either matches the removed code
89
+ const [from, to] = key.split("-");
90
+ if (from !== code && to !== code) {
91
+ filteredRates[key] = rate;
92
+ }
93
+ }
94
+ return {
95
+ customCurrencies: remaining,
96
+ customExchangeRates: filteredRates,
97
+ };
98
+ });
99
+ },
100
+ setExchangeRate: (from, to, rate) => {
101
+ set(state => {
102
+ const key = `${from}-${to}`;
103
+ const inverseKey = `${to}-${from}`;
104
+ // Only set inverse rate if rate is not 0 (to avoid Infinity)
105
+ const newRates = {
106
+ ...state.customExchangeRates,
107
+ [key]: rate,
108
+ };
109
+ if (rate !== 0) {
110
+ newRates[inverseKey] = 1 / rate;
111
+ }
112
+ return {
113
+ customExchangeRates: newRates,
114
+ };
115
+ });
116
+ },
117
+ getExchangeRate: (from, to) => {
118
+ const key = `${from}-${to}`;
119
+ return get().customExchangeRates[key];
120
+ },
121
+ getAllCurrencies: () => {
122
+ const builtIn = Object.keys(exports.CURRENCY_SYMBOLS);
123
+ const custom = Object.keys(get().customCurrencies);
124
+ return [...builtIn, ...custom];
125
+ },
54
126
  }), {
55
127
  name: "currency-storage",
56
- version: 2,
128
+ version: 3,
57
129
  }));
130
+ /**
131
+ * Get the symbol for any currency (built-in or custom).
132
+ */
133
+ function getCurrencySymbol(currency) {
134
+ // Check built-in currencies first
135
+ if (currency in exports.CURRENCY_SYMBOLS) {
136
+ return exports.CURRENCY_SYMBOLS[currency];
137
+ }
138
+ // Check custom currencies
139
+ const customCurrencies = exports.useCurrencyStore.getState().customCurrencies;
140
+ const customCurrency = customCurrencies[currency];
141
+ if (customCurrency) {
142
+ return customCurrency.symbol;
143
+ }
144
+ // Fallback to currency code
145
+ return currency;
146
+ }
147
+ /**
148
+ * Get the name for any currency (built-in or custom).
149
+ */
150
+ function getCurrencyName(currency) {
151
+ // Check built-in currencies first
152
+ if (currency in exports.CURRENCY_NAMES) {
153
+ return exports.CURRENCY_NAMES[currency];
154
+ }
155
+ // Check custom currencies
156
+ const customCurrencies = exports.useCurrencyStore.getState().customCurrencies;
157
+ const customCurrency = customCurrencies[currency];
158
+ if (customCurrency) {
159
+ return customCurrency.name;
160
+ }
161
+ // Fallback to currency code
162
+ return currency;
163
+ }
164
+ /**
165
+ * Get metadata for a custom currency.
166
+ */
167
+ function getCurrencyMetadata(currency) {
168
+ const customCurrencies = exports.useCurrencyStore.getState().customCurrencies;
169
+ return customCurrencies[currency];
170
+ }
171
+ /**
172
+ * Get the number of decimal places for a currency (for converting from smallest unit).
173
+ * Used when parsing amounts from wei/smallest unit format.
174
+ *
175
+ * @param currency - Currency code
176
+ * @returns Number of decimal places (e.g., 18 for ETH/wei, 2 for USD cents, 0 for JPY)
177
+ */
178
+ function getCurrencyDecimalPlaces(currency) {
179
+ // Check custom currencies first
180
+ const customCurrencies = exports.useCurrencyStore.getState().customCurrencies;
181
+ const customMetadata = customCurrencies[currency];
182
+ if (customMetadata?.decimals !== undefined) {
183
+ return customMetadata.decimals;
184
+ }
185
+ // Built-in currencies with 18 decimals (wei-like)
186
+ if (currency === "WIN" || currency === "ETH" || currency === "SOL" || currency === "B3") {
187
+ return 18;
188
+ }
189
+ // Fiat currencies with cent-like decimals
190
+ if (currency === "USD" || currency === "EUR" || currency === "GBP" || currency === "CAD" || currency === "AUD") {
191
+ return 2;
192
+ }
193
+ // Currencies without fractional units
194
+ if (currency === "JPY" || currency === "KRW") {
195
+ return 0;
196
+ }
197
+ // Default to 18 decimals (wei-like)
198
+ return 18;
199
+ }
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useGlobalWalletState } from "../../../../anyspend/utils/index.js";
3
4
  import { useAccountWallet } from "../../../../global-account/react/index.js";
4
5
  import { cn } from "../../../../shared/utils/cn.js";
5
6
  import { shortenAddress } from "../../../../shared/utils/formatAddress.js";
@@ -9,7 +10,7 @@ import { ChevronLeft, ChevronRightCircle, Wallet, X, ZapIcon } from "lucide-reac
9
10
  import { useState } from "react";
10
11
  import { createPortal } from "react-dom";
11
12
  import { toast } from "sonner";
12
- import { useSetActiveWallet, useWalletInfo } from "thirdweb/react";
13
+ import { useActiveWallet, useSetActiveWallet, useWalletInfo } from "thirdweb/react";
13
14
  import { createWallet } from "thirdweb/wallets";
14
15
  import { useAccount, useConnect, useDisconnect, useWalletClient } from "wagmi";
15
16
  export var CryptoPaymentMethodType;
@@ -28,6 +29,8 @@ export function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentM
28
29
  const [showWalletModal, setShowWalletModal] = useState(false);
29
30
  const setActiveWallet = useSetActiveWallet();
30
31
  const { data: eoaWalletInfo } = useWalletInfo(connectedEOAWallet?.id);
32
+ const activeWallet = useActiveWallet();
33
+ const setGlobalAccountWallet = useGlobalWalletState(state => state.setGlobalAccountWallet);
31
34
  const isConnected = !!connectedEOAWallet;
32
35
  const globalAddress = connectedSmartWallet?.getAccount()?.address;
33
36
  // Helper function to check if two addresses are the same
@@ -169,6 +172,7 @@ export function CryptoPaymentMethod({ selectedPaymentMethod, setSelectedPaymentM
169
172
  return (_jsxs("div", { className: "crypto-payment-method mx-auto h-fit w-[460px] max-w-full", children: [_jsxs("div", { className: cn("relative flex flex-col gap-10"), children: [_jsx("button", { onClick: onBack, className: "text-as-quaternary hover:text-as-primary absolute flex h-8 w-8 items-center justify-center rounded-lg transition-colors", children: _jsx(ChevronLeft, { className: "h-6 w-6" }) }), _jsx("div", { className: "flex items-center justify-around gap-4", children: _jsx("div", { className: "flex-1 text-center", children: _jsx("h2", { className: "text-as-primary text-lg font-semibold", children: "Select a payment method" }) }) }), _jsxs("div", { className: "crypto-payment-methods flex flex-col gap-4", children: [(shouldShowConnectedEOA || shouldShowWagmiWallet || globalAddress) && (_jsxs("div", { className: "installed-wallets", children: [_jsx("h3", { className: "text-as-primary/80 mb-3 text-sm font-medium", children: "Connected wallets" }), _jsxs("div", { className: "space-y-2", children: [shouldShowConnectedEOA && (_jsx("button", { onClick: () => {
170
173
  setSelectedPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
171
174
  onSelectPaymentMethod(CryptoPaymentMethodType.CONNECT_WALLET);
175
+ setGlobalAccountWallet(activeWallet);
172
176
  setActiveWallet(connectedEOAWallet);
173
177
  toast.success(`Selected ${eoaWalletInfo?.name || connector?.name || "wallet"}`);
174
178
  }, className: cn("crypto-payment-method-connect-wallet w-full rounded-xl border p-4 text-left transition-all hover:shadow-md", selectedPaymentMethod === CryptoPaymentMethodType.CONNECT_WALLET
@@ -0,0 +1,7 @@
1
+ import type { Wallet } from "thirdweb/wallets";
2
+ interface GlobalWalletState {
3
+ globalAccountWallet?: Wallet;
4
+ setGlobalAccountWallet: (account?: Wallet) => void;
5
+ }
6
+ export declare const useGlobalWalletState: import("zustand").UseBoundStore<import("zustand").StoreApi<GlobalWalletState>>;
7
+ export {};
@@ -0,0 +1,5 @@
1
+ import { create } from "zustand";
2
+ export const useGlobalWalletState = create(set => ({
3
+ globalAccountWallet: undefined,
4
+ setGlobalAccountWallet: account => set({ globalAccountWallet: account }),
5
+ }));
@@ -1,3 +1,4 @@
1
+ export * from "./accountStore";
1
2
  export * from "./address";
2
3
  export * from "./chain";
3
4
  export * from "./format";
@@ -1,3 +1,4 @@
1
+ export * from "./accountStore.js";
1
2
  export * from "./address.js";
2
3
  export * from "./chain.js";
3
4
  export * from "./format.js";
@@ -2,9 +2,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { AnySpend, AnySpendBondKit, AnySpendBuySpin, AnySpendNFT, AnyspendSignatureMint, AnySpendStakeB3, AnySpendTournament, OrderHistory, } from "../../../anyspend/react/index.js";
3
3
  import { AnySpendDepositHype } from "../../../anyspend/react/components/AnyspendDepositHype.js";
4
4
  import { AnySpendStakeUpside } from "../../../anyspend/react/components/AnySpendStakeUpside.js";
5
+ import { useGlobalWalletState } from "../../../anyspend/utils/index.js";
5
6
  import { useIsMobile, useModalStore } from "../../../global-account/react/index.js";
6
7
  import { cn } from "../../../shared/utils/cn.js";
7
8
  import { debugB3React } from "../../../shared/utils/debug.js";
9
+ import { useEffect, useRef } from "react";
8
10
  import { AvatarEditor } from "./AvatarEditor/AvatarEditor.js";
9
11
  import { useB3 } from "./B3Provider/useB3.js";
10
12
  import { LinkAccount } from "./LinkAccount/LinkAccount.js";
@@ -13,11 +15,26 @@ import { RequestPermissions } from "./RequestPermissions/RequestPermissions.js";
13
15
  import { SignInWithB3Flow } from "./SignInWithB3/SignInWithB3Flow.js";
14
16
  import { Dialog, DialogContent, DialogDescription, DialogTitle } from "./ui/dialog.js";
15
17
  import { Drawer, DrawerContent, DrawerDescription, DrawerTitle } from "./ui/drawer.js";
18
+ import { useSetActiveWallet } from "thirdweb/react";
16
19
  const debug = debugB3React("B3DynamicModal");
17
20
  export function B3DynamicModal() {
18
21
  const { isOpen, setB3ModalOpen, contentType, history, navigateBack } = useModalStore();
19
22
  const { theme } = useB3();
20
23
  const isMobile = useIsMobile();
24
+ const prevIsOpenRef = useRef(isOpen);
25
+ const globalAccountWallet = useGlobalWalletState(state => state.globalAccountWallet);
26
+ const setGlobalAccountWallet = useGlobalWalletState(state => state.setGlobalAccountWallet);
27
+ const setActiveWallet = useSetActiveWallet();
28
+ // anyspend cleanup global account chnages by setting account back
29
+ useEffect(() => {
30
+ if (prevIsOpenRef.current && !isOpen) {
31
+ if (globalAccountWallet) {
32
+ setActiveWallet(globalAccountWallet);
33
+ setGlobalAccountWallet(undefined);
34
+ }
35
+ }
36
+ prevIsOpenRef.current = isOpen;
37
+ }, [isOpen, globalAccountWallet, setActiveWallet, setGlobalAccountWallet]);
21
38
  // Define arrays for different modal type groups
22
39
  const fullWidthTypes = [
23
40
  "anySpend",
@@ -1,11 +1,16 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { cn } from "../../../shared/utils/index.js";
4
4
  import { Button } from "../../../global-account/react/components/ui/button.js";
5
5
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "../../../global-account/react/components/ui/dropdown-menu.js";
6
- import { CURRENCY_NAMES, CURRENCY_SYMBOLS, useCurrencyStore } from "../stores/currencyStore.js";
7
- const currencies = ["B3", "ETH", "SOL", "USD", "EUR", "GBP", "KRW", "JPY", "CAD", "AUD"];
6
+ import { CURRENCY_NAMES, CURRENCY_SYMBOLS, useCurrencyStore, getCurrencyName, getCurrencySymbol, } from "../stores/currencyStore.js";
7
+ const builtInCurrencies = ["B3", "ETH", "SOL", "USD", "EUR", "GBP", "KRW", "JPY", "CAD", "AUD"];
8
8
  export function CurrencySelector({ labelClassName, buttonVariant = "dark", label }) {
9
- const { selectedCurrency, setSelectedCurrency } = useCurrencyStore();
10
- return (_jsx("div", { className: "flex items-center gap-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("div", { className: "flex items-center gap-3", children: [label && (_jsx("span", { className: cn("text-foreground text-sm font-medium leading-none tracking-tight sm:text-base", labelClassName), children: label })), _jsxs(Button, { variant: buttonVariant, className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium", children: CURRENCY_NAMES[selectedCurrency] }), _jsx("svg", { className: "h-4 w-4", fill: "currentColor", viewBox: "0 0 20 20", children: _jsx("path", { fillRule: "evenodd", d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", clipRule: "evenodd" }) })] })] }) }), _jsx(DropdownMenuContent, { align: "end", className: "z-[100] min-w-[200px]", children: currencies.map(currency => (_jsxs("div", { children: [_jsxs(DropdownMenuItem, { onClick: () => setSelectedCurrency(currency), className: `flex cursor-pointer items-center justify-between gap-3 px-3 py-2.5 transition-colors ${selectedCurrency === currency ? "bg-accent" : "hover:bg-accent/50"}`, children: [_jsx("span", { className: "text-foreground text-sm font-medium", children: CURRENCY_NAMES[currency] }), _jsx("span", { className: "text-muted-foreground text-xs font-medium", children: CURRENCY_SYMBOLS[currency] })] }), currency === "SOL" && _jsx(DropdownMenuSeparator, { className: "bg-border my-1" }, "separator")] }, currency))) })] }) }));
9
+ const selectedCurrency = useCurrencyStore(state => state.selectedCurrency);
10
+ const setSelectedCurrency = useCurrencyStore(state => state.setSelectedCurrency);
11
+ const customCurrencies = useCurrencyStore(state => state.customCurrencies);
12
+ // Separate built-in and custom for better organization
13
+ const customCurrencyCodes = Object.keys(customCurrencies);
14
+ const hasCustomCurrencies = customCurrencyCodes.length > 0;
15
+ return (_jsx("div", { className: "flex items-center gap-2", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("div", { className: "flex items-center gap-3", children: [label && (_jsx("span", { className: cn("text-foreground text-sm font-medium leading-none tracking-tight sm:text-base", labelClassName), children: label })), _jsxs(Button, { variant: buttonVariant, className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium", children: getCurrencyName(selectedCurrency) }), _jsx("svg", { className: "h-4 w-4", fill: "currentColor", viewBox: "0 0 20 20", children: _jsx("path", { fillRule: "evenodd", d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", clipRule: "evenodd" }) })] })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "z-[100] min-w-[200px]", children: [builtInCurrencies.map(currency => (_jsxs("div", { children: [_jsxs(DropdownMenuItem, { onClick: () => setSelectedCurrency(currency), className: `flex cursor-pointer items-center justify-between gap-3 px-3 py-2.5 transition-colors ${selectedCurrency === currency ? "bg-accent" : "hover:bg-accent/50"}`, children: [_jsx("span", { className: "text-foreground text-sm font-medium", children: CURRENCY_NAMES[currency] }), _jsx("span", { className: "text-muted-foreground text-xs font-medium", children: CURRENCY_SYMBOLS[currency] })] }), currency === "SOL" && _jsx(DropdownMenuSeparator, { className: "bg-border my-1" }, "separator")] }, currency))), hasCustomCurrencies && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, { className: "bg-border my-1" }), customCurrencyCodes.map(currency => (_jsxs(DropdownMenuItem, { onClick: () => setSelectedCurrency(currency), className: `flex cursor-pointer items-center justify-between gap-3 px-3 py-2.5 transition-colors ${selectedCurrency === currency ? "bg-accent" : "hover:bg-accent/50"}`, children: [_jsx("span", { className: "text-foreground text-sm font-medium", children: getCurrencyName(currency) }), _jsx("span", { className: "text-muted-foreground text-xs font-medium", children: getCurrencySymbol(currency) })] }, currency)))] }))] })] }) }));
11
16
  }
@@ -1,12 +1,12 @@
1
1
  interface FormattedCurrencyProps {
2
- amount: number;
2
+ amount: string;
3
+ sourceCurrency: string;
3
4
  showChange?: boolean;
4
5
  showColor?: boolean;
5
6
  className?: string;
6
7
  subB3Icon?: boolean;
7
8
  clickable?: boolean;
8
9
  decimals?: number;
9
- currency?: string;
10
10
  }
11
- export declare function FormattedCurrency({ amount, showChange, showColor, className, subB3Icon, clickable, decimals, currency, }: FormattedCurrencyProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function FormattedCurrency({ amount, sourceCurrency, showChange, showColor, className, subB3Icon, clickable, decimals, }: FormattedCurrencyProps): import("react/jsx-runtime").JSX.Element;
12
12
  export {};
@@ -5,21 +5,30 @@ import { cn } from "../../../shared/utils/index.js";
5
5
  import { Tooltip, TooltipContent, TooltipTrigger } from "../../../global-account/react/components/ui/tooltip.js";
6
6
  import { useCurrencyConversion } from "../hooks/useCurrencyConversion.js";
7
7
  import { useCurrencyModalStore } from "../stores/currencyModalStore.js";
8
- export function FormattedCurrency({ amount, showChange = false, showColor = false, className, subB3Icon = true, clickable = true, decimals, currency, }) {
8
+ import { getCurrencyDecimalPlaces } from "../stores/currencyStore.js";
9
+ export function FormattedCurrency({ amount, sourceCurrency, showChange = false, showColor = false, className, subB3Icon = true, clickable = true, decimals, }) {
9
10
  const { formatCurrencyValue, formatTooltipValue, selectedCurrency, baseCurrency } = useCurrencyConversion();
10
11
  const { openModal } = useCurrencyModalStore();
11
- // Use passed currency or fall back to selected currency
12
- const activeCurrency = currency || selectedCurrency;
13
- const isPositive = amount >= 0;
14
- // Get the formatted value (using absolute value for negative numbers when showing change)
15
- const baseAmount = showChange ? Math.abs(amount) : amount;
16
- // Use centralized formatting from hook with optional overrides
17
- const formattedValue = formatCurrencyValue(baseAmount, {
18
- decimals,
19
- currency,
20
- });
12
+ // Convert from smallest unit to human-readable using currency's decimal places
13
+ const decimalPlaces = getCurrencyDecimalPlaces(sourceCurrency);
14
+ const divisor = Math.pow(10, decimalPlaces);
15
+ // Parse amount - handle both string and numeric inputs, including negatives
16
+ let parsedAmount;
17
+ if (typeof amount === "string") {
18
+ // Handle BigInt strings and negative values
19
+ const numericAmount = amount.startsWith("-") ? -Math.abs(parseFloat(amount.replace("-", ""))) : parseFloat(amount);
20
+ parsedAmount = numericAmount / divisor;
21
+ }
22
+ else {
23
+ parsedAmount = amount / divisor;
24
+ }
25
+ const isPositive = parsedAmount >= 0;
26
+ // Always format with absolute value, we'll add the sign separately
27
+ const absoluteAmount = Math.abs(parsedAmount);
28
+ // Format value with automatic conversion from source to display currency
29
+ const formattedValue = formatCurrencyValue(absoluteAmount, sourceCurrency, { decimals });
21
30
  // Generate tooltip using the centralized hook function
22
- const baseTooltipValue = formatTooltipValue(amount, currency);
31
+ const baseTooltipValue = formatTooltipValue(parsedAmount, sourceCurrency);
23
32
  // Add change indicator if needed
24
33
  const tooltipValue = showChange ? `${isPositive ? "+" : "-"}${baseTooltipValue}` : baseTooltipValue;
25
34
  // Determine color class
@@ -32,26 +41,22 @@ export function FormattedCurrency({ amount, showChange = false, showColor = fals
32
41
  colorClass = "text-red-400";
33
42
  }
34
43
  }
35
- // Add change indicator
44
+ // Build display value with appropriate sign
36
45
  let displayValue = formattedValue;
37
46
  if (showChange) {
38
- if (isPositive) {
39
- displayValue = `+${formattedValue}`;
40
- }
41
- else {
42
- displayValue = `-${formattedValue}`;
43
- }
47
+ // Add +/- prefix for change indicators
48
+ displayValue = `${isPositive ? "+" : "-"}${formattedValue}`;
49
+ }
50
+ else if (!isPositive) {
51
+ // Add minus sign for negative values
52
+ displayValue = `-${formattedValue}`;
44
53
  }
45
54
  const handleClick = () => {
46
55
  if (clickable) {
47
56
  openModal();
48
57
  }
49
58
  };
50
- return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("span", { onClick: handleClick, className: cn("inline-flex items-center gap-1 whitespace-nowrap", colorClass, className, clickable && "cursor-pointer transition-opacity hover:opacity-80"), children: [subB3Icon &&
51
- (currency === baseCurrency || (!currency && activeCurrency === baseCurrency)) &&
52
- baseCurrency === "B3"
53
- ? displayValue.split(" ")[0]
54
- : displayValue, subB3Icon &&
55
- (currency === baseCurrency || (!currency && activeCurrency === baseCurrency)) &&
56
- baseCurrency === "B3" && (_jsx("img", { src: B3_COIN_IMAGE_URL, className: "inline-block h-4 w-4 align-middle", alt: "B3 coin" }))] }) }), _jsx(TooltipContent, { children: tooltipValue })] }));
59
+ // Check if we should show B3 icon (when displaying in B3 and baseCurrency is B3)
60
+ const shouldShowB3Icon = subB3Icon && selectedCurrency === "B3" && baseCurrency === "B3";
61
+ return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("span", { onClick: handleClick, className: cn("inline-flex items-center gap-1 whitespace-nowrap", colorClass, className, clickable && "cursor-pointer transition-opacity hover:opacity-80"), children: [shouldShowB3Icon ? displayValue.split(" ")[0] : displayValue, shouldShowB3Icon && (_jsx("img", { src: B3_COIN_IMAGE_URL, className: "inline-block h-4 w-4 align-middle", alt: "B3 coin" }))] }) }), _jsx(TooltipContent, { children: tooltipValue })] }));
57
62
  }
@@ -16,20 +16,23 @@
16
16
  */
17
17
  export declare function useCurrencyConversion(): {
18
18
  /** Currently selected display currency */
19
- selectedCurrency: import("../stores/currencyStore").SupportedCurrency;
19
+ selectedCurrency: string;
20
20
  /** Base currency used for conversion (typically B3) */
21
- baseCurrency: import("../stores/currencyStore").SupportedCurrency;
21
+ baseCurrency: string;
22
22
  /** Current exchange rate from base to selected currency (undefined while loading) */
23
23
  exchangeRate: number | undefined;
24
24
  /** Format a value with currency conversion and proper symbol/decimal handling */
25
- formatCurrencyValue: (value: number, options?: {
25
+ formatCurrencyValue: (value: number, sourceCurrency: string, options?: {
26
26
  decimals?: number;
27
- currency?: string;
28
27
  }) => string;
29
28
  /** Format a tooltip value showing alternate currency representation */
30
- formatTooltipValue: (value: number, customCurrency?: string) => string;
29
+ formatTooltipValue: (value: number, sourceCurrency: string) => string;
31
30
  /** Symbol for the currently selected currency (e.g., "$", "€", "ETH") */
32
31
  selectedCurrencySymbol: string;
33
32
  /** Symbol for the base currency */
34
33
  baseCurrencySymbol: string;
34
+ /** Get exchange rate between any two currencies */
35
+ getExchangeRate: (from: string, to: string) => number | undefined;
36
+ /** All registered custom currencies */
37
+ customCurrencies: Record<string, import("../stores/currencyStore").CurrencyMetadata>;
35
38
  };