diff --git a/nym-wallet/src/components/FeeWarning.tsx b/nym-wallet/src/components/FeeWarning.tsx
new file mode 100644
index 0000000000..b26a7f8369
--- /dev/null
+++ b/nym-wallet/src/components/FeeWarning.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { Warning } from '@mui/icons-material';
+import { FeeDetails } from '@nymproject/types';
+import { Alert, AlertTitle } from '@mui/material';
+
+export const FeeWarning = ({ fee, amount }: { fee: FeeDetails; amount: number }) => {
+ if (fee.amount && +fee.amount.amount > amount) {
+ return (
+ }>
+ Warning: fees are greater than the reward
+ The fees for redeeming rewards will cost more than the rewards. Are you sure you want to continue?
+
+ );
+ }
+ return null;
+};
diff --git a/nym-wallet/src/components/Rewards/CompoundModal.tsx b/nym-wallet/src/components/Rewards/CompoundModal.tsx
index 7b90e3a01b..cc779dc1db 100644
--- a/nym-wallet/src/components/Rewards/CompoundModal.tsx
+++ b/nym-wallet/src/components/Rewards/CompoundModal.tsx
@@ -1,13 +1,12 @@
import React, { useEffect } from 'react';
-import { Alert, AlertTitle, Stack, Typography } from '@mui/material';
-import WarningIcon from '@mui/icons-material/Warning';
+import { Stack, Typography } from '@mui/material';
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
import { simulateCompoundDelgatorReward, simulateVestingCompoundDelgatorReward } from 'src/requests';
-import { isGreaterThan } from 'src/utils';
import { useGetFee } from 'src/hooks/useGetFee';
import { SimpleModal } from '../Modals/SimpleModal';
import { ModalFee } from '../Modals/ModalFee';
import { FeeDetails } from '@nymproject/types';
+import { FeeWarning } from '../FeeWarning';
export const CompoundModal: React.FC<{
open: boolean;
@@ -57,13 +56,16 @@ export const CompoundModal: React.FC<{
Rewards will be transferred to account you are logged in with now
+
+ theme.palette.nym.fee}>
+ Est. fee for this transaction:
+
+ theme.palette.nym.fee}>
+ {fee} {currency}
+
+
+ {fee && }
- {fee?.amount && isGreaterThan(+fee.amount.amount, amount) && (
- }>
- Warning: fees are greater than the reward
- The fees for redeeming rewards will cost more than the rewards. Are you sure you want to continue?
-
- )}
);
};
diff --git a/nym-wallet/src/components/Rewards/RedeemModal.tsx b/nym-wallet/src/components/Rewards/RedeemModal.tsx
index 8ac05d7ab3..0bb317c093 100644
--- a/nym-wallet/src/components/Rewards/RedeemModal.tsx
+++ b/nym-wallet/src/components/Rewards/RedeemModal.tsx
@@ -1,13 +1,12 @@
import React, { useEffect } from 'react';
-import { Alert, AlertTitle, Stack, Typography } from '@mui/material';
+import { Stack, Typography } from '@mui/material';
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
-import WarningIcon from '@mui/icons-material/Warning';
-import { simulateClaimDelgatorReward, simulateVestingClaimDelgatorReward } from 'src/requests';
-import { isGreaterThan } from 'src/utils';
-import { useGetFee } from 'src/hooks/useGetFee';
-import { SimpleModal } from '../Modals/SimpleModal';
-import { ModalFee } from '../Modals/ModalFee';
import { FeeDetails } from '@nymproject/types';
+import { useGetFee } from 'src/hooks/useGetFee';
+import { simulateClaimDelgatorReward, simulateVestingClaimDelgatorReward } from 'src/requests';
+import { ModalFee } from '../Modals/ModalFee';
+import { SimpleModal } from '../Modals/SimpleModal';
+import { FeeWarning } from '../FeeWarning';
export const RedeemModal: React.FC<{
open: boolean;
@@ -58,13 +57,16 @@ export const RedeemModal: React.FC<{
Rewards will be transferred to account you are logged in with now
+
+ theme.palette.nym.fee}>
+ Est. fee for this transaction:
+
+ theme.palette.nym.fee}>
+ {fee} {currency}
+
+
+ {fee && }
- {fee?.amount && isGreaterThan(+fee.amount.amount, amount) && (
- }>
- Warning: fees are greater than the reward
- The fees for redeeming rewards will cost more than the rewards. Are you sure you want to continue?
-
- )}
);
};
diff --git a/nym-wallet/src/context/mocks/main.tsx b/nym-wallet/src/context/mocks/main.tsx
index 5fefc649fb..672b3e0123 100644
--- a/nym-wallet/src/context/mocks/main.tsx
+++ b/nym-wallet/src/context/mocks/main.tsx
@@ -32,6 +32,7 @@ export const MockMainContextProvider: FC<{}> = ({ children }) => {
clearBalance: () => undefined,
fetchBalance: async () => undefined,
fetchTokenAllocation: async () => undefined,
+ refreshBalances: async () => {},
},
showAdmin: false,
showTerminal: false,
diff --git a/nym-wallet/src/hooks/useGetBalance.ts b/nym-wallet/src/hooks/useGetBalance.ts
index 3c8015fe8f..56118351e5 100644
--- a/nym-wallet/src/hooks/useGetBalance.ts
+++ b/nym-wallet/src/hooks/useGetBalance.ts
@@ -35,6 +35,7 @@ export type TUseuserBalance = {
fetchTokenAllocation: () => Promise;
clearBalance: () => void;
clearAll: () => void;
+ refreshBalances: () => Promise;
};
export const useGetBalance = (clientDetails?: Account): TUseuserBalance => {
@@ -108,8 +109,8 @@ export const useGetBalance = (clientDetails?: Account): TUseuserBalance => {
clearOriginalVesting();
};
- const handleRefresh = async (addr?: string) => {
- if (addr) {
+ const refreshBalances = async () => {
+ if (clientDetails?.client_address) {
await fetchBalance();
await fetchTokenAllocation();
} else {
@@ -118,7 +119,7 @@ export const useGetBalance = (clientDetails?: Account): TUseuserBalance => {
};
useEffect(() => {
- handleRefresh(clientDetails?.client_address);
+ refreshBalances();
}, [clientDetails]);
return {
@@ -133,5 +134,6 @@ export const useGetBalance = (clientDetails?: Account): TUseuserBalance => {
clearBalance,
clearAll,
fetchTokenAllocation,
+ refreshBalances,
};
};
diff --git a/nym-wallet/src/pages/balance/components/TransferModal.tsx b/nym-wallet/src/pages/balance/components/TransferModal.tsx
new file mode 100644
index 0000000000..8312b31ad0
--- /dev/null
+++ b/nym-wallet/src/pages/balance/components/TransferModal.tsx
@@ -0,0 +1,101 @@
+import React, { useContext, useEffect, useState } from 'react';
+import { Alert, Box, CircularProgress } from '@mui/material';
+import { FeeDetails } from '@nymproject/types';
+import { SimpleModal } from 'src/components/Modals/SimpleModal';
+import { ModalListItem } from 'src/components/Modals/ModalListItem';
+import { AppContext, urls } from 'src/context';
+import { FeeWarning } from 'src/components/FeeWarning';
+import { withdrawVestedCoins } from 'src/requests';
+import { Console } from 'src/utils/console';
+import { simulateWithdrawVestedCoins } from 'src/requests/simulate';
+import { SuccessModal } from './TransferModalSuccess';
+import { TResponseState, TTransactionDetails } from '../types';
+
+export const TransferModal = ({ onClose }: { onClose: () => void }) => {
+ const [state, setState] = useState();
+ const [fee, setFee] = useState();
+ const [tx, setTx] = useState();
+
+ const { userBalance, clientDetails, network } = useContext(AppContext);
+
+ const getFee = async () => {
+ if (userBalance.tokenAllocation?.spendable && clientDetails?.denom) {
+ try {
+ const simulatedFee = await simulateWithdrawVestedCoins({
+ amount: { amount: userBalance.tokenAllocation?.spendable, denom: clientDetails?.denom },
+ });
+ setFee(simulatedFee);
+ } catch (e) {
+ setFee({ amount: { amount: 'n/a', denom: clientDetails.denom }, fee: { Auto: null } });
+ Console.error(e);
+ }
+ }
+ };
+
+ useEffect(() => {
+ getFee();
+ }, []);
+
+ const handleTransfer = async () => {
+ if (userBalance.tokenAllocation?.spendable && clientDetails?.denom) {
+ setState('loading');
+ try {
+ const txResponse = await withdrawVestedCoins({
+ amount: userBalance.tokenAllocation?.spendable,
+ denom: clientDetails.denom,
+ });
+ setState('success');
+ setTx({
+ amount: `${userBalance.tokenAllocation?.spendable} ${clientDetails?.denom}`,
+ url: `${urls(network).blockExplorer}/transaction/${txResponse.transaction_hash}`,
+ });
+ await userBalance.refreshBalances();
+ } catch (e) {
+ Console.error(e as string);
+ setState('fail');
+ }
+ }
+ };
+
+ if (state === 'success') {
+ return ;
+ }
+
+ return (
+
+
+ {state === 'loading' ? (
+
+
+
+ ) : (
+ <>
+
+ }
+ divider
+ />
+ {userBalance.tokenAllocation?.spendable && fee && (
+
+ )}
+ >
+ )}
+
+ {state === 'fail' && Transfer failed please try again in a few minutes}
+
+ );
+};
diff --git a/nym-wallet/src/pages/balance/components/TransferModalSuccess.tsx b/nym-wallet/src/pages/balance/components/TransferModalSuccess.tsx
new file mode 100644
index 0000000000..a4cba85844
--- /dev/null
+++ b/nym-wallet/src/pages/balance/components/TransferModalSuccess.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { Stack, Typography } from '@mui/material';
+import { Link } from '@nymproject/react/link/Link';
+import { ConfirmationModal } from 'src/components';
+import { TTransactionDetails } from '../types';
+
+export const SuccessModal = ({ tx, onClose }: { tx?: TTransactionDetails; onClose: () => void }) => (
+ Transfer to balance successful}
+ onClose={onClose}
+ onConfirm={onClose}
+ maxWidth="xs"
+ fullWidth
+ confirmButton="Done"
+ >
+
+ {tx && (
+ <>
+ {tx.amount}
+
+ >
+ )}
+
+
+);
diff --git a/nym-wallet/src/pages/balance/index.tsx b/nym-wallet/src/pages/balance/index.tsx
index 72a955db10..a51931fc84 100644
--- a/nym-wallet/src/pages/balance/index.tsx
+++ b/nym-wallet/src/pages/balance/index.tsx
@@ -1,15 +1,29 @@
-import React from 'react';
+import React, { useContext, useState } from 'react';
import { Box } from '@mui/material';
+import { AppContext } from '../../context/main';
+
import { BalanceCard } from './balance';
import { VestingCard } from './vesting';
-
import { PageLayout } from '../../layouts';
+import { TransferModal } from './components/TransferModal';
-export const Balance = () => (
-
-
-
-
-
-
-);
+export const Balance = () => {
+ const [showTransferModal, setShowTransferModal] = useState(false);
+
+ const { userBalance } = useContext(AppContext);
+
+ const handleShowTransferModal = async () => {
+ await userBalance.refreshBalances();
+ setShowTransferModal(true);
+ };
+
+ return (
+
+
+
+
+ {showTransferModal && setShowTransferModal(false)} />}
+
+
+ );
+};
diff --git a/nym-wallet/src/pages/balance/types.ts b/nym-wallet/src/pages/balance/types.ts
new file mode 100644
index 0000000000..5f88fe60b1
--- /dev/null
+++ b/nym-wallet/src/pages/balance/types.ts
@@ -0,0 +1,2 @@
+export type TResponseState = 'loading' | 'success' | 'fail';
+export type TTransactionDetails = { amount: string; url: string };
diff --git a/nym-wallet/src/pages/balance/vesting.tsx b/nym-wallet/src/pages/balance/vesting.tsx
index a8ca344ad9..54dd112fe2 100644
--- a/nym-wallet/src/pages/balance/vesting.tsx
+++ b/nym-wallet/src/pages/balance/vesting.tsx
@@ -2,7 +2,6 @@ import React, { useCallback, useContext, useEffect, useState } from 'react';
import {
Box,
Button,
- CircularProgress,
Grid,
IconButton,
Table,
@@ -15,12 +14,10 @@ import {
} from '@mui/material';
import { InfoOutlined, Refresh } from '@mui/icons-material';
import { useSnackbar } from 'notistack';
-import { Fee, InfoTooltip, NymCard, Title } from '../../components';
-import { AppContext } from '../../context/main';
-import { withdrawVestedCoins } from '../../requests';
-import { Period } from '../../types';
+import { InfoTooltip, NymCard, Title } from 'src/components';
+import { AppContext } from 'src/context/main';
+import { Period } from 'src/types';
import { VestingTimeline } from './components/vesting-timeline';
-import { Console } from '../../utils/console';
const columnsHeaders: Array<{ title: string; align: TableCellProps['align'] }> = [
{ title: 'Locked', align: 'left' },
@@ -120,10 +117,8 @@ const TokenTransfer = () => {
);
};
-export const VestingCard = () => {
- const [isLoading, setIsLoading] = useState(false);
-
- const { userBalance, clientDetails } = useContext(AppContext);
+export const VestingCard = ({ onTransfer }: { onTransfer: () => Promise }) => {
+ const { userBalance } = useContext(AppContext);
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
const refreshBalances = async () => {
@@ -156,39 +151,8 @@ export const VestingCard = () => {
>
-
- {userBalance.tokenAllocation?.spendable !== '0' ? : }
-