update modals
This commit is contained in:
@@ -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<boolean>(false);
|
||||
const [errorAmount, setErrorAmount] = useState<string | undefined>();
|
||||
const [tokenPool, setTokenPool] = useState<TPoolOption>('balance');
|
||||
const [fee, setFee] = useState<string>();
|
||||
const [fee, setFee] = useState<FeeDetails>();
|
||||
|
||||
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 (
|
||||
<ConfirmTx
|
||||
open
|
||||
header="Delegation details"
|
||||
fee={fee.amount}
|
||||
onClose={onClose}
|
||||
onPrev={() => setFee(undefined)}
|
||||
onConfirm={handleOk}
|
||||
currency={currency}
|
||||
>
|
||||
<ModalListItem label="Node identity key" value={identityKey} divider />
|
||||
<ModalListItem label="Amount" value={`${amount} ${currency}`} divider />
|
||||
</ConfirmTx>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SimpleModal
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
onOk={handleOk}
|
||||
onOk={async () => {
|
||||
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<{
|
||||
<Typography component="div" textAlign="right" variant="caption" sx={{ color: 'error.main' }}>
|
||||
{errorAmount}
|
||||
</Typography>
|
||||
<Stack direction="row" justifyContent="space-between" my={3}>
|
||||
<Typography fontWeight={600}>Account balance</Typography>
|
||||
<Typography fontWeight={600}>{accountBalance}</Typography>
|
||||
</Stack>
|
||||
<Box sx={{ mt: 3 }}>
|
||||
<ModalListItem label="Account balance" value={accountBalance} divider />
|
||||
</Box>
|
||||
|
||||
<ModalListItem label="Rewards payout interval" value={rewardInterval} hidden divider />
|
||||
<ModalListItem
|
||||
label="Node profit margin"
|
||||
@@ -159,14 +257,6 @@ export const DelegateModal: React.FC<{
|
||||
/>
|
||||
|
||||
<ModalListItem label="Node est. reward per epoch" value={`${estimatedReward} ${currency}`} hidden divider />
|
||||
<Stack direction="row" justifyContent="space-between" mt={4}>
|
||||
<Typography fontSize="smaller" color={(theme) => theme.palette.nym.fee}>
|
||||
Est. fee for this transaction:
|
||||
</Typography>
|
||||
<Typography fontSize="smaller" color={(theme) => theme.palette.nym.fee}>
|
||||
{fee} {currency}
|
||||
</Typography>
|
||||
</Stack>
|
||||
</SimpleModal>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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<FeeDetails>();
|
||||
const [error, setError] = useState<string>();
|
||||
|
||||
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 (
|
||||
<SimpleModal
|
||||
open={open}
|
||||
@@ -26,6 +45,7 @@ export const UndelegateModal: React.FC<{
|
||||
header="Undelegate"
|
||||
subHeader="Undelegate from mixnode"
|
||||
okLabel="Undelegate stake"
|
||||
okDisabled={!fee && !error}
|
||||
>
|
||||
<IdentityKeyFormField
|
||||
readOnly
|
||||
@@ -35,25 +55,18 @@ export const UndelegateModal: React.FC<{
|
||||
showTickOnValid={false}
|
||||
/>
|
||||
|
||||
<Stack direction="row" justifyContent="space-between" my={3}>
|
||||
<Typography fontWeight={600}>Delegation amount:</Typography>
|
||||
<Typography fontWeight={600}>
|
||||
{amount} {currency}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Box sx={{ mt: 3 }}>
|
||||
<ModalListItem label="Delegation amount" value={`${amount} ${currency}`} divider />
|
||||
</Box>
|
||||
|
||||
<Typography mb={5} fontSize="smaller">
|
||||
Tokens will be transferred to account you are logged in with now
|
||||
</Typography>
|
||||
|
||||
<Stack direction="row" justifyContent="space-between" mt={3}>
|
||||
<Typography fontSize="smaller" color={(theme) => theme.palette.nym.fee}>
|
||||
Est. fee for this transaction:
|
||||
</Typography>
|
||||
<Typography fontSize="smaller" color={(theme) => theme.palette.nym.fee}>
|
||||
{fee} {currency}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<ModalListItem
|
||||
label="Estimated fee for this operation"
|
||||
value={fee ? `${fee.amount?.amount} ${fee.amount?.denom}` : 'n/a'}
|
||||
/>
|
||||
</SimpleModal>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user