Files
nym/explorer-nextjs/app/components/Delegations/DelegateModal.tsx
Fouad e5f41731ae Explorer NextJS Rebuild (#4534)
* bootstrap next app + add overview page

* fix AssetList type

* fix up nav stuff

* Refactor Nav component and add network components pages

* Refactor WorldMap component and update TelegramIcon, GitHubIcon, NymVpnIcon, DiscordIcon, and TwitterIcon components

* add service providers page

* mixnodes page

* delegations page + use material react table for all tables

* nodes map page

* Refactor StyledLink component and remove unnecessary console.log statements

* Refactor ESLint configuration, remove unused dependencies, and update component imports

* update deps

* Refactor imports and update dependencies

* fix dark mode

* build single mixnode page

* build single gateway page

* Refactor handleOnDelegate function to use useCallback in mixnodes page.tsx

* Add defaults for constants

---------

Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
2024-05-16 16:12:06 +01:00

192 lines
4.9 KiB
TypeScript

'use client'
import React, { useState } from 'react'
import { Box, SxProps } from '@mui/material'
import { IdentityKeyFormField } from '@nymproject/react/mixnodes/IdentityKeyFormField'
import { CurrencyFormField } from '@nymproject/react/currency/CurrencyFormField'
import { CurrencyDenom, DecCoin } from '@nymproject/types'
import { useWalletContext } from '@/app/context/wallet'
import { urls } from '@/app/utils'
import { useDelegationsContext } from '@/app/context/delegations'
import { validateAmount } from '@/app/utils/currency'
import { SimpleModal } from './SimpleModal'
import { ModalListItem } from './ModalListItem'
import { DelegationModalProps } from './DelegationModal'
const MIN_AMOUNT_TO_DELEGATE = 10
type Props = {
mixId: number
identityKey: string
header?: string
buttonText?: string
rewardInterval?: string
estimatedReward?: number
profitMarginPercentage?: string | null
nodeUptimePercentage?: number | null
denom: CurrencyDenom
sx?: SxProps
backdropProps?: object
onClose: () => void
onOk?: (delegationModalProps: DelegationModalProps) => void
}
export const DelegateModal = ({
mixId,
identityKey,
onClose,
onOk,
denom,
sx,
}: Props) => {
const [amount, setAmount] = useState<DecCoin | undefined>({
amount: '10',
denom: 'nym',
})
const [isValidated, setValidated] = useState<boolean>(false)
const [errorAmount, setErrorAmount] = useState<string | undefined>()
const { address, balance } = useWalletContext()
const { handleDelegate } = useDelegationsContext()
const validate = async () => {
let newValidatedValue = true
let errorAmountMessage
if (amount && !(await validateAmount(amount.amount, '0'))) {
newValidatedValue = false
errorAmountMessage = 'Please enter a valid amount'
}
if (amount && +amount.amount < MIN_AMOUNT_TO_DELEGATE) {
errorAmountMessage = `Min. delegation amount: ${MIN_AMOUNT_TO_DELEGATE} ${denom.toUpperCase()}`
newValidatedValue = false
}
if (!amount?.amount.length) {
newValidatedValue = false
}
if (amount && balance.data && +balance.data - +amount.amount <= 0) {
errorAmountMessage = 'Not enough funds'
newValidatedValue = false
}
setErrorAmount(errorAmountMessage)
setValidated(newValidatedValue)
}
const delegateToMixnode = async ({
delegationMixId,
delegationAmount,
}: {
delegationMixId: number
delegationAmount: string
}) => {
try {
const tx = await handleDelegate(delegationMixId, delegationAmount)
return tx
} catch (e) {
console.error('Failed to delegate to mixnode', e)
throw e
}
}
const handleConfirm = async () => {
if (mixId && amount && onOk) {
onOk({
status: 'loading',
})
try {
if (!address) {
throw new Error('Please connect your wallet')
}
const tx = await delegateToMixnode({
delegationMixId: mixId,
delegationAmount: amount.amount,
})
if (!tx) {
throw new Error('Failed to delegate')
}
onOk({
status: 'success',
message: 'Delegation 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 delegate', e)
onOk({
status: 'error',
message: (e as Error).message,
})
}
}
}
const handleAmountChanged = (newAmount: DecCoin) => {
setAmount(newAmount)
}
React.useEffect(() => {
validate()
}, [amount, identityKey, mixId])
return (
<SimpleModal
open
onClose={onClose}
onOk={handleConfirm}
header="Delegate"
okLabel="Delegate"
okDisabled={!isValidated}
sx={sx}
>
<Box sx={{ mt: 3 }} gap={2}>
<IdentityKeyFormField
required
fullWidth
label="Node identity key"
onChanged={() => undefined}
initialValue={identityKey}
readOnly
showTickOnValid={false}
/>
</Box>
<Box display="flex" gap={2} alignItems="center" sx={{ mt: 3 }}>
<CurrencyFormField
showCoinMark={false}
required
fullWidth
autoFocus
label="Amount"
initialValue={amount?.amount || '10'}
onChanged={handleAmountChanged}
denom={denom}
validationError={errorAmount}
/>
</Box>
<Box sx={{ mt: 3 }}>
<ModalListItem
label="Account balance"
value={`${balance.data} NYM`}
divider
fontWeight={600}
/>
</Box>
<ModalListItem label="Est. fee for this transaction will be calculated in your connected wallet" />
</SimpleModal>
)
}