From a9ff98418c907815ce787d8f3f1b3f53bfec3536 Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Sat, 11 Jun 2022 00:19:00 +0100 Subject: [PATCH] update modals --- .../components/Delegation/DelegateModal.tsx | 166 ++++++++++++++---- .../components/Delegation/UndelegateModal.tsx | 51 ++++-- 2 files changed, 160 insertions(+), 57 deletions(-) diff --git a/nym-wallet/src/components/Delegation/DelegateModal.tsx b/nym-wallet/src/components/Delegation/DelegateModal.tsx index 1da4668c64..374b3a650f 100644 --- a/nym-wallet/src/components/Delegation/DelegateModal.tsx +++ b/nym-wallet/src/components/Delegation/DelegateModal.tsx @@ -2,15 +2,74 @@ import React, { useState } from 'react'; import { Box, Stack, Typography } from '@mui/material'; import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'; import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField'; -import { CurrencyDenom, MajorCurrencyAmount } from '@nymproject/types'; -import { getGasFee } from 'src/requests'; +import { CurrencyDenom, FeeDetails, MajorCurrencyAmount } from '@nymproject/types'; +import { getGasFee, simulateDelegateToMixnode } from 'src/requests'; import { SimpleModal } from '../Modals/SimpleModal'; -import { ModalListItem } from './ModalListItem'; -import { validateKey } from '../../utils'; +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 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; + } +}; + export const DelegateModal: React.FC<{ open: boolean; onClose?: () => void; @@ -40,7 +99,6 @@ export const DelegateModal: React.FC<{ identityKey: initialIdentityKey, rewardInterval, accountBalance, - feeOverride, estimatedReward, currency, profitMarginPercentage, @@ -53,36 +111,59 @@ 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, setFee] = useState(); - const getFee = async () => { - if (feeOverride) setFee(feeOverride); - else { - const res = await getGasFee('BondMixnode'); - setFee(res.amount); - } - }; - - const validate = () => { + const validate = async () => { let newValidatedValue = true; + let errorMessage; + if (!identityKey || !validateKey(identityKey, 32)) { newValidatedValue = false; } - if (amount && Number(amount) < MIN_AMOUNT_TO_DELEGATE) { - setErrorAmount(`Min. delegation amount: ${MIN_AMOUNT_TO_DELEGATE} ${currency}`); + + if (amount && !(await validateAmount(amount, '0'))) { newValidatedValue = false; - } else { - setErrorAmount(undefined); + errorMessage = 'Please enter a valid amount'; } + + if (amount && Number(amount) < MIN_AMOUNT_TO_DELEGATE) { + errorMessage = `Min. delegation amount: ${MIN_AMOUNT_TO_DELEGATE} ${currency}`; + newValidatedValue = false; + } + + if (!amount?.length) { + newValidatedValue = false; + } + + setErrorAmount(errorMessage); setValidated(newValidatedValue); }; - const handleOk = () => { + const handleOk = async () => { if (onOk && amount && identityKey) { onOk(identityKey, { amount, denom: currency }, tokenPool); } }; + const handleConfirm = async ({ identityKey, amount }: { identityKey: string; amount: MajorCurrencyAmount }) => { + let response: confirmationResponseType = {}; + + if (tokenPool === 'locked') { + response = await handleConfirmWithLocked({ identityKey, amount }); + } else { + response = await handleConfirmWithBalance({ identityKey, amount }); + } + + if (response.error) { + setErrorAmount(response.error); + } + + if (!response.error && response.fees) { + setFee(response.fees); + setErrorAmount(undefined); + } + }; + const handleIdentityKeyChanged = (newIdentityKey: string) => { setIdentityKey(newIdentityKey); if (onIdentityKeyChanged) { @@ -101,15 +182,32 @@ export const DelegateModal: React.FC<{ validate(); }, [amount, identityKey]); - React.useEffect(() => { - getFee(); - }, []); + if (fee?.amount) { + return ( + setFee(undefined)} + onConfirm={handleOk} + currency={currency} + > + + + + ); + } return ( { + if (identityKey && amount) { + handleConfirm({ identityKey, amount: { amount, denom: currency } }); + } + }} header={header || 'Delegate'} subHeader="Delegate to mixnode" okLabel={buttonText || 'Delegate stake'} @@ -120,7 +218,7 @@ export const DelegateModal: React.FC<{ fullWidth placeholder="Node identity key" onChanged={handleIdentityKeyChanged} - initialValue={initialIdentityKey} + initialValue={identityKey} readOnly={Boolean(initialIdentityKey)} textFieldProps={{ autoFocus: !initialIdentityKey, @@ -132,7 +230,7 @@ export const DelegateModal: React.FC<{ required fullWidth placeholder="Amount" - initialValue={initialAmount} + initialValue={amount} autoFocus={Boolean(initialIdentityKey)} onChanged={handleAmountChanged} /> @@ -140,10 +238,10 @@ export const DelegateModal: React.FC<{ {errorAmount} - - Account balance - {accountBalance} - + + + + ); }; diff --git a/nym-wallet/src/components/Delegation/UndelegateModal.tsx b/nym-wallet/src/components/Delegation/UndelegateModal.tsx index 350fb739a8..2787a64515 100644 --- a/nym-wallet/src/components/Delegation/UndelegateModal.tsx +++ b/nym-wallet/src/components/Delegation/UndelegateModal.tsx @@ -1,7 +1,10 @@ -import React from 'react'; -import { Stack, Typography } from '@mui/material'; +import React, { useEffect, useState } from 'react'; +import { Box, Stack, Typography } from '@mui/material'; import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'; import { SimpleModal } from '../Modals/SimpleModal'; +import { simulateUndelegateFromMixnode } from 'src/requests'; +import { ModalListItem } from '../Modals/ModalListItem'; +import { FeeDetails } from '@nymproject/types'; export const UndelegateModal: React.FC<{ open: boolean; @@ -9,15 +12,31 @@ export const UndelegateModal: React.FC<{ onOk?: (identityKey: string, proxy: string | null) => void; identityKey: string; amount: number; - fee: number; currency: string; proxy: string | null; -}> = ({ identityKey, open, onClose, onOk, amount, fee, currency, proxy }) => { - const handleOk = () => { +}> = ({ 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'); + } + }; + + useEffect(() => { + getFee(); + }, []); + + const handleOk = async () => { if (onOk) { onOk(identityKey, proxy); } }; + return ( - - Delegation amount: - - {amount} {currency} - - + + + Tokens 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} - - + ); };