diff --git a/nym-wallet/src/components/ConfirmTX.stories.tsx b/nym-wallet/src/components/ConfirmTX.stories.tsx index 83f42d7000..e3498e29a3 100644 --- a/nym-wallet/src/components/ConfirmTX.stories.tsx +++ b/nym-wallet/src/components/ConfirmTX.stories.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { Box } from '@mui/material'; import { ConfirmTx } from './ConfirmTX'; import { ModalListItem } from './Modals/ModalListItem'; @@ -12,8 +11,8 @@ export default { const Template: ComponentStory = (args) => ( - - + + ); @@ -22,8 +21,7 @@ Default.args = { open: true, header: 'Confirm transaction', subheader: 'Confirm and proceed or cancel transaction', - fee: { amount: '1', denom: 'NYM' }, - currency: 'NYM', + fee: { amount: { amount: '0.001', denom: 'NYM' } }, onClose: () => {}, onConfirm: async () => {}, onPrev: () => {}, diff --git a/nym-wallet/src/components/ConfirmTX.tsx b/nym-wallet/src/components/ConfirmTX.tsx index e021a2f411..c398e2e879 100644 --- a/nym-wallet/src/components/ConfirmTX.tsx +++ b/nym-wallet/src/components/ConfirmTX.tsx @@ -1,15 +1,14 @@ import React from 'react'; +import { FeeDetails } from '@nymproject/types'; +import { Box, Button } from '@mui/material'; import { SimpleModal } from './Modals/SimpleModal'; -import { MajorCurrencyAmount, MajorAmountString } from '@nymproject/types'; -import { ModalListItem } from './Modals/ModalListItem'; -import { Button } from '@mui/material'; +import { ModalFee } from './Modals/ModalFee'; export const ConfirmTx: React.FC<{ open: boolean; header: string; subheader?: string; - fee: MajorCurrencyAmount; - currency: MajorAmountString; + fee: FeeDetails; onConfirm: () => Promise; onClose?: () => void; onPrev: () => void; @@ -27,7 +26,9 @@ export const ConfirmTx: React.FC<{ } > - {children} - + + {children} + + ); diff --git a/nym-wallet/src/components/Delegation/DelegateModal.tsx b/nym-wallet/src/components/Delegation/DelegateModal.tsx index 374b3a650f..aa20ce688c 100644 --- a/nym-wallet/src/components/Delegation/DelegateModal.tsx +++ b/nym-wallet/src/components/Delegation/DelegateModal.tsx @@ -1,73 +1,29 @@ import React, { useState } from 'react'; -import { Box, Stack, Typography } from '@mui/material'; +import { Box, Typography } from '@mui/material'; import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'; import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField'; -import { CurrencyDenom, FeeDetails, MajorCurrencyAmount } from '@nymproject/types'; -import { getGasFee, simulateDelegateToMixnode } from 'src/requests'; +import { CurrencyDenom, MajorCurrencyAmount } from '@nymproject/types'; +import { useGetFee } from 'src/hooks/useGetFee'; +import { simulateDelegateToMixnode } from 'src/requests'; import { SimpleModal } from '../Modals/SimpleModal'; import { ModalListItem } from '../Modals/ModalListItem'; import { checkHasEnoughFunds, checkHasEnoughLockedTokens, validateAmount, validateKey } from '../../utils'; import { TokenPoolSelector, TPoolOption } from '../TokenPoolSelector'; import { ConfirmTx } from '../ConfirmTX'; -import { Console } from 'src/utils/console'; const MIN_AMOUNT_TO_DELEGATE = 10; -type confirmationResponseType = { - error?: string; - fees?: FeeDetails; -}; - -const handleConfirmWithBalance = async ({ - identityKey, - amount, -}: { - identityKey: string; - amount: MajorCurrencyAmount; -}) => { - const response: confirmationResponseType = {}; - const hasEnoughTokens = await checkHasEnoughFunds(amount.amount); - - try { - if (!hasEnoughTokens) { - response.error = 'Not enough funds'; - } else { - const fees = await simulateDelegateToMixnode({ identity: identityKey, amount }); - response.fees = fees; - } - return response; - } catch (e) { - Console.error(e); - response.fees = undefined; - response.error = 'An error occurred. Please check the address and amount are correct'; - return response; +const checkTokenBalance = async (tokenPool: TPoolOption, amount: string) => { + let hasEnoughFunds = false; + if (tokenPool === 'locked') { + hasEnoughFunds = await checkHasEnoughLockedTokens(amount); } -}; -const handleConfirmWithLocked = async ({ - identityKey, - amount, -}: { - identityKey: string; - amount: MajorCurrencyAmount; -}) => { - const response: confirmationResponseType = {}; - const hasEnoughTokens = await checkHasEnoughLockedTokens(amount.amount); - - try { - if (!hasEnoughTokens) { - response.error = 'Not enough funds'; - } else { - const fees = await simulateDelegateToMixnode({ identity: identityKey, amount }); - response.fees = fees; - } - return response; - } catch (e) { - Console.error(e); - response.fees = undefined; - response.error = 'An error occurred. Please check the address and amount are correct'; - return response; + if (tokenPool === 'balance') { + hasEnoughFunds = await checkHasEnoughFunds(amount); } + + return hasEnoughFunds; }; export const DelegateModal: React.FC<{ @@ -84,7 +40,6 @@ export const DelegateModal: React.FC<{ estimatedReward?: number; profitMarginPercentage?: number | null; nodeUptimePercentage?: number | null; - feeOverride?: string; currency: CurrencyDenom; initialAmount?: string; hasVestingContract: boolean; @@ -111,7 +66,8 @@ export const DelegateModal: React.FC<{ const [isValidated, setValidated] = useState(false); const [errorAmount, setErrorAmount] = useState(); const [tokenPool, setTokenPool] = useState('balance'); - const [fee, setFee] = useState(); + + const { fee, getFee, resetFeeState } = useGetFee(); const validate = async () => { let newValidatedValue = true; @@ -145,22 +101,20 @@ export const DelegateModal: React.FC<{ } }; - const handleConfirm = async ({ identityKey, amount }: { identityKey: string; amount: MajorCurrencyAmount }) => { - let response: confirmationResponseType = {}; + const handleConfirm = async ({ identity, value }: { identity: string; value: MajorCurrencyAmount }) => { + const hasEnoughTokens = await checkTokenBalance(tokenPool, value.amount); + + if (!hasEnoughTokens) { + setErrorAmount('Not enough funds'); + return; + } if (tokenPool === 'locked') { - response = await handleConfirmWithLocked({ identityKey, amount }); - } else { - response = await handleConfirmWithBalance({ identityKey, amount }); + getFee(simulateDelegateToMixnode, { identity, amount: value }); } - if (response.error) { - setErrorAmount(response.error); - } - - if (!response.error && response.fees) { - setFee(response.fees); - setErrorAmount(undefined); + if (tokenPool === 'balance') { + getFee(simulateDelegateToMixnode, { identity, amount: value }); } }; @@ -182,16 +136,15 @@ export const DelegateModal: React.FC<{ validate(); }, [amount, identityKey]); - if (fee?.amount) { + if (fee) { return ( setFee(undefined)} + onPrev={resetFeeState} onConfirm={handleOk} - currency={currency} > @@ -205,7 +158,7 @@ export const DelegateModal: React.FC<{ onClose={onClose} onOk={async () => { if (identityKey && amount) { - handleConfirm({ identityKey, amount: { amount, denom: currency } }); + handleConfirm({ identity: identityKey, value: { amount, denom: currency } }); } }} header={header || 'Delegate'} diff --git a/nym-wallet/src/components/Delegation/Modals.stories.tsx b/nym-wallet/src/components/Delegation/Modals.stories.tsx index 83fb390db9..29c1eea04f 100644 --- a/nym-wallet/src/components/Delegation/Modals.stories.tsx +++ b/nym-wallet/src/components/Delegation/Modals.stories.tsx @@ -51,7 +51,6 @@ export const Delegate = () => { onClose={() => setOpen(false)} onOk={async () => setOpen(false)} currency="NYM" - feeOverride="0.004375" estimatedReward={50.423} accountBalance="425.2345053" nodeUptimePercentage={99.28394} @@ -73,7 +72,6 @@ export const DelegateBelowMinimum = () => { onClose={() => setOpen(false)} onOk={async () => setOpen(false)} currency="NYM" - feeOverride="0.004375" estimatedReward={425.2345053} nodeUptimePercentage={99.28394} profitMarginPercentage={11.12334234} @@ -97,7 +95,6 @@ export const DelegateMore = () => { header="Delegate more" buttonText="Delegate more" currency="NYM" - feeOverride="0.004375" estimatedReward={50.423} accountBalance="425.2345053" nodeUptimePercentage={99.28394} diff --git a/nym-wallet/src/components/Delegation/UndelegateModal.tsx b/nym-wallet/src/components/Delegation/UndelegateModal.tsx index 2787a64515..8c7c3eeff7 100644 --- a/nym-wallet/src/components/Delegation/UndelegateModal.tsx +++ b/nym-wallet/src/components/Delegation/UndelegateModal.tsx @@ -1,10 +1,11 @@ -import React, { useEffect, useState } from 'react'; -import { Box, Stack, Typography } from '@mui/material'; +import React, { useEffect } from 'react'; +import { Box, Typography } from '@mui/material'; import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'; -import { SimpleModal } from '../Modals/SimpleModal'; +import { useGetFee } from 'src/hooks/useGetFee'; import { simulateUndelegateFromMixnode } from 'src/requests'; +import { SimpleModal } from '../Modals/SimpleModal'; import { ModalListItem } from '../Modals/ModalListItem'; -import { FeeDetails } from '@nymproject/types'; +import { ModalFee } from '../Modals/ModalFee'; export const UndelegateModal: React.FC<{ open: boolean; @@ -15,20 +16,11 @@ export const UndelegateModal: React.FC<{ currency: string; proxy: string | null; }> = ({ identityKey, open, onClose, onOk, amount, currency, proxy }) => { - const [fee, setFee] = useState(); - const [error, setError] = useState(); - - const getFee = async () => { - try { - const simulatedFee = await simulateUndelegateFromMixnode(identityKey); - setFee(simulatedFee); - } catch (e) { - setError('Unable to determine fee estimate'); - } - }; + const { fee, isFeeLoading, feeError, getFee } = useGetFee(); useEffect(() => { - getFee(); + // Need simulateVestingUndelegateFromMixnode + getFee(simulateUndelegateFromMixnode, identityKey); }, []); const handleOk = async () => { @@ -45,7 +37,7 @@ export const UndelegateModal: React.FC<{ header="Undelegate" subHeader="Undelegate from mixnode" okLabel="Undelegate stake" - okDisabled={!fee && !error} + okDisabled={!fee} > - + ); }; diff --git a/nym-wallet/src/components/Modals/ModalFee.tsx b/nym-wallet/src/components/Modals/ModalFee.tsx new file mode 100644 index 0000000000..c64fa0286e --- /dev/null +++ b/nym-wallet/src/components/Modals/ModalFee.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { FeeDetails } from '@nymproject/types'; +import { CircularProgress } from '@mui/material'; +import { ModalListItem } from './ModalListItem'; + +type TFeeProps = { fee?: FeeDetails; isLoading: boolean; error?: string }; + +const getValue = ({ fee, isLoading, error }: TFeeProps) => { + if (isLoading) return ; + if (error && !isLoading) return 'n/a'; + if (fee) return `${fee.amount?.amount} ${fee.amount?.denom}`; + return '-'; +}; + +export const ModalFee = ({ fee, isLoading, error }: TFeeProps) => ( + +); diff --git a/nym-wallet/src/components/Modals/ModalListItem.tsx b/nym-wallet/src/components/Modals/ModalListItem.tsx index 4f467d03f8..a416375200 100644 --- a/nym-wallet/src/components/Modals/ModalListItem.tsx +++ b/nym-wallet/src/components/Modals/ModalListItem.tsx @@ -6,7 +6,7 @@ export const ModalListItem: React.FC<{ label: string; divider?: boolean; hidden?: boolean; - value: React.ReactNode; + value: string | React.ReactNode; }> = ({ label, value, hidden, divider }) => (