Skip to content

Commit

Permalink
Add confirmation models
Browse files Browse the repository at this point in the history
  • Loading branch information
yanok87 committed Nov 15, 2023
1 parent abbcfbb commit 8ca7c48
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 126 deletions.
129 changes: 43 additions & 86 deletions explorer/src/components/Delegations/components/DelegateModal.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import React, { useCallback, useContext, useState, useEffect, ChangeEvent } from 'react';
import React, { useState, useEffect, ChangeEvent } from 'react';
import { Box, Typography, SxProps, TextField } from '@mui/material';
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField';
import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField';
import { CurrencyDenom, FeeDetails, DecCoin, decimalToFloatApproximation, Coin } from '@nymproject/types';

import { CurrencyDenom, DecCoin } from '@nymproject/types';
import { SimpleModal } from './SimpleModal';
import { ModalListItem } from './ModalListItem';

import { TPoolOption, validateAmount } from '../utils';

import { Console, urls, validateAmount } from '../utils';
import { useChain } from '@cosmos-kit/react';
import { StdFee } from '@cosmjs/amino';
import { ExecuteResult } from '@cosmjs/cosmwasm-stargate';

import { uNYMtoNYM } from '../utils';
import { ErrorModal } from './ErrorModal';
import { DelegationModalProps } from './DelegationModal';

const MIN_AMOUNT_TO_DELEGATE = 10;
const MIXNET_CONTRACT_ADDRESS = 'n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr';
const sandboxContractAddress = 'n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav';
// const sandboxContractAddress = 'n1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3sjkxkav';

