@ton/appkit-react 1.0.0-alpha.1 → 1.0.0-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/esm/components/shared/amount-preview/amount-preview.js +17 -0
- package/dist/esm/components/shared/amount-preview/amount-preview.js.map +1 -0
- package/dist/esm/components/shared/amount-preview/amount-preview.module.css +40 -0
- package/dist/esm/components/shared/amount-preview/index.js +9 -0
- package/dist/esm/components/shared/amount-preview/index.js.map +1 -0
- package/dist/esm/components/shared/flow-preview/flow-preview.js +24 -0
- package/dist/esm/components/shared/flow-preview/flow-preview.js.map +1 -0
- package/dist/esm/components/shared/flow-preview/flow-preview.module.css +37 -0
- package/dist/esm/components/shared/flow-preview/index.js +9 -0
- package/dist/esm/components/shared/flow-preview/index.js.map +1 -0
- package/dist/esm/components/ui/logo/logo.module.css +1 -3
- package/dist/esm/features/staking/components/staking-confirm-modal/index.js +9 -0
- package/dist/esm/features/staking/components/staking-confirm-modal/index.js.map +1 -0
- package/dist/esm/features/staking/components/staking-confirm-modal/staking-confirm-modal.js +46 -0
- package/dist/esm/features/staking/components/staking-confirm-modal/staking-confirm-modal.js.map +1 -0
- package/dist/esm/features/staking/components/staking-confirm-modal/staking-confirm-modal.module.css +11 -0
- package/dist/esm/features/staking/components/staking-widget-provider/staking-widget-provider.js +27 -4
- package/dist/esm/features/staking/components/staking-widget-provider/staking-widget-provider.js.map +1 -1
- package/dist/esm/features/staking/components/staking-widget-provider/use-staking-validation.js +12 -3
- package/dist/esm/features/staking/components/staking-widget-provider/use-staking-validation.js.map +1 -1
- package/dist/esm/features/staking/components/staking-widget-ui/staking-widget-ui.js +16 -4
- package/dist/esm/features/staking/components/staking-widget-ui/staking-widget-ui.js.map +1 -1
- package/dist/esm/features/staking/hooks/use-build-stake-transaction.js +2 -2
- package/dist/esm/features/staking/hooks/use-build-stake-transaction.js.map +1 -1
- package/dist/esm/features/staking/utils/map-staking-error.js +6 -4
- package/dist/esm/features/staking/utils/map-staking-error.js.map +1 -1
- package/dist/esm/features/swap/components/swap-confirm-modal/index.js +9 -0
- package/dist/esm/features/swap/components/swap-confirm-modal/index.js.map +1 -0
- package/dist/esm/features/swap/components/swap-confirm-modal/swap-confirm-modal.js +12 -0
- package/dist/esm/features/swap/components/swap-confirm-modal/swap-confirm-modal.js.map +1 -0
- package/dist/esm/features/swap/components/swap-confirm-modal/swap-confirm-modal.module.css +7 -0
- package/dist/esm/features/swap/components/swap-widget-provider/swap-widget-provider.js +28 -6
- package/dist/esm/features/swap/components/swap-widget-provider/swap-widget-provider.js.map +1 -1
- package/dist/esm/features/swap/components/swap-widget-provider/use-swap-validation.js +12 -3
- package/dist/esm/features/swap/components/swap-widget-provider/use-swap-validation.js.map +1 -1
- package/dist/esm/features/swap/components/swap-widget-ui/swap-widget-ui.js +16 -4
- package/dist/esm/features/swap/components/swap-widget-ui/swap-widget-ui.js.map +1 -1
- package/dist/esm/features/swap/utils/map-swap-error.js +5 -3
- package/dist/esm/features/swap/utils/map-swap-error.js.map +1 -1
- package/dist/esm/locales/en.js +9 -0
- package/dist/esm/locales/en.js.map +1 -1
- package/dist/esm/styles/index.css +2 -2
- package/dist/types/components/shared/amount-preview/amount-preview.d.ts +24 -0
- package/dist/types/components/shared/amount-preview/amount-preview.d.ts.map +1 -0
- package/dist/types/components/shared/amount-preview/index.d.ts +9 -0
- package/dist/types/components/shared/amount-preview/index.d.ts.map +1 -0
- package/dist/types/components/shared/flow-preview/flow-preview.d.ts +18 -0
- package/dist/types/components/shared/flow-preview/flow-preview.d.ts.map +1 -0
- package/dist/types/components/shared/flow-preview/index.d.ts +9 -0
- package/dist/types/components/shared/flow-preview/index.d.ts.map +1 -0
- package/dist/types/features/staking/components/staking-confirm-modal/index.d.ts +9 -0
- package/dist/types/features/staking/components/staking-confirm-modal/index.d.ts.map +1 -0
- package/dist/types/features/staking/components/staking-confirm-modal/staking-confirm-modal.d.ts +23 -0
- package/dist/types/features/staking/components/staking-confirm-modal/staking-confirm-modal.d.ts.map +1 -0
- package/dist/types/features/staking/components/staking-widget-provider/staking-widget-provider.d.ts.map +1 -1
- package/dist/types/features/staking/components/staking-widget-provider/use-staking-validation.d.ts +3 -1
- package/dist/types/features/staking/components/staking-widget-provider/use-staking-validation.d.ts.map +1 -1
- package/dist/types/features/staking/components/staking-widget-ui/staking-widget-ui.d.ts.map +1 -1
- package/dist/types/features/staking/hooks/use-build-stake-transaction.d.ts +3 -2
- package/dist/types/features/staking/hooks/use-build-stake-transaction.d.ts.map +1 -1
- package/dist/types/features/staking/utils/map-staking-error.d.ts +5 -3
- package/dist/types/features/staking/utils/map-staking-error.d.ts.map +1 -1
- package/dist/types/features/swap/components/swap-confirm-modal/index.d.ts +9 -0
- package/dist/types/features/swap/components/swap-confirm-modal/index.d.ts.map +1 -0
- package/dist/types/features/swap/components/swap-confirm-modal/swap-confirm-modal.d.ts +26 -0
- package/dist/types/features/swap/components/swap-confirm-modal/swap-confirm-modal.d.ts.map +1 -0
- package/dist/types/features/swap/components/swap-widget-provider/swap-widget-provider.d.ts.map +1 -1
- package/dist/types/features/swap/components/swap-widget-provider/use-swap-validation.d.ts +4 -1
- package/dist/types/features/swap/components/swap-widget-provider/use-swap-validation.d.ts.map +1 -1
- package/dist/types/features/swap/components/swap-widget-ui/swap-widget-ui.d.ts.map +1 -1
- package/dist/types/features/swap/utils/map-swap-error.d.ts +4 -2
- package/dist/types/features/swap/utils/map-swap-error.d.ts.map +1 -1
- package/dist/types/libs/i18n.d.ts +9 -0
- package/dist/types/libs/i18n.d.ts.map +1 -1
- package/dist/types/locales/en.d.ts +9 -0
- package/dist/types/locales/en.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/components/shared/amount-preview/amount-preview.tsx +74 -0
- package/src/components/shared/amount-preview/index.ts +9 -0
- package/src/components/shared/flow-preview/flow-preview.tsx +64 -0
- package/src/components/shared/flow-preview/index.ts +9 -0
- package/src/features/staking/components/staking-confirm-modal/index.ts +9 -0
- package/src/features/staking/components/staking-confirm-modal/staking-confirm-modal.tsx +121 -0
- package/src/features/staking/components/staking-widget-provider/staking-widget-provider.tsx +39 -4
- package/src/features/staking/components/staking-widget-provider/use-staking-validation.ts +14 -2
- package/src/features/staking/components/staking-widget-ui/staking-widget-ui.tsx +28 -3
- package/src/features/staking/hooks/use-build-stake-transaction.ts +7 -2
- package/src/features/staking/utils/map-staking-error.ts +6 -4
- package/src/features/swap/components/swap-confirm-modal/index.ts +9 -0
- package/src/features/swap/components/swap-confirm-modal/swap-confirm-modal.tsx +75 -0
- package/src/features/swap/components/swap-widget-provider/swap-widget-provider.tsx +40 -6
- package/src/features/swap/components/swap-widget-provider/use-swap-validation.ts +17 -2
- package/src/features/swap/components/swap-widget-ui/swap-widget-ui.tsx +30 -3
- package/src/features/swap/utils/map-swap-error.ts +5 -3
- package/src/locales/en.ts +9 -0
- package/dist/esm/tsconfig.build.tsbuildinfo +0 -1
package/dist/types/features/swap/components/swap-widget-provider/use-swap-validation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-swap-validation.d.ts","sourceRoot":"","sources":["../../../../../../src/features/swap/components/swap-widget-provider/use-swap-validation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"use-swap-validation.d.ts","sourceRoot":"","sources":["../../../../../../src/features/swap/components/swap-widget-provider/use-swap-validation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAIvE,UAAU,wBAAwB;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,aAAa,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,UAAU,EAAE,KAAK,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,KAAK,GAAG,IAAI,CAAC;IACxB,kBAAkB,EAAE,OAAO,CAAC;CAC/B;AAED,wBAAgB,iBAAiB,CAAC,EAC9B,UAAU,EACV,mBAAmB,EACnB,SAAS,EACT,OAAO,EACP,WAAW,EACX,KAAK,EACL,UAAU,EACV,SAAS,EACT,kBAAkB,GACrB,EAAE,wBAAwB;;;EA4B1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swap-widget-ui.d.ts","sourceRoot":"","sources":["../../../../../../src/features/swap/components/swap-widget-ui/swap-widget-ui.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,EAAE,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"swap-widget-ui.d.ts","sourceRoot":"","sources":["../../../../../../src/features/swap/components/swap-widget-ui/swap-widget-ui.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,EAAE,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAahD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI/D,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;AAE5E,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,qBAAqB,CAsKlD,CAAC"}
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
9
|
* Map a thrown swap error to an i18n key. Tries swap-specific codes first, falls back to the
|
|
10
|
-
* shared {@link mapDefiError} for base DeFi codes, and finally to
|
|
10
|
+
* shared {@link mapDefiError} for base DeFi codes, and finally to the caller-provided
|
|
11
|
+
* {@link fallback} (defaults to `swap.quoteError`, but send-time callers should pass
|
|
12
|
+
* `swap.sendFailed`).
|
|
11
13
|
*/
|
|
12
|
-
export declare const mapSwapError: (error: unknown) => string;
|
|
14
|
+
export declare const mapSwapError: (error: unknown, fallback?: string) => string;
|
|
13
15
|
//# sourceMappingURL=map-swap-error.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"map-swap-error.d.ts","sourceRoot":"","sources":["../../../../../src/features/swap/utils/map-swap-error.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH
|
|
1
|
+
{"version":3,"file":"map-swap-error.d.ts","sourceRoot":"","sources":["../../../../../src/features/swap/utils/map-swap-error.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,EAAE,WAAU,MAA0B,KAAG,MAenF,CAAC"}
|
|
@@ -66,6 +66,10 @@ export declare const i18n: rosetta.Rosetta<{
|
|
|
66
66
|
readonly provider: "Provider";
|
|
67
67
|
readonly save: "Save";
|
|
68
68
|
readonly minReceived: "Min Received";
|
|
69
|
+
readonly confirmTitle: "Confirm swap transaction";
|
|
70
|
+
readonly confirm: "Confirm";
|
|
71
|
+
readonly sendFailed: "Transaction failed";
|
|
72
|
+
readonly loading: "Loading...";
|
|
69
73
|
};
|
|
70
74
|
readonly lowBalance: {
|
|
71
75
|
readonly title: "Not enough TON";
|
|
@@ -100,6 +104,11 @@ export declare const i18n: rosetta.Rosetta<{
|
|
|
100
104
|
readonly provider: "Provider";
|
|
101
105
|
readonly settings: "Staking settings";
|
|
102
106
|
readonly save: "Save";
|
|
107
|
+
readonly confirmStakingTitle: "Confirm staking";
|
|
108
|
+
readonly confirmUnstakingTitle: "Confirm unstaking";
|
|
109
|
+
readonly confirm: "Confirm";
|
|
110
|
+
readonly sendFailed: "Transaction failed";
|
|
111
|
+
readonly loading: "Loading...";
|
|
103
112
|
};
|
|
104
113
|
}>;
|
|
105
114
|
export { en };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/libs/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,MAAM,eAAe,CAAC;AAE/B,eAAO,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/libs/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,MAAM,eAAe,CAAC;AAE/B,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAkB,CAAC;AACpC,OAAO,EAAE,EAAE,EAAE,CAAC;AACd,eAAO,MAAM,eAAe,OAAO,CAAC;AAIpC,MAAM,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC;AAC/B,MAAM,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC"}
|
|
@@ -64,6 +64,10 @@ declare const _default: {
|
|
|
64
64
|
readonly provider: "Provider";
|
|
65
65
|
readonly save: "Save";
|
|
66
66
|
readonly minReceived: "Min Received";
|
|
67
|
+
readonly confirmTitle: "Confirm swap transaction";
|
|
68
|
+
readonly confirm: "Confirm";
|
|
69
|
+
readonly sendFailed: "Transaction failed";
|
|
70
|
+
readonly loading: "Loading...";
|
|
67
71
|
};
|
|
68
72
|
readonly lowBalance: {
|
|
69
73
|
readonly title: "Not enough TON";
|
|
@@ -98,6 +102,11 @@ declare const _default: {
|
|
|
98
102
|
readonly provider: "Provider";
|
|
99
103
|
readonly settings: "Staking settings";
|
|
100
104
|
readonly save: "Save";
|
|
105
|
+
readonly confirmStakingTitle: "Confirm staking";
|
|
106
|
+
readonly confirmUnstakingTitle: "Confirm unstaking";
|
|
107
|
+
readonly confirm: "Confirm";
|
|
108
|
+
readonly sendFailed: "Transaction failed";
|
|
109
|
+
readonly loading: "Loading...";
|
|
101
110
|
};
|
|
102
111
|
};
|
|
103
112
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../../src/locales/en.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG
|
|
1
|
+
{"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../../src/locales/en.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,wBA0HW"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ton/appkit-react",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/ton-
|
|
7
|
+
"url": "https://github.com/ton-org/kit"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist/**",
|
|
@@ -33,27 +33,27 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"clsx": "2.1.1",
|
|
36
|
+
"clsx": "^2.1.1",
|
|
37
37
|
"radix-ui": "^1.4.3",
|
|
38
38
|
"rosetta": "1.1.0",
|
|
39
|
-
"@ton/appkit": "1.0.0-alpha.
|
|
39
|
+
"@ton/appkit": "1.0.0-alpha.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@storybook/addon-docs": "10.
|
|
43
|
-
"@storybook/react": "10.
|
|
44
|
-
"@storybook/react-vite": "10.
|
|
42
|
+
"@storybook/addon-docs": "10.4.1",
|
|
43
|
+
"@storybook/react": "10.4.1",
|
|
44
|
+
"@storybook/react-vite": "10.4.1",
|
|
45
45
|
"@storybook/test": "^8.6.15",
|
|
46
|
-
"@tanstack/react-query": "5.
|
|
47
|
-
"@tonconnect/ui-react": "2.5.0-alpha.0",
|
|
46
|
+
"@tanstack/react-query": "^5.100.14",
|
|
47
|
+
"@tonconnect/ui-react": "^2.5.0-alpha.0",
|
|
48
48
|
"@types/react": "19.2.3",
|
|
49
49
|
"@types/react-dom": "19.2.3",
|
|
50
|
+
"buffer": "^6.0.3",
|
|
50
51
|
"copyfiles": "2.4.1",
|
|
51
52
|
"react": "19.2.3",
|
|
52
53
|
"react-dom": "19.2.3",
|
|
53
|
-
"storybook": "10.
|
|
54
|
-
"typescript": "
|
|
55
|
-
"vite": "
|
|
56
|
-
"vite-plugin-node-polyfills": "^0.26.0"
|
|
54
|
+
"storybook": "10.4.1",
|
|
55
|
+
"typescript": "5.9.3",
|
|
56
|
+
"vite": "8.0.14"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"@tanstack/react-query": ">=5.0.0",
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) TonTech.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { FC, ComponentProps } from 'react';
|
|
10
|
+
import { calcFiatValue, formatLargeValue } from '@ton/appkit';
|
|
11
|
+
import clsx from 'clsx';
|
|
12
|
+
|
|
13
|
+
import { Logo } from '../../ui/logo';
|
|
14
|
+
import { TonIconCircle } from '../../ui/icons';
|
|
15
|
+
import type { AppkitUIToken } from '../../../types/appkit-ui-token';
|
|
16
|
+
import { getDisplayAmount } from '../../../features/swap/utils/get-display-amount';
|
|
17
|
+
import styles from './amount-preview.module.css';
|
|
18
|
+
|
|
19
|
+
export interface AmountPreviewProps extends ComponentProps<'div'> {
|
|
20
|
+
/** Raw token amount to display (decimal string). */
|
|
21
|
+
amount: string;
|
|
22
|
+
/** Token whose logo and symbol are shown alongside the amount. */
|
|
23
|
+
token?: AppkitUIToken;
|
|
24
|
+
/** Fiat currency symbol, e.g. "$". */
|
|
25
|
+
fiatSymbol?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Relative fiat delta to render after the fiat value, e.g. -0.0025 → "(-0.25%)".
|
|
28
|
+
* Typically computed by a parent that knows both legs of a flow.
|
|
29
|
+
*/
|
|
30
|
+
fiatDelta?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const formatFiatDelta = (delta: number): string => {
|
|
34
|
+
const sign = delta > 0 ? '+' : '';
|
|
35
|
+
return `(${sign}${(delta * 100).toFixed(2)}%)`;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const AmountPreview: FC<AmountPreviewProps> = ({
|
|
39
|
+
amount,
|
|
40
|
+
token,
|
|
41
|
+
fiatSymbol = '$',
|
|
42
|
+
fiatDelta,
|
|
43
|
+
className,
|
|
44
|
+
...props
|
|
45
|
+
}) => {
|
|
46
|
+
const displayAmount = getDisplayAmount(amount, token?.decimals);
|
|
47
|
+
const fiatValue = token?.rate ? formatLargeValue(calcFiatValue(amount || '0', token.rate), 2, 2) : null;
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div className={clsx(styles.container, className)} {...props}>
|
|
51
|
+
<div className={styles.amountRow}>
|
|
52
|
+
<span className={styles.amount}>{displayAmount}</span>
|
|
53
|
+
{token && (
|
|
54
|
+
<span className={styles.tokenTag}>
|
|
55
|
+
{token.address === 'ton' ? (
|
|
56
|
+
<TonIconCircle size={24} />
|
|
57
|
+
) : (
|
|
58
|
+
<Logo size={24} src={token.logo} fallback={token.symbol?.[0] ?? '?'} alt={token.symbol} />
|
|
59
|
+
)}
|
|
60
|
+
<span className={styles.symbol}>{token.symbol}</span>
|
|
61
|
+
</span>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
{fiatValue !== null && (
|
|
65
|
+
<div className={styles.fiat}>
|
|
66
|
+
<span>
|
|
67
|
+
{fiatSymbol} {fiatValue}
|
|
68
|
+
</span>
|
|
69
|
+
{fiatDelta !== undefined && <span className={styles.fiatDelta}>{formatFiatDelta(fiatDelta)}</span>}
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) TonTech.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { FC, ComponentProps } from 'react';
|
|
10
|
+
import { calcFiatValue } from '@ton/appkit';
|
|
11
|
+
import clsx from 'clsx';
|
|
12
|
+
|
|
13
|
+
import { ChevronDownIcon } from '../../ui/icons';
|
|
14
|
+
import { AmountPreview } from '../amount-preview';
|
|
15
|
+
import type { AppkitUIToken } from '../../../types/appkit-ui-token';
|
|
16
|
+
import styles from './flow-preview.module.css';
|
|
17
|
+
|
|
18
|
+
export interface FlowPreviewProps extends ComponentProps<'div'> {
|
|
19
|
+
fromAmount: string;
|
|
20
|
+
toAmount: string;
|
|
21
|
+
fromToken?: AppkitUIToken;
|
|
22
|
+
toToken?: AppkitUIToken;
|
|
23
|
+
fiatSymbol?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Returns the relative fiat delta between paying `fromFiat` and receiving `toFiat`,
|
|
28
|
+
* or `undefined` when either side lacks fiat data.
|
|
29
|
+
*/
|
|
30
|
+
const calcFiatDelta = (fromFiat: string, toFiat: string): number | undefined => {
|
|
31
|
+
const from = parseFloat(fromFiat);
|
|
32
|
+
const to = parseFloat(toFiat);
|
|
33
|
+
if (!from || !to) return undefined;
|
|
34
|
+
return (to - from) / from;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const FlowPreview: FC<FlowPreviewProps> = ({
|
|
38
|
+
fromAmount,
|
|
39
|
+
toAmount,
|
|
40
|
+
fromToken,
|
|
41
|
+
toToken,
|
|
42
|
+
fiatSymbol = '$',
|
|
43
|
+
className,
|
|
44
|
+
...props
|
|
45
|
+
}) => {
|
|
46
|
+
const fromFiat = calcFiatValue(fromAmount || '0', fromToken?.rate);
|
|
47
|
+
const toFiat = calcFiatValue(toAmount || '0', toToken?.rate);
|
|
48
|
+
const fiatDelta = calcFiatDelta(fromFiat, toFiat);
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className={clsx(styles.container, className)} {...props}>
|
|
52
|
+
<AmountPreview amount={fromAmount} token={fromToken} fiatSymbol={fiatSymbol} />
|
|
53
|
+
|
|
54
|
+
<div className={styles.separator}>
|
|
55
|
+
<span className={styles.separatorLine} />
|
|
56
|
+
<span className={styles.arrowBadge}>
|
|
57
|
+
<ChevronDownIcon size={16} />
|
|
58
|
+
</span>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<AmountPreview amount={toAmount} token={toToken} fiatSymbol={fiatSymbol} fiatDelta={fiatDelta} />
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) TonTech.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { FC } from 'react';
|
|
10
|
+
import type {
|
|
11
|
+
JettonInfo,
|
|
12
|
+
Network,
|
|
13
|
+
StakingProviderInfo,
|
|
14
|
+
StakingProviderMetadata,
|
|
15
|
+
StakingQuote,
|
|
16
|
+
StakingQuoteDirection,
|
|
17
|
+
StakingTokenInfo,
|
|
18
|
+
} from '@ton/appkit';
|
|
19
|
+
|
|
20
|
+
import { Modal } from '../../../../components/ui/modal/modal';
|
|
21
|
+
import { Button } from '../../../../components/ui/button';
|
|
22
|
+
import { AmountPreview } from '../../../../components/shared/amount-preview';
|
|
23
|
+
import { FlowPreview } from '../../../../components/shared/flow-preview';
|
|
24
|
+
import type { AppkitUIToken } from '../../../../types/appkit-ui-token';
|
|
25
|
+
import { useJettonInfo } from '../../../jettons';
|
|
26
|
+
import { useI18n } from '../../../settings/hooks/use-i18n';
|
|
27
|
+
import { StakingInfo } from '../staking-info';
|
|
28
|
+
import styles from './staking-confirm-modal.module.css';
|
|
29
|
+
|
|
30
|
+
export interface StakingConfirmModalProps {
|
|
31
|
+
open: boolean;
|
|
32
|
+
onClose: () => void;
|
|
33
|
+
onConfirm: () => void;
|
|
34
|
+
direction: StakingQuoteDirection;
|
|
35
|
+
network: Network | undefined;
|
|
36
|
+
quote: StakingQuote | undefined;
|
|
37
|
+
providerInfo: StakingProviderInfo | undefined;
|
|
38
|
+
providerMetadata: StakingProviderMetadata | undefined;
|
|
39
|
+
isProviderInfoLoading: boolean;
|
|
40
|
+
isQuoteLoading: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Adapter from staking-domain token shape (`StakingTokenInfo`) to the shared
|
|
45
|
+
* `AppkitUIToken` shape consumed by AmountPreview/FlowPreview. `name` is taken
|
|
46
|
+
* from the resolved jetton metadata when available, falling back to ticker.
|
|
47
|
+
*/
|
|
48
|
+
const toUIToken = (
|
|
49
|
+
token: StakingTokenInfo | undefined,
|
|
50
|
+
jettonInfo: JettonInfo | null | undefined,
|
|
51
|
+
network: Network | undefined,
|
|
52
|
+
): AppkitUIToken | undefined => {
|
|
53
|
+
if (!token || !network) return undefined;
|
|
54
|
+
return {
|
|
55
|
+
symbol: token.ticker,
|
|
56
|
+
name: jettonInfo?.name ?? token.ticker,
|
|
57
|
+
decimals: token.decimals,
|
|
58
|
+
address: token.address,
|
|
59
|
+
logo: token.address === 'ton' ? undefined : jettonInfo?.image,
|
|
60
|
+
network,
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const StakingConfirmModal: FC<StakingConfirmModalProps> = ({
|
|
65
|
+
open,
|
|
66
|
+
onClose,
|
|
67
|
+
onConfirm,
|
|
68
|
+
direction,
|
|
69
|
+
network,
|
|
70
|
+
quote,
|
|
71
|
+
providerInfo,
|
|
72
|
+
providerMetadata,
|
|
73
|
+
isProviderInfoLoading,
|
|
74
|
+
isQuoteLoading,
|
|
75
|
+
}) => {
|
|
76
|
+
const { t } = useI18n();
|
|
77
|
+
|
|
78
|
+
const stakeAddress = providerMetadata?.stakeToken.address;
|
|
79
|
+
const receiveAddress = providerMetadata?.receiveToken?.address;
|
|
80
|
+
|
|
81
|
+
const { data: stakeJettonInfo } = useJettonInfo({
|
|
82
|
+
address: stakeAddress,
|
|
83
|
+
query: { enabled: !!stakeAddress && stakeAddress !== 'ton' },
|
|
84
|
+
});
|
|
85
|
+
const { data: receiveJettonInfo } = useJettonInfo({
|
|
86
|
+
address: receiveAddress,
|
|
87
|
+
query: { enabled: !!receiveAddress && receiveAddress !== 'ton' },
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const stakeToken = toUIToken(providerMetadata?.stakeToken, stakeJettonInfo, network);
|
|
91
|
+
const receiveToken = toUIToken(providerMetadata?.receiveToken, receiveJettonInfo, network);
|
|
92
|
+
|
|
93
|
+
const title = direction === 'stake' ? t('staking.confirmStakingTitle') : t('staking.confirmUnstakingTitle');
|
|
94
|
+
|
|
95
|
+
const amountIn = quote?.amountIn ?? '0';
|
|
96
|
+
const amountOut = quote?.amountOut ?? '0';
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<Modal open={open} onOpenChange={(isOpen) => !isOpen && onClose()} title={title}>
|
|
100
|
+
{direction === 'stake' ? (
|
|
101
|
+
<AmountPreview className={styles.singleAmount} amount={amountIn} token={stakeToken} />
|
|
102
|
+
) : (
|
|
103
|
+
<FlowPreview fromAmount={amountIn} toAmount={amountOut} fromToken={receiveToken} toToken={stakeToken} />
|
|
104
|
+
)}
|
|
105
|
+
|
|
106
|
+
<StakingInfo
|
|
107
|
+
className={styles.info}
|
|
108
|
+
quote={quote}
|
|
109
|
+
isQuoteLoading={isQuoteLoading}
|
|
110
|
+
providerInfo={providerInfo}
|
|
111
|
+
providerMetadata={providerMetadata}
|
|
112
|
+
isProviderInfoLoading={isProviderInfoLoading}
|
|
113
|
+
direction={direction}
|
|
114
|
+
/>
|
|
115
|
+
|
|
116
|
+
<Button className={styles.confirmButton} variant="fill" size="l" fullWidth onClick={onConfirm}>
|
|
117
|
+
{t('staking.confirm')}
|
|
118
|
+
</Button>
|
|
119
|
+
</Modal>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { createContext, useCallback, useContext, useMemo, useState } from 'react';
|
|
9
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
10
10
|
import type { FC, PropsWithChildren } from 'react';
|
|
11
11
|
import type { Network, StakingProvider, StakingQuoteDirection, TonShortfall } from '@ton/appkit';
|
|
12
12
|
import {
|
|
@@ -224,8 +224,39 @@ export const StakingWidgetProvider: FC<StakingProviderProps> = ({ children, netw
|
|
|
224
224
|
query: { refetchInterval: 5000 },
|
|
225
225
|
});
|
|
226
226
|
|
|
227
|
-
const {
|
|
228
|
-
|
|
227
|
+
const {
|
|
228
|
+
mutateAsync: buildTransaction,
|
|
229
|
+
isPending: isBuildingTransaction,
|
|
230
|
+
error: buildError,
|
|
231
|
+
reset: resetBuild,
|
|
232
|
+
} = useBuildStakeTransaction({ mutation: { networkMode: 'always' } });
|
|
233
|
+
const {
|
|
234
|
+
mutateAsync: sendTransaction,
|
|
235
|
+
isPending: isSendingPending,
|
|
236
|
+
error: sendMutationError,
|
|
237
|
+
reset: resetSend,
|
|
238
|
+
} = useSendTransaction({ mutation: { networkMode: 'always' } });
|
|
239
|
+
const isSendingTransaction = isBuildingTransaction || isSendingPending;
|
|
240
|
+
const sendError = sendMutationError ?? buildError;
|
|
241
|
+
|
|
242
|
+
const resetSendError = useCallback(() => {
|
|
243
|
+
resetBuild();
|
|
244
|
+
resetSend();
|
|
245
|
+
}, [resetBuild, resetSend]);
|
|
246
|
+
|
|
247
|
+
// Drop the previous send error when the user changes anything that invalidates it —
|
|
248
|
+
// the next attempt is conceptually a new stake, no need to keep the old message on screen.
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
resetSendError();
|
|
251
|
+
}, [direction, amount, isReversed, resetSendError]);
|
|
252
|
+
|
|
253
|
+
// Auto-clear the send error after a short delay so a stale failure doesn't linger in the
|
|
254
|
+
// submit button — the user is expected to act on it within seconds or move on.
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (!sendError) return;
|
|
257
|
+
const id = setTimeout(resetSendError, 5000);
|
|
258
|
+
return () => clearTimeout(id);
|
|
259
|
+
}, [sendError, resetSendError]);
|
|
229
260
|
|
|
230
261
|
const amountDecimals = useMemo(() => {
|
|
231
262
|
const unstakeDecimals = isReversed
|
|
@@ -256,7 +287,10 @@ export const StakingWidgetProvider: FC<StakingProviderProps> = ({ children, netw
|
|
|
256
287
|
data: quote,
|
|
257
288
|
isFetching: isQuoteLoading,
|
|
258
289
|
error: quoteError,
|
|
259
|
-
} = useStakingQuote({
|
|
290
|
+
} = useStakingQuote({
|
|
291
|
+
...quoteParamsDebounced,
|
|
292
|
+
query: { enabled: isNetworkSupported, networkMode: 'always', retry: false, gcTime: 0 },
|
|
293
|
+
});
|
|
260
294
|
|
|
261
295
|
const reversedAmount = useMemo(() => {
|
|
262
296
|
if (direction === 'unstake' && isReversed) return quote?.amountIn || '0';
|
|
@@ -337,6 +371,7 @@ export const StakingWidgetProvider: FC<StakingProviderProps> = ({ children, netw
|
|
|
337
371
|
amountDebounced: quoteParamsDebounced.amount || '',
|
|
338
372
|
balance,
|
|
339
373
|
quoteError,
|
|
374
|
+
sendError,
|
|
340
375
|
direction,
|
|
341
376
|
stakedBalance: stakedBalanceData?.stakedBalance,
|
|
342
377
|
quote,
|
|
@@ -18,6 +18,8 @@ interface UseStakingValidationOptions {
|
|
|
18
18
|
balance: string | undefined;
|
|
19
19
|
quote?: StakingQuote;
|
|
20
20
|
quoteError: Error | null;
|
|
21
|
+
/** Error from the build/send mutation. Takes priority over input validation but does not block submit. */
|
|
22
|
+
sendError: Error | null;
|
|
21
23
|
direction: StakingQuoteDirection;
|
|
22
24
|
amountDecimals?: number;
|
|
23
25
|
isReversed: boolean;
|
|
@@ -31,13 +33,16 @@ export const useStakingValidation = ({
|
|
|
31
33
|
balance,
|
|
32
34
|
quote,
|
|
33
35
|
quoteError,
|
|
36
|
+
sendError,
|
|
34
37
|
direction,
|
|
35
38
|
amountDecimals,
|
|
36
39
|
isReversed,
|
|
37
40
|
stakedBalance,
|
|
38
41
|
isNetworkSupported,
|
|
39
42
|
}: UseStakingValidationOptions) => {
|
|
40
|
-
|
|
43
|
+
// Input-side validation that blocks submission. `sendError` is intentionally NOT considered
|
|
44
|
+
// here — a previous failed attempt shouldn't lock the button against a retry.
|
|
45
|
+
const blockingError: string | null = useMemo(() => {
|
|
41
46
|
if (!isNetworkSupported) return 'defi.unsupportedNetwork';
|
|
42
47
|
|
|
43
48
|
if ((parseFloat(amount) || 0) <= 0) return null;
|
|
@@ -73,7 +78,14 @@ export const useStakingValidation = ({
|
|
|
73
78
|
amountDecimals,
|
|
74
79
|
]);
|
|
75
80
|
|
|
76
|
-
|
|
81
|
+
// The user-visible error: build/send failure (most recent user action) wins over background
|
|
82
|
+
// validation noise; falls back to validation when no send error is active.
|
|
83
|
+
const error = useMemo<string | null>(() => {
|
|
84
|
+
if (sendError) return mapStakingError(sendError, 'staking.sendFailed');
|
|
85
|
+
return blockingError;
|
|
86
|
+
}, [sendError, blockingError]);
|
|
87
|
+
|
|
88
|
+
const canSubmit = (parseFloat(amount) || 0) > 0 && blockingError === null && quote !== undefined;
|
|
77
89
|
|
|
78
90
|
return { error, canSubmit };
|
|
79
91
|
};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { useMemo, useState } from 'react';
|
|
9
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
10
10
|
import type { ComponentProps, FC, ReactNode } from 'react';
|
|
11
11
|
import type { StakingQuoteDirection } from '@ton/appkit';
|
|
12
12
|
import clsx from 'clsx';
|
|
@@ -15,6 +15,7 @@ import { CenteredAmountInput } from '../../../../components/ui/centered-amount-i
|
|
|
15
15
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../../../../components/ui/tabs';
|
|
16
16
|
import { useI18n } from '../../../settings/hooks/use-i18n';
|
|
17
17
|
import { StakingBalanceBlock } from '../staking-balance-block';
|
|
18
|
+
import { StakingConfirmModal } from '../staking-confirm-modal';
|
|
18
19
|
import { StakingInfo } from '../staking-info';
|
|
19
20
|
import { SelectUnstakeMode } from '../select-unstake-mode';
|
|
20
21
|
import { StakingSettingsModal } from '../staking-settings-modal';
|
|
@@ -66,14 +67,25 @@ export const StakingWidgetUI: FC<StakingWidgetRenderProps> = ({
|
|
|
66
67
|
const { t } = useI18n();
|
|
67
68
|
|
|
68
69
|
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
|
70
|
+
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
|
|
69
71
|
|
|
70
72
|
const receiveToken = providerMetadata?.receiveToken;
|
|
71
73
|
const stakeToken = providerMetadata?.stakeToken;
|
|
72
74
|
|
|
73
75
|
const buttonText = useMemo(() => {
|
|
76
|
+
if (isSendingTransaction || isQuoteLoading) return t('staking.loading');
|
|
74
77
|
if (error) return t(error);
|
|
75
78
|
return direction === 'stake' ? t('staking.continue') : t('staking.unstake');
|
|
76
|
-
}, [error, direction, t]);
|
|
79
|
+
}, [isSendingTransaction, isQuoteLoading, error, direction, t]);
|
|
80
|
+
|
|
81
|
+
// Close the modal immediately; the build/send result (including errors) is surfaced
|
|
82
|
+
// back in the widget's main button via the `error` from the provider.
|
|
83
|
+
const handleConfirm = useCallback(() => {
|
|
84
|
+
setIsConfirmOpen(false);
|
|
85
|
+
sendTransaction().catch(() => {
|
|
86
|
+
// Error is captured by the mutation and shown through the validator's `error` output.
|
|
87
|
+
});
|
|
88
|
+
}, [sendTransaction]);
|
|
77
89
|
|
|
78
90
|
const submitActions: ReactNode = (
|
|
79
91
|
<div className={styles.actions}>
|
|
@@ -82,7 +94,7 @@ export const StakingWidgetUI: FC<StakingWidgetRenderProps> = ({
|
|
|
82
94
|
size="l"
|
|
83
95
|
fullWidth
|
|
84
96
|
disabled={!canSubmit || isQuoteLoading || isSendingTransaction}
|
|
85
|
-
onClick={
|
|
97
|
+
onClick={() => setIsConfirmOpen(true)}
|
|
86
98
|
>
|
|
87
99
|
{buttonText}
|
|
88
100
|
</ButtonWithConnect>
|
|
@@ -195,6 +207,19 @@ export const StakingWidgetUI: FC<StakingWidgetRenderProps> = ({
|
|
|
195
207
|
onProviderChange={setStakingProviderId}
|
|
196
208
|
network={network}
|
|
197
209
|
/>
|
|
210
|
+
|
|
211
|
+
<StakingConfirmModal
|
|
212
|
+
open={isConfirmOpen}
|
|
213
|
+
onClose={() => setIsConfirmOpen(false)}
|
|
214
|
+
onConfirm={handleConfirm}
|
|
215
|
+
direction={direction}
|
|
216
|
+
network={network}
|
|
217
|
+
quote={quote}
|
|
218
|
+
providerInfo={providerInfo}
|
|
219
|
+
providerMetadata={providerMetadata}
|
|
220
|
+
isProviderInfoLoading={isProviderInfoLoading}
|
|
221
|
+
isQuoteLoading={isQuoteLoading}
|
|
222
|
+
/>
|
|
198
223
|
</div>
|
|
199
224
|
);
|
|
200
225
|
};
|
|
@@ -11,12 +11,15 @@ import { buildStakeTransactionMutationOptions } from '@ton/appkit/queries';
|
|
|
11
11
|
import type {
|
|
12
12
|
BuildStakeTransactionData,
|
|
13
13
|
BuildStakeTransactionErrorType,
|
|
14
|
+
BuildStakeTransactionMutationOptions,
|
|
14
15
|
BuildStakeTransactionVariables,
|
|
15
16
|
} from '@ton/appkit/queries';
|
|
16
17
|
|
|
17
18
|
import { useAppKit } from '../../settings';
|
|
18
19
|
import { useMutation } from '../../../libs/query';
|
|
19
20
|
|
|
21
|
+
export type UseBuildStakeTransactionParameters<context = unknown> = BuildStakeTransactionMutationOptions<context>;
|
|
22
|
+
|
|
20
23
|
export type UseBuildStakeTransactionReturnType<context = unknown> = UseMutationResult<
|
|
21
24
|
BuildStakeTransactionData,
|
|
22
25
|
BuildStakeTransactionErrorType,
|
|
@@ -27,7 +30,9 @@ export type UseBuildStakeTransactionReturnType<context = unknown> = UseMutationR
|
|
|
27
30
|
/**
|
|
28
31
|
* Hook to build stake transaction
|
|
29
32
|
*/
|
|
30
|
-
export const useBuildStakeTransaction = <context = unknown>(
|
|
33
|
+
export const useBuildStakeTransaction = <context = unknown>(
|
|
34
|
+
parameters?: UseBuildStakeTransactionParameters<context>,
|
|
35
|
+
): UseBuildStakeTransactionReturnType<context> => {
|
|
31
36
|
const appKit = useAppKit();
|
|
32
|
-
return useMutation(buildStakeTransactionMutationOptions<context>(appKit));
|
|
37
|
+
return useMutation(buildStakeTransactionMutationOptions<context>(appKit, parameters));
|
|
33
38
|
};
|