@b3dotfun/sdk 0.0.42-alpha.2 → 0.0.42-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.
- package/dist/cjs/global-account/react/components/index.d.ts +8 -7
- package/dist/cjs/global-account/react/components/index.js +29 -23
- package/dist/cjs/global-account/react/components/ui/dropdown-menu.d.ts +27 -0
- package/dist/cjs/global-account/react/components/ui/dropdown-menu.js +100 -0
- package/dist/cjs/shared/constants/currency.d.ts +1 -0
- package/dist/cjs/shared/constants/currency.js +5 -0
- package/dist/cjs/shared/constants/index.d.ts +1 -0
- package/dist/cjs/shared/constants/index.js +15 -0
- package/dist/cjs/shared/react/components/CurrencySelector.d.ts +7 -0
- package/dist/cjs/shared/react/components/CurrencySelector.js +14 -0
- package/dist/cjs/shared/react/components/FormattedCurrency.d.ts +12 -0
- package/dist/cjs/shared/react/components/FormattedCurrency.js +60 -0
- package/dist/cjs/shared/react/components/index.d.ts +2 -0
- package/dist/cjs/shared/react/components/index.js +18 -0
- package/dist/cjs/shared/react/hooks/__tests__/useCurrencyConversion.test.d.ts +1 -0
- package/dist/cjs/shared/react/hooks/__tests__/useCurrencyConversion.test.js +245 -0
- package/dist/cjs/shared/react/hooks/index.d.ts +1 -0
- package/dist/cjs/shared/react/hooks/index.js +1 -0
- package/dist/cjs/shared/react/hooks/useCurrencyConversion.d.ts +35 -0
- package/dist/cjs/shared/react/hooks/useCurrencyConversion.js +200 -0
- package/dist/cjs/shared/react/index.d.ts +2 -0
- package/dist/cjs/shared/react/index.js +2 -0
- package/dist/cjs/shared/react/stores/currencyModalStore.d.ts +7 -0
- package/dist/cjs/shared/react/stores/currencyModalStore.js +9 -0
- package/dist/cjs/shared/react/stores/currencyStore.d.ts +51 -0
- package/dist/cjs/shared/react/stores/currencyStore.js +57 -0
- package/dist/cjs/shared/react/stores/index.d.ts +2 -0
- package/dist/cjs/shared/react/stores/index.js +18 -0
- package/dist/esm/global-account/react/components/index.d.ts +8 -7
- package/dist/esm/global-account/react/components/index.js +8 -7
- package/dist/esm/global-account/react/components/ui/dropdown-menu.d.ts +27 -0
- package/dist/esm/global-account/react/components/ui/dropdown-menu.js +60 -0
- package/dist/esm/shared/constants/currency.d.ts +1 -0
- package/dist/esm/shared/constants/currency.js +2 -0
- package/dist/esm/shared/constants/index.d.ts +1 -0
- package/dist/esm/shared/constants/index.js +1 -0
- package/dist/esm/shared/react/components/CurrencySelector.d.ts +7 -0
- package/dist/esm/shared/react/components/CurrencySelector.js +11 -0
- package/dist/esm/shared/react/components/FormattedCurrency.d.ts +12 -0
- package/dist/esm/shared/react/components/FormattedCurrency.js +57 -0
- package/dist/esm/shared/react/components/index.d.ts +2 -0
- package/dist/esm/shared/react/components/index.js +2 -0
- package/dist/esm/shared/react/hooks/__tests__/useCurrencyConversion.test.d.ts +1 -0
- package/dist/esm/shared/react/hooks/__tests__/useCurrencyConversion.test.js +243 -0
- package/dist/esm/shared/react/hooks/index.d.ts +1 -0
- package/dist/esm/shared/react/hooks/index.js +1 -0
- package/dist/esm/shared/react/hooks/useCurrencyConversion.d.ts +35 -0
- package/dist/esm/shared/react/hooks/useCurrencyConversion.js +197 -0
- package/dist/esm/shared/react/index.d.ts +2 -0
- package/dist/esm/shared/react/index.js +2 -0
- package/dist/esm/shared/react/stores/currencyModalStore.d.ts +7 -0
- package/dist/esm/shared/react/stores/currencyModalStore.js +6 -0
- package/dist/esm/shared/react/stores/currencyStore.d.ts +51 -0
- package/dist/esm/shared/react/stores/currencyStore.js +54 -0
- package/dist/esm/shared/react/stores/index.d.ts +2 -0
- package/dist/esm/shared/react/stores/index.js +2 -0
- package/dist/styles/index.css +1 -1
- package/dist/types/global-account/react/components/index.d.ts +8 -7
- package/dist/types/global-account/react/components/ui/dropdown-menu.d.ts +27 -0
- package/dist/types/shared/constants/currency.d.ts +1 -0
- package/dist/types/shared/constants/index.d.ts +1 -0
- package/dist/types/shared/react/components/CurrencySelector.d.ts +7 -0
- package/dist/types/shared/react/components/FormattedCurrency.d.ts +12 -0
- package/dist/types/shared/react/components/index.d.ts +2 -0
- package/dist/types/shared/react/hooks/__tests__/useCurrencyConversion.test.d.ts +1 -0
- package/dist/types/shared/react/hooks/index.d.ts +1 -0
- package/dist/types/shared/react/hooks/useCurrencyConversion.d.ts +35 -0
- package/dist/types/shared/react/index.d.ts +2 -0
- package/dist/types/shared/react/stores/currencyModalStore.d.ts +7 -0
- package/dist/types/shared/react/stores/currencyStore.d.ts +51 -0
- package/dist/types/shared/react/stores/index.d.ts +2 -0
- package/package.json +29 -3
- package/src/global-account/react/components/index.ts +19 -12
- package/src/global-account/react/components/ui/dropdown-menu.tsx +132 -0
- package/src/shared/constants/currency.ts +2 -0
- package/src/shared/constants/index.ts +2 -0
- package/src/shared/react/components/CurrencySelector.tsx +71 -0
- package/src/shared/react/components/FormattedCurrency.tsx +106 -0
- package/src/shared/react/components/index.ts +2 -0
- package/src/shared/react/hooks/__tests__/useCurrencyConversion.test.ts +308 -0
- package/src/shared/react/hooks/index.ts +1 -0
- package/src/shared/react/hooks/useCurrencyConversion.ts +211 -0
- package/src/shared/react/index.ts +2 -0
- package/src/shared/react/stores/currencyModalStore.ts +13 -0
- package/src/shared/react/stores/currencyStore.ts +82 -0
- package/src/shared/react/stores/index.ts +2 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported currencies for display and conversion.
|
|
3
|
+
* Includes fiat currencies (USD, EUR, GBP, JPY, CAD, AUD, KRW) and crypto (ETH, SOL, B3).
|
|
4
|
+
*/
|
|
5
|
+
export type SupportedCurrency = "ETH" | "USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD" | "B3" | "SOL" | "KRW";
|
|
6
|
+
/**
|
|
7
|
+
* Currency symbols used for display formatting.
|
|
8
|
+
* Prefix currencies (USD, EUR, GBP, CAD, AUD) show symbol before the amount.
|
|
9
|
+
* Suffix currencies (JPY, KRW, ETH, SOL, B3) show symbol after the amount.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CURRENCY_SYMBOLS: Record<SupportedCurrency, string>;
|
|
12
|
+
/**
|
|
13
|
+
* Human-readable currency names for display in selectors and labels.
|
|
14
|
+
*/
|
|
15
|
+
export declare const CURRENCY_NAMES: Record<SupportedCurrency, string>;
|
|
16
|
+
/**
|
|
17
|
+
* Currency store state interface.
|
|
18
|
+
* @property selectedCurrency - The currency currently selected for display
|
|
19
|
+
* @property baseCurrency - The base currency for conversion (typically B3)
|
|
20
|
+
* @property setSelectedCurrency - Update the selected display currency
|
|
21
|
+
* @property setBaseCurrency - Update the base currency for conversions
|
|
22
|
+
*/
|
|
23
|
+
interface CurrencyState {
|
|
24
|
+
selectedCurrency: SupportedCurrency;
|
|
25
|
+
baseCurrency: SupportedCurrency;
|
|
26
|
+
setSelectedCurrency: (currency: SupportedCurrency) => void;
|
|
27
|
+
setBaseCurrency: (currency: SupportedCurrency) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Zustand store for managing currency selection and conversion.
|
|
31
|
+
* Persists user's selected currency preference in localStorage.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* const { selectedCurrency, setSelectedCurrency } = useCurrencyStore();
|
|
36
|
+
* // Change display currency to USD
|
|
37
|
+
* setSelectedCurrency('USD');
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare const useCurrencyStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<CurrencyState>, "persist"> & {
|
|
41
|
+
persist: {
|
|
42
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<CurrencyState, CurrencyState>>) => void;
|
|
43
|
+
clearStorage: () => void;
|
|
44
|
+
rehydrate: () => Promise<void> | void;
|
|
45
|
+
hasHydrated: () => boolean;
|
|
46
|
+
onHydrate: (fn: (state: CurrencyState) => void) => () => void;
|
|
47
|
+
onFinishHydration: (fn: (state: CurrencyState) => void) => () => void;
|
|
48
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<CurrencyState, CurrencyState>>;
|
|
49
|
+
};
|
|
50
|
+
}>;
|
|
51
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@b3dotfun/sdk",
|
|
3
|
-
"version": "0.0.42-alpha.
|
|
3
|
+
"version": "0.0.42-alpha.3",
|
|
4
4
|
"source": "src/index.ts",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"react-native": "./dist/cjs/index.native.js",
|
|
@@ -205,6 +205,26 @@
|
|
|
205
205
|
"import": "./dist/esm/shared/thirdweb/*.js",
|
|
206
206
|
"require": "./dist/cjs/shared/thirdweb/*.js"
|
|
207
207
|
},
|
|
208
|
+
"./shared/react": {
|
|
209
|
+
"types": "./dist/types/shared/react/index.d.ts",
|
|
210
|
+
"import": "./dist/esm/shared/react/index.js",
|
|
211
|
+
"require": "./dist/cjs/shared/react/index.js"
|
|
212
|
+
},
|
|
213
|
+
"./shared/react/components": {
|
|
214
|
+
"types": "./dist/types/shared/react/components/index.d.ts",
|
|
215
|
+
"import": "./dist/esm/shared/react/components/index.js",
|
|
216
|
+
"require": "./dist/cjs/shared/react/components/index.js"
|
|
217
|
+
},
|
|
218
|
+
"./shared/react/hooks": {
|
|
219
|
+
"types": "./dist/types/shared/react/hooks/index.d.ts",
|
|
220
|
+
"import": "./dist/esm/shared/react/hooks/index.js",
|
|
221
|
+
"require": "./dist/cjs/shared/react/hooks/index.js"
|
|
222
|
+
},
|
|
223
|
+
"./shared/react/stores": {
|
|
224
|
+
"types": "./dist/types/shared/react/stores/index.d.ts",
|
|
225
|
+
"import": "./dist/esm/shared/react/stores/index.js",
|
|
226
|
+
"require": "./dist/cjs/shared/react/stores/index.js"
|
|
227
|
+
},
|
|
208
228
|
"./types/chain-networks": {
|
|
209
229
|
"types": "./dist/types/generated/chain-networks.d.ts",
|
|
210
230
|
"import": "./dist/esm/generated/chain-networks.js",
|
|
@@ -289,6 +309,8 @@
|
|
|
289
309
|
"@feathersjs/feathers": "5.0.33",
|
|
290
310
|
"@feathersjs/socketio-client": "5.0.33",
|
|
291
311
|
"@feathersjs/typebox": "5.0.33",
|
|
312
|
+
"@testing-library/react": "^16.3.0",
|
|
313
|
+
"@testing-library/react-hooks": "^8.0.1",
|
|
292
314
|
"@types/big.js": "^6.2.2",
|
|
293
315
|
"@types/invariant": "2.2.37",
|
|
294
316
|
"@types/js-cookie": "3.0.6",
|
|
@@ -304,6 +326,7 @@
|
|
|
304
326
|
"eslint-plugin-import": "2.x.x",
|
|
305
327
|
"eslint-plugin-react-hooks": "4.6.2",
|
|
306
328
|
"eslint-plugin-tailwindcss": "3.18.0",
|
|
329
|
+
"happy-dom": "^19.0.2",
|
|
307
330
|
"postcss": "8.5.3",
|
|
308
331
|
"postcss-cli": "11.0.1",
|
|
309
332
|
"postcss-nesting": "^13.0.2",
|
|
@@ -311,7 +334,8 @@
|
|
|
311
334
|
"tailwindcss": "3.4.1",
|
|
312
335
|
"tailwindcss-animate": "^1.0.7",
|
|
313
336
|
"tsc-alias": "^1.8.16",
|
|
314
|
-
"tsc-watch": "^7.1.1"
|
|
337
|
+
"tsc-watch": "^7.1.1",
|
|
338
|
+
"vitest": "^3.2.4"
|
|
315
339
|
},
|
|
316
340
|
"typesVersions": {
|
|
317
341
|
"*": {
|
|
@@ -367,6 +391,8 @@
|
|
|
367
391
|
"typecheck": "tsc --noEmit",
|
|
368
392
|
"generate:thirdweb": "npx @hey-api/openapi-ts --file src/thirdweb/openapi-ts.config.ts --input src/thirdweb/insight-service.json",
|
|
369
393
|
"lint": "eslint 'src/**/*.{ts,tsx}'",
|
|
370
|
-
"lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix"
|
|
394
|
+
"lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix",
|
|
395
|
+
"test": "vitest run",
|
|
396
|
+
"test:ui": "vitest --ui"
|
|
371
397
|
}
|
|
372
398
|
}
|
|
@@ -7,12 +7,12 @@ export { useB3 } from "./B3Provider/useB3";
|
|
|
7
7
|
export { StyleRoot } from "./StyleRoot";
|
|
8
8
|
|
|
9
9
|
// SignInWithB3 Components
|
|
10
|
-
export { SignInWithB3 } from "./SignInWithB3/SignInWithB3";
|
|
11
|
-
export { SignInWithB3Flow } from "./SignInWithB3/SignInWithB3Flow";
|
|
12
|
-
export { SignInWithB3Privy } from "./SignInWithB3/SignInWithB3Privy";
|
|
13
10
|
export { AuthButton } from "./SignInWithB3/components/AuthButton";
|
|
14
11
|
export { PermissionItem } from "./SignInWithB3/components/PermissionItem";
|
|
15
12
|
export { WalletRow } from "./SignInWithB3/components/WalletRow";
|
|
13
|
+
export { SignInWithB3 } from "./SignInWithB3/SignInWithB3";
|
|
14
|
+
export { SignInWithB3Flow } from "./SignInWithB3/SignInWithB3Flow";
|
|
15
|
+
export { SignInWithB3Privy } from "./SignInWithB3/SignInWithB3Privy";
|
|
16
16
|
export { LoginStepContainer } from "./SignInWithB3/steps/LoginStep";
|
|
17
17
|
export { getConnectOptionsFromStrategy, isWalletType, type AllowedStrategy } from "./SignInWithB3/utils/signInUtils";
|
|
18
18
|
|
|
@@ -43,15 +43,6 @@ export { StaggeredFadeLoader } from "./custom/StaggeredFadeLoader";
|
|
|
43
43
|
export { WalletConnectorIcon } from "./custom/WalletConnectorIcon";
|
|
44
44
|
|
|
45
45
|
// UI Components
|
|
46
|
-
export { Loading } from "./ui/Loading";
|
|
47
|
-
export { ShinyButton } from "./ui/ShinyButton";
|
|
48
|
-
export { TabTrigger, Tabs, TabsContent, TabsList, TabsTransitionWrapper } from "./ui/TabSystem";
|
|
49
|
-
export {
|
|
50
|
-
TabTrigger as TabTriggerPrimitive,
|
|
51
|
-
TabsContent as TabsContentPrimitive,
|
|
52
|
-
TabsList as TabsListPrimitive,
|
|
53
|
-
Tabs as TabsPrimitive,
|
|
54
|
-
} from "./ui/Tabs";
|
|
55
46
|
export { Badge, badgeVariants } from "./ui/badge";
|
|
56
47
|
export { Button, buttonVariants } from "./ui/button";
|
|
57
48
|
export {
|
|
@@ -89,12 +80,28 @@ export {
|
|
|
89
80
|
DrawerTitle,
|
|
90
81
|
DrawerTrigger,
|
|
91
82
|
} from "./ui/drawer";
|
|
83
|
+
export {
|
|
84
|
+
DropdownMenu,
|
|
85
|
+
DropdownMenuContent,
|
|
86
|
+
DropdownMenuItem,
|
|
87
|
+
DropdownMenuSeparator,
|
|
88
|
+
DropdownMenuTrigger,
|
|
89
|
+
} from "./ui/dropdown-menu";
|
|
92
90
|
export { GlareCard } from "./ui/glare-card";
|
|
93
91
|
export { GlareCardRounded } from "./ui/glare-card-rounded";
|
|
94
92
|
export { Input } from "./ui/input";
|
|
93
|
+
export { Loading } from "./ui/Loading";
|
|
95
94
|
export { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
|
|
96
95
|
export { ScrollArea, ScrollBar } from "./ui/scroll-area";
|
|
96
|
+
export { ShinyButton } from "./ui/ShinyButton";
|
|
97
97
|
export { Skeleton } from "./ui/skeleton";
|
|
98
|
+
export {
|
|
99
|
+
TabTrigger as TabTriggerPrimitive,
|
|
100
|
+
TabsContent as TabsContentPrimitive,
|
|
101
|
+
TabsList as TabsListPrimitive,
|
|
102
|
+
Tabs as TabsPrimitive,
|
|
103
|
+
} from "./ui/Tabs";
|
|
104
|
+
export { TabTrigger, Tabs, TabsContent, TabsList, TabsTransitionWrapper } from "./ui/TabSystem";
|
|
98
105
|
export { TextLoop } from "./ui/text-loop";
|
|
99
106
|
export { TextShimmer } from "./ui/text-shimmer";
|
|
100
107
|
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip";
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@b3dotfun/sdk/shared/utils";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
interface DropdownMenuProps {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface DropdownMenuContentProps {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
align?: "start" | "center" | "end";
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface DropdownMenuItemProps {
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
onClick?: () => void;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface DropdownMenuSeparatorProps {
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface DropdownMenuTriggerProps {
|
|
27
|
+
children: React.ReactNode;
|
|
28
|
+
asChild?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const DropdownMenuContext = React.createContext<{
|
|
32
|
+
isOpen: boolean;
|
|
33
|
+
setIsOpen: (open: boolean) => void;
|
|
34
|
+
}>({
|
|
35
|
+
isOpen: false,
|
|
36
|
+
setIsOpen: () => {},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export function DropdownMenu({ children }: DropdownMenuProps) {
|
|
40
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
41
|
+
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
44
|
+
const target = event.target as Element;
|
|
45
|
+
if (!target.closest("[data-dropdown-menu]")) {
|
|
46
|
+
setIsOpen(false);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if (isOpen) {
|
|
51
|
+
document.addEventListener("click", handleClickOutside);
|
|
52
|
+
return () => document.removeEventListener("click", handleClickOutside);
|
|
53
|
+
}
|
|
54
|
+
}, [isOpen]);
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<DropdownMenuContext.Provider value={{ isOpen, setIsOpen }}>
|
|
58
|
+
<div className="relative" data-dropdown-menu>
|
|
59
|
+
{children}
|
|
60
|
+
</div>
|
|
61
|
+
</DropdownMenuContext.Provider>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function DropdownMenuTrigger({ children, asChild }: DropdownMenuTriggerProps) {
|
|
66
|
+
const { isOpen, setIsOpen } = React.useContext(DropdownMenuContext);
|
|
67
|
+
|
|
68
|
+
const handleClick = () => {
|
|
69
|
+
setIsOpen(!isOpen);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if (asChild) {
|
|
73
|
+
if (React.isValidElement(children)) {
|
|
74
|
+
return React.cloneElement(children as React.ReactElement<{ onClick?: () => void }>, {
|
|
75
|
+
onClick: handleClick,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return <button onClick={handleClick}>{children}</button>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function DropdownMenuContent({ children, align = "start", className }: DropdownMenuContentProps) {
|
|
84
|
+
const { isOpen } = React.useContext(DropdownMenuContext);
|
|
85
|
+
|
|
86
|
+
if (!isOpen) return null;
|
|
87
|
+
|
|
88
|
+
const alignmentClasses = {
|
|
89
|
+
start: "left-0",
|
|
90
|
+
center: "left-1/2 -translate-x-1/2",
|
|
91
|
+
end: "right-0",
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div
|
|
96
|
+
className={cn(
|
|
97
|
+
"bg-popover text-popover-foreground absolute top-full z-50 mt-1 min-w-32 overflow-hidden rounded-md border p-1 shadow-md",
|
|
98
|
+
"border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-800",
|
|
99
|
+
alignmentClasses[align],
|
|
100
|
+
className,
|
|
101
|
+
)}
|
|
102
|
+
>
|
|
103
|
+
{children}
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function DropdownMenuItem({ children, onClick, className }: DropdownMenuItemProps) {
|
|
109
|
+
const { setIsOpen } = React.useContext(DropdownMenuContext);
|
|
110
|
+
|
|
111
|
+
const handleClick = () => {
|
|
112
|
+
onClick?.();
|
|
113
|
+
setIsOpen(false);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<div
|
|
118
|
+
className={cn(
|
|
119
|
+
"hover:bg-accent hover:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
120
|
+
"hover:bg-gray-100 dark:hover:bg-gray-700",
|
|
121
|
+
className,
|
|
122
|
+
)}
|
|
123
|
+
onClick={handleClick}
|
|
124
|
+
>
|
|
125
|
+
{children}
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function DropdownMenuSeparator({ className }: DropdownMenuSeparatorProps) {
|
|
131
|
+
return <div className={cn("bg-muted -mx-1 my-1 h-px", "bg-gray-200 dark:bg-gray-600", className)} />;
|
|
132
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@b3dotfun/sdk/shared/utils";
|
|
4
|
+
import { Button } from "../../../global-account/react/components/ui/button";
|
|
5
|
+
import {
|
|
6
|
+
DropdownMenu,
|
|
7
|
+
DropdownMenuContent,
|
|
8
|
+
DropdownMenuItem,
|
|
9
|
+
DropdownMenuSeparator,
|
|
10
|
+
DropdownMenuTrigger,
|
|
11
|
+
} from "../../../global-account/react/components/ui/dropdown-menu";
|
|
12
|
+
import { CURRENCY_NAMES, CURRENCY_SYMBOLS, SupportedCurrency, useCurrencyStore } from "../stores/currencyStore";
|
|
13
|
+
|
|
14
|
+
const currencies: SupportedCurrency[] = ["B3", "ETH", "SOL", "USD", "EUR", "GBP", "KRW", "JPY", "CAD", "AUD"];
|
|
15
|
+
|
|
16
|
+
interface CurrencySelectorProps {
|
|
17
|
+
labelClassName?: string;
|
|
18
|
+
buttonVariant?: "dark" | "primary" | "ghost" | "gold";
|
|
19
|
+
label?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function CurrencySelector({ labelClassName, buttonVariant = "dark", label }: CurrencySelectorProps) {
|
|
23
|
+
const { selectedCurrency, setSelectedCurrency } = useCurrencyStore();
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className="flex items-center gap-2">
|
|
27
|
+
<DropdownMenu>
|
|
28
|
+
<DropdownMenuTrigger asChild>
|
|
29
|
+
<div className="flex items-center gap-3">
|
|
30
|
+
{label && (
|
|
31
|
+
<span
|
|
32
|
+
className={cn(
|
|
33
|
+
"text-foreground text-sm font-medium leading-none tracking-tight sm:text-base",
|
|
34
|
+
labelClassName,
|
|
35
|
+
)}
|
|
36
|
+
>
|
|
37
|
+
{label}
|
|
38
|
+
</span>
|
|
39
|
+
)}
|
|
40
|
+
<Button variant={buttonVariant as any} className="flex items-center gap-2">
|
|
41
|
+
<span className="text-sm font-medium">{CURRENCY_NAMES[selectedCurrency]}</span>
|
|
42
|
+
<svg className="h-4 w-4" fill="currentColor" viewBox="0 0 20 20">
|
|
43
|
+
<path
|
|
44
|
+
fillRule="evenodd"
|
|
45
|
+
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"
|
|
46
|
+
clipRule="evenodd"
|
|
47
|
+
/>
|
|
48
|
+
</svg>
|
|
49
|
+
</Button>
|
|
50
|
+
</div>
|
|
51
|
+
</DropdownMenuTrigger>
|
|
52
|
+
<DropdownMenuContent align="end" className="z-[100] min-w-[200px]">
|
|
53
|
+
{currencies.map(currency => (
|
|
54
|
+
<div key={currency}>
|
|
55
|
+
<DropdownMenuItem
|
|
56
|
+
onClick={() => setSelectedCurrency(currency)}
|
|
57
|
+
className={`flex cursor-pointer items-center justify-between gap-3 px-3 py-2.5 transition-colors ${
|
|
58
|
+
selectedCurrency === currency ? "bg-accent" : "hover:bg-accent/50"
|
|
59
|
+
}`}
|
|
60
|
+
>
|
|
61
|
+
<span className="text-foreground text-sm font-medium">{CURRENCY_NAMES[currency]}</span>
|
|
62
|
+
<span className="text-muted-foreground text-xs font-medium">{CURRENCY_SYMBOLS[currency]}</span>
|
|
63
|
+
</DropdownMenuItem>
|
|
64
|
+
{currency === "SOL" && <DropdownMenuSeparator key="separator" className="bg-border my-1" />}
|
|
65
|
+
</div>
|
|
66
|
+
))}
|
|
67
|
+
</DropdownMenuContent>
|
|
68
|
+
</DropdownMenu>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { B3_COIN_IMAGE_URL } from "@b3dotfun/sdk/shared/constants/currency";
|
|
4
|
+
import { cn } from "@b3dotfun/sdk/shared/utils";
|
|
5
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../../../global-account/react/components/ui/tooltip";
|
|
6
|
+
import { useCurrencyConversion } from "../hooks/useCurrencyConversion";
|
|
7
|
+
import { useCurrencyModalStore } from "../stores/currencyModalStore";
|
|
8
|
+
|
|
9
|
+
interface FormattedCurrencyProps {
|
|
10
|
+
amount: number;
|
|
11
|
+
showChange?: boolean;
|
|
12
|
+
showColor?: boolean;
|
|
13
|
+
className?: string;
|
|
14
|
+
subB3Icon?: boolean;
|
|
15
|
+
clickable?: boolean;
|
|
16
|
+
decimals?: number;
|
|
17
|
+
currency?: string; // Override currency (e.g., "ETH", "USDC", "B3")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function FormattedCurrency({
|
|
21
|
+
amount,
|
|
22
|
+
showChange = false,
|
|
23
|
+
showColor = false,
|
|
24
|
+
className,
|
|
25
|
+
subB3Icon = true,
|
|
26
|
+
clickable = true,
|
|
27
|
+
decimals,
|
|
28
|
+
currency,
|
|
29
|
+
}: FormattedCurrencyProps) {
|
|
30
|
+
const { formatCurrencyValue, formatTooltipValue, selectedCurrency, baseCurrency } = useCurrencyConversion();
|
|
31
|
+
const { openModal } = useCurrencyModalStore();
|
|
32
|
+
|
|
33
|
+
// Use passed currency or fall back to selected currency
|
|
34
|
+
const activeCurrency = currency || selectedCurrency;
|
|
35
|
+
|
|
36
|
+
const isPositive = amount >= 0;
|
|
37
|
+
|
|
38
|
+
// Get the formatted value (using absolute value for negative numbers when showing change)
|
|
39
|
+
const baseAmount = showChange ? Math.abs(amount) : amount;
|
|
40
|
+
|
|
41
|
+
// Use centralized formatting from hook with optional overrides
|
|
42
|
+
const formattedValue = formatCurrencyValue(baseAmount, {
|
|
43
|
+
decimals,
|
|
44
|
+
currency,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Generate tooltip using the centralized hook function
|
|
48
|
+
const baseTooltipValue = formatTooltipValue(amount, currency);
|
|
49
|
+
|
|
50
|
+
// Add change indicator if needed
|
|
51
|
+
const tooltipValue = showChange ? `${isPositive ? "+" : "-"}${baseTooltipValue}` : baseTooltipValue;
|
|
52
|
+
|
|
53
|
+
// Determine color class
|
|
54
|
+
let colorClass = "";
|
|
55
|
+
if (showColor) {
|
|
56
|
+
if (isPositive) {
|
|
57
|
+
colorClass = "text-green-400";
|
|
58
|
+
} else {
|
|
59
|
+
colorClass = "text-red-400";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Add change indicator
|
|
64
|
+
let displayValue = formattedValue;
|
|
65
|
+
if (showChange) {
|
|
66
|
+
if (isPositive) {
|
|
67
|
+
displayValue = `+${formattedValue}`;
|
|
68
|
+
} else {
|
|
69
|
+
displayValue = `-${formattedValue}`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const handleClick = () => {
|
|
74
|
+
if (clickable) {
|
|
75
|
+
openModal();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Tooltip>
|
|
81
|
+
<TooltipTrigger asChild>
|
|
82
|
+
<span
|
|
83
|
+
onClick={handleClick}
|
|
84
|
+
className={cn(
|
|
85
|
+
"inline-flex items-center gap-1 whitespace-nowrap",
|
|
86
|
+
colorClass,
|
|
87
|
+
className,
|
|
88
|
+
clickable && "cursor-pointer transition-opacity hover:opacity-80",
|
|
89
|
+
)}
|
|
90
|
+
>
|
|
91
|
+
{subB3Icon &&
|
|
92
|
+
(currency === baseCurrency || (!currency && activeCurrency === baseCurrency)) &&
|
|
93
|
+
baseCurrency === "B3"
|
|
94
|
+
? displayValue.split(" ")[0]
|
|
95
|
+
: displayValue}
|
|
96
|
+
{subB3Icon &&
|
|
97
|
+
(currency === baseCurrency || (!currency && activeCurrency === baseCurrency)) &&
|
|
98
|
+
baseCurrency === "B3" && (
|
|
99
|
+
<img src={B3_COIN_IMAGE_URL} className="inline-block h-4 w-4 align-middle" alt="B3 coin" />
|
|
100
|
+
)}
|
|
101
|
+
</span>
|
|
102
|
+
</TooltipTrigger>
|
|
103
|
+
<TooltipContent>{tooltipValue}</TooltipContent>
|
|
104
|
+
</Tooltip>
|
|
105
|
+
);
|
|
106
|
+
}
|