export const DelegateModal: FCWithChildren<{
open: boolean;
onClose: () => void;
onOk?: () => void;
onOk?: (delegationModalProps: DelegationModalProps) => void;
identityKey?: string;
onIdentityKeyChanged?: (identityKey: string) => void;
onAmountChanged?: (amount: string) => void;
Expand Down Expand Up @@ -61,8 +57,10 @@ export const DelegateModal: FCWithChildren<{
const [errorIdentityKey, setErrorIdentityKey] = useState<string>();
const [mixIdError, setMixIdError] = useState<string>();
const [cosmWasmSignerClient, setCosmWasmSignerClient] = useState<any>();

// const { fee, getFee, resetFeeState, feeError } = useGetFee();
const [balance, setBalance] = useState<{
status: 'loading' | 'success';
data?: string;
}>({ status: 'loading', data: undefined });

const {
username,
Expand All @@ -77,11 +75,6 @@ export const DelegateModal: FCWithChildren<{
estimateFee,
} = useChain('nyx');

const [balance, setBalance] = useState<{
status: 'loading' | 'success';
data?: string;
}>({ status: 'loading', data: undefined });

useEffect(() => {
const getClient = async () => {
await getSigningCosmWasmClient()
Expand All @@ -95,15 +88,14 @@ export const DelegateModal: FCWithChildren<{
isWalletConnected && getClient();
}, [isWalletConnected]);

useEffect(() => {
const getBalance = async (walletAddress: string) => {
const account = await getCosmWasmClient();
const uNYMBalance = await account.getBalance(walletAddress, 'unym');
const NYMBalance = uNYMtoNYM(uNYMBalance.amount).asString();

setBalance({ status: 'success', data: NYMBalance });
};
const getBalance = async (walletAddress: string) => {
const account = await getCosmWasmClient();
const uNYMBalance = await account.getBalance(walletAddress, 'unym');
const NYMBalance = uNYMtoNYM(uNYMBalance.amount).asString();

setBalance({ status: 'success', data: NYMBalance });
};
useEffect(() => {
if (address) {
getBalance(address);
}
Expand Down Expand Up @@ -182,14 +174,32 @@ export const DelegateModal: FCWithChildren<{
const fee = { gas: '1000000', amount: [{ amount: '25000', denom: 'unym' }] };

if (mixId && amount && onOk && cosmWasmSignerClient) {
console.log('trying to delegate :>> ');
console.log('balance.data :>> ', balance.data);
onOk();
console.log('amount :>> ', amount);
console.log('fee :>> ', fee);
await delegateToMixnode({ mixId }, fee, memo, [amount])
.then((res) => console.log('res :>> ', res))
.catch((err) => console.log('err :>> ', err));
onOk({
status: 'loading',
action: 'delegate',
});
try {
await delegateToMixnode({ mixId }, fee, memo, [amount]).then((res) => {
console.log('res :>> ', res);
});
const tx = await delegateToMixnode({ mixId }, fee, memo, [amount]);

onOk({
status: 'success',
action: 'delegate',
message: 'This operation can take up to one hour to process',
transactions: [
{ url: `${urls('MAINNET').blockExplorer}/transaction/${tx.transactionHash}`, hash: tx.transactionHash },
],
});
} catch (e) {
Console.error('Failed to addDelegation', e);
onOk({
status: 'error',
action: 'delegate',
message: (e as Error).message,
});
}
}
};

Expand Down Expand Up @@ -218,39 +228,6 @@ export const DelegateModal: FCWithChildren<{
validate();
}, [amount, identityKey, mixId]);

// if (fee) {
// return (
// <ConfirmTx
// open
// header="Delegation details"
// fee={fee}
// onClose={onClose}
// onPrev={resetFeeState}
// onConfirm={handleOk}
// >
// {balance.data && fee?.amount?.amount && (
// <Box sx={{ my: 2 }}>
// <BalanceWarning fee={fee?.amount?.amount} tx={amount} />
// </Box>
// )}
// <ModalListItem label="Node identity key" value={identityKey} divider />
// <ModalListItem label="Amount" value={`${amount} ${denom.toUpperCase()}`} divider />
// </ConfirmTx>
// );
// }

// if (feeError) {
// return (
// <ErrorModal
// title="Something went wrong while calculating fee. Are you sure you entered a valid node address?"
// message={feeError}
// sx={sx}
// open={open}
// onClose={onClose}
// />
// );
// }

return (
<SimpleModal
open={open}
Expand Down Expand Up @@ -316,26 +293,6 @@ export const DelegateModal: FCWithChildren<{
<ModalListItem label="Account balance" value={`${balance.data} NYM`} divider fontWeight={600} />
</Box>

{/* <ModalListItem label="Rewards payout interval" value={rewardInterval} hidden divider /> */}
{/* <ModalListItem
label="Node profit margin"
value={`${profitMarginPercentage ? `${profitMarginPercentage}%` : '-'}`}
hidden={profitMarginPercentage === undefined}
divider
/>
<ModalListItem
label="Node avg. uptime"
value={`${nodeUptimePercentage ? `${nodeUptimePercentage}%` : '-'}`}
hidden={nodeUptimePercentage === undefined}
divider
/> */}

{/* <ModalListItem
label="Node est. reward per epoch"
value={`${estimatedReward} ${denom.toUpperCase()}`}
hidden
divider
/> */}
<ModalListItem label="Est. fee for this transaction will be calculated in the next page" />
</SimpleModal>
);
Expand Down
80 changes: 80 additions & 0 deletions explorer/src/components/Delegations/components/DelegationModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react';
import { Typography, SxProps, Stack } from '@mui/material';
import { Link } from '@nymproject/react/link/Link';
import { LoadingModal } from './LoadingModal';
import { ConfirmationModal } from './ConfirmationModal';
import { ErrorModal } from './ErrorModal';

export type ActionType = 'delegate' | 'undelegate' | 'redeem' | 'redeem-all' | 'compound';

const actionToHeader = (action: ActionType): string => {
// eslint-disable-next-line default-case
switch (action) {
case 'redeem':
return 'Rewards redeemed successfully';
case 'redeem-all':
return 'All rewards redeemed successfully';
case 'delegate':
return 'Delegation successful';
case 'undelegate':
return 'Undelegation successful';
case 'compound':
return 'Rewards compounded successfully';
default:
throw new Error('Unknown type');
}
};

export type DelegationModalProps = {
status: 'loading' | 'success' | 'error';
action: ActionType;
message?: string;
transactions?: {
url: string;
hash: string;
}[];
};

export const DelegationModal: FCWithChildren<
DelegationModalProps & {
open: boolean;
onClose: () => void;
sx?: SxProps;
backdropProps?: object;
children?: React.ReactNode;
}
> = ({ status, action, message, transactions, open, onClose, children, sx, backdropProps }) => {
if (status === 'loading') return <LoadingModal sx={sx} backdropProps={backdropProps} />;

if (status === 'error') {
return (
<ErrorModal message={message} sx={sx} open={open} onClose={onClose}>
{children}
</ErrorModal>
);
}

return (
<ConfirmationModal
open={open}
onConfirm={onClose || (() => {})}
title={actionToHeader(action)}
confirmButton="Done"
>
<Stack alignItems="center" spacing={2} mb={0}>
{message && <Typography>{message}</Typography>}
{transactions?.length === 1 && (
<Link href={transactions[0].url} target="_blank" sx={{ ml: 1 }} text="View on blockchain" noIcon />
)}
{transactions && transactions.length > 1 && (
<Stack alignItems="center" spacing={1}>
<Typography>View the transactions on blockchain:</Typography>
{transactions.map(({ url, hash }) => (
<Link href={url} target="_blank" sx={{ ml: 1 }} text={hash.slice(0, 6)} key={hash} noIcon />
))}
</Stack>
)}
</Stack>
</ConfirmationModal>
);
};
29 changes: 29 additions & 0 deletions explorer/src/components/Delegations/components/LoadingModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { Box, CircularProgress, Modal, Stack, Typography, SxProps } from '@mui/material';

const modalStyle: SxProps = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 500,
bgcolor: 'background.paper',
boxShadow: 24,
borderRadius: '16px',
p: 4,
};

export const LoadingModal: FCWithChildren<{
text?: string;
sx?: SxProps;
backdropProps?: object;
}> = ({ sx, backdropProps, text = 'Please wait...' }) => (
<Modal open BackdropProps={backdropProps}>
<Box sx={{ border: (t) => `1px solid grey`, ...modalStyle, ...sx }} textAlign="center">
<Stack spacing={4} direction="row" alignItems="center">
<CircularProgress />
<Typography sx={{ color: 'text.primary' }}>{text}</Typography>
</Stack>
</Box>
</Modal>
);
13 changes: 13 additions & 0 deletions explorer/src/components/Delegations/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { add, format, fromUnixTime } from 'date-fns';
import { DecCoin, isValidRawCoin, MixNodeCostParams } from '@nymproject/types';
import { getCurrentInterval, getDefaultMixnodeCostParams, getLockedCoins, getSpendableCoins } from '../requests';
import { Console } from './console';
import { Network } from '../types';

export type TPoolOption = 'balance' | 'locked';

Expand Down Expand Up @@ -253,3 +254,15 @@ export const getIntervalAsDate = async () => {

return { nextEpoch, nextInterval };
};

export const urls = (networkName?: Network) =>
networkName === 'MAINNET'
? {
mixnetExplorer: 'https://mixnet.explorers.guru/',
blockExplorer: 'https://blocks.nymtech.net',
networkExplorer: 'https://explorer.nymtech.net',
}
: {
blockExplorer: `https://${networkName}-blocks.nymtech.net`,
networkExplorer: `https://${networkName}-explorer.nymtech.net`,
};
Loading

0 comments on commit 8ca7c48

Please sign in to comment.