combine deposit and withdraw to single modal
This commit is contained in:
parent
945d38aefc
commit
13cdf408ef
|
@ -12,20 +12,18 @@ import Image from 'next/legacy/image'
|
|||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { ModalProps } from '../../types/modal'
|
||||
import { ALPHA_DEPOSIT_LIMIT, INPUT_TOKEN_DEFAULT } from '../../utils/constants'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import { floorToDecimal, formatFixedDecimals } from '../../utils/numbers'
|
||||
import { TokenAccount } from '../../utils/tokens'
|
||||
import ActionTokenList from '../account/ActionTokenList'
|
||||
import ButtonGroup from '../forms/ButtonGroup'
|
||||
import Label from '../forms/Label'
|
||||
import Button from '../shared/Button'
|
||||
import InlineNotification from '../shared/InlineNotification'
|
||||
import Loading from '../shared/Loading'
|
||||
import Modal from '../shared/Modal'
|
||||
import { EnterBottomExitBottom, FadeInFadeOut } from '../shared/Transitions'
|
||||
import { withValueLimit } from '../swap/SwapForm'
|
||||
import { ALPHA_DEPOSIT_LIMIT, INPUT_TOKEN_DEFAULT } from './../utils/constants'
|
||||
import { notify } from './../utils/notifications'
|
||||
import { floorToDecimal, formatFixedDecimals } from './../utils/numbers'
|
||||
import { TokenAccount } from './../utils/tokens'
|
||||
import ActionTokenList from './account/ActionTokenList'
|
||||
import ButtonGroup from './forms/ButtonGroup'
|
||||
import Label from './forms/Label'
|
||||
import Button from './shared/Button'
|
||||
import InlineNotification from './shared/InlineNotification'
|
||||
import Loading from './shared/Loading'
|
||||
import { EnterBottomExitBottom, FadeInFadeOut } from './shared/Transitions'
|
||||
import { withValueLimit } from './swap/SwapForm'
|
||||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import Tooltip from '@components/shared/Tooltip'
|
||||
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
|
||||
|
@ -33,12 +31,11 @@ import SolBalanceWarnings from '@components/shared/SolBalanceWarnings'
|
|||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
|
||||
interface DepositModalProps {
|
||||
interface DepositFormProps {
|
||||
onSuccess: () => void
|
||||
token?: string
|
||||
}
|
||||
|
||||
type ModalCombinedProps = DepositModalProps & ModalProps
|
||||
|
||||
export const walletBalanceForToken = (
|
||||
walletTokens: TokenAccount[],
|
||||
token: string
|
||||
|
@ -60,7 +57,7 @@ export const walletBalanceForToken = (
|
|||
}
|
||||
}
|
||||
|
||||
function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
||||
function DepositForm({ onSuccess, token }: DepositFormProps) {
|
||||
const { t } = useTranslation('common')
|
||||
const { group } = useMangoGroup()
|
||||
const [inputAmount, setInputAmount] = useState('')
|
||||
|
@ -124,8 +121,8 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
|
||||
if (!mangoAccount || !group || !bank) return
|
||||
|
||||
setSubmitting(true)
|
||||
try {
|
||||
setSubmitting(true)
|
||||
const tx = await client.tokenDeposit(
|
||||
group,
|
||||
mangoAccount,
|
||||
|
@ -140,7 +137,6 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
|
||||
await actions.reloadMangoAccount()
|
||||
actions.fetchWalletTokens(wallet!.adapter as unknown as Wallet)
|
||||
setSubmitting(false)
|
||||
} catch (e: any) {
|
||||
notify({
|
||||
title: 'Transaction failed',
|
||||
|
@ -149,10 +145,11 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
type: 'error',
|
||||
})
|
||||
console.error('Error depositing:', e)
|
||||
} finally {
|
||||
setSubmitting(false)
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
onClose()
|
||||
}, [bank, wallet, inputAmount, onClose])
|
||||
}, [bank, wallet, inputAmount])
|
||||
|
||||
// TODO extract into a shared hook for UserSetup.tsx
|
||||
const banks = useMemo(() => {
|
||||
|
@ -194,12 +191,14 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
const showInsufficientBalance = tokenMax.maxAmount < Number(inputAmount)
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<>
|
||||
<EnterBottomExitBottom
|
||||
className="absolute bottom-0 left-0 z-20 h-full w-full overflow-auto rounded-lg bg-th-bkg-1 p-6"
|
||||
show={showTokenList}
|
||||
>
|
||||
<h2 className="mb-4 text-center">{t('select-token')}</h2>
|
||||
<h2 className="mb-4 text-center text-lg">
|
||||
{t('select-deposit-token')}
|
||||
</h2>
|
||||
<div className="grid auto-cols-fr grid-flow-col px-4 pb-2">
|
||||
<div className="text-left">
|
||||
<p className="text-xs">{t('token')}</p>
|
||||
|
@ -221,13 +220,12 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
</EnterBottomExitBottom>
|
||||
<FadeInFadeOut
|
||||
className="flex h-full flex-col justify-between"
|
||||
show={isOpen}
|
||||
show={!showTokenList}
|
||||
>
|
||||
<div>
|
||||
<h2 className="mb-2 text-center">{t('deposit')}</h2>
|
||||
<InlineNotification
|
||||
type="info"
|
||||
desc={`There is a $${ALPHA_DEPOSIT_LIMIT} deposit limit during alpha
|
||||
desc={`There is a $${ALPHA_DEPOSIT_LIMIT} account value limit during alpha
|
||||
testing.`}
|
||||
/>
|
||||
<SolBalanceWarnings
|
||||
|
@ -237,7 +235,7 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
/>
|
||||
<div className="mt-4 grid grid-cols-2">
|
||||
<div className="col-span-2 flex justify-between">
|
||||
<Label text={t('token')} />
|
||||
<Label text={`${t('deposit')} ${t('token')}`} />
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
label={t('wallet-balance')}
|
||||
|
@ -312,14 +310,14 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
: '-'}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
{/* <div className="flex justify-between">
|
||||
<div className="flex items-center">
|
||||
<Tooltip content={t('asset-weight-desc')}>
|
||||
<p className="tooltip-underline">{t('asset-weight')}</p>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<p className="font-mono">{bank!.initAssetWeight.toFixed(2)}x</p>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="flex justify-between">
|
||||
<Tooltip content={t('tooltip-collateral-value')}>
|
||||
<p className="tooltip-underline">{t('collateral-value')}</p>
|
||||
|
@ -360,8 +358,8 @@ function DepositModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
|||
</Button>
|
||||
</div>
|
||||
</FadeInFadeOut>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DepositModal
|
||||
export default DepositForm
|
|
@ -167,7 +167,7 @@ const SideNav = ({ collapsed }: { collapsed: boolean }) => {
|
|||
alignBottom
|
||||
hideIconBg
|
||||
>
|
||||
<div className="px-4 pb-4 pt-2">
|
||||
<div className="px-4 py-2">
|
||||
<MangoAccountSummary />
|
||||
</div>
|
||||
</ExpandableMenuItem>
|
||||
|
|
|
@ -21,8 +21,6 @@ import {
|
|||
import { breakpoints } from '../utils/theme'
|
||||
import Switch from './forms/Switch'
|
||||
import BorrowModal from './modals/BorrowModal'
|
||||
import DepositModal from './modals/DepositModal'
|
||||
import WithdrawModal from './modals/WithdrawModal'
|
||||
import { IconButton, LinkButton } from './shared/Button'
|
||||
import ContentBox from './shared/ContentBox'
|
||||
import IconDropMenu from './shared/IconDropMenu'
|
||||
|
@ -33,6 +31,7 @@ import useMangoAccount from 'hooks/useMangoAccount'
|
|||
import useJupiterMints from '../hooks/useJupiterMints'
|
||||
import { Table, Td, Th, TrBody, TrHead } from './shared/TableElements'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import DepositWithdrawModal from './modals/DepositWithdrawModal'
|
||||
|
||||
const TokenList = () => {
|
||||
const { t } = useTranslation(['common', 'token', 'trade'])
|
||||
|
@ -554,14 +553,16 @@ const ActionsMenu = ({
|
|||
</LinkButton> */}
|
||||
</IconDropMenu>
|
||||
{showDepositModal ? (
|
||||
<DepositModal
|
||||
<DepositWithdrawModal
|
||||
action="deposit"
|
||||
isOpen={showDepositModal}
|
||||
onClose={() => setShowDepositModal(false)}
|
||||
token={selectedToken}
|
||||
/>
|
||||
) : null}
|
||||
{showWithdrawModal ? (
|
||||
<WithdrawModal
|
||||
<DepositWithdrawModal
|
||||
action="withdraw"
|
||||
isOpen={showWithdrawModal}
|
||||
onClose={() => setShowWithdrawModal(false)}
|
||||
token={selectedToken}
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import WalletIcon from './icons/WalletIcon'
|
||||
import { IconButton } from './shared/Button'
|
||||
import Button, { IconButton } from './shared/Button'
|
||||
import ConnectedMenu from './wallet/ConnectedMenu'
|
||||
import { ConnectWalletButton } from './wallet/ConnectWalletButton'
|
||||
import { IS_ONBOARDED_KEY } from '../utils/constants'
|
||||
|
@ -23,7 +23,8 @@ import useOnlineStatus from 'hooks/useOnlineStatus'
|
|||
import { DEFAULT_DELEGATE } from './modals/DelegateModal'
|
||||
import Tooltip from './shared/Tooltip'
|
||||
import { abbreviateAddress } from 'utils/formatting'
|
||||
import ThemeSwitcher from './ThemeSwitcher'
|
||||
import DepositWithdrawModal from './modals/DepositWithdrawModal'
|
||||
// import ThemeSwitcher from './ThemeSwitcher'
|
||||
|
||||
const TopBar = () => {
|
||||
const { t } = useTranslation('common')
|
||||
|
@ -33,6 +34,8 @@ const TopBar = () => {
|
|||
const [showUserSetup, setShowUserSetup] = useState(false)
|
||||
const [showCreateAccountModal, setShowCreateAccountModal] = useState(false)
|
||||
const [showMangoAccountsModal, setShowMangoAccountsModal] = useState(false)
|
||||
const [showDepositWithdrawModal, setShowDepositWithdrawModal] =
|
||||
useState(false)
|
||||
const isOnline = useOnlineStatus()
|
||||
const router = useRouter()
|
||||
const { query } = router
|
||||
|
@ -92,11 +95,16 @@ const TopBar = () => {
|
|||
</div>
|
||||
) : null}
|
||||
<div className="flex items-center">
|
||||
<div className="px-3 md:px-4">
|
||||
{/* <div className="px-3 md:px-4">
|
||||
<ThemeSwitcher />
|
||||
</div>
|
||||
</div> */}
|
||||
{connected ? (
|
||||
<div className="flex items-center pr-4 md:pr-0">
|
||||
<Button
|
||||
onClick={() => setShowDepositWithdrawModal(true)}
|
||||
secondary
|
||||
className="mx-4"
|
||||
>{`${t('deposit')} / ${t('withdraw')}`}</Button>
|
||||
<button
|
||||
className="hidden h-16 border-l border-th-bkg-3 px-4 md:block"
|
||||
id="account-step-two"
|
||||
|
@ -142,6 +150,13 @@ const TopBar = () => {
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
{showDepositWithdrawModal ? (
|
||||
<DepositWithdrawModal
|
||||
action="deposit"
|
||||
isOpen={showDepositWithdrawModal}
|
||||
onClose={() => setShowDepositWithdrawModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
{showMangoAccountsModal ? (
|
||||
<MangoAccountsListModal
|
||||
isOpen={showMangoAccountsModal}
|
||||
|
|
|
@ -34,7 +34,7 @@ import ButtonGroup from './forms/ButtonGroup'
|
|||
import Input from './forms/Input'
|
||||
import Label from './forms/Label'
|
||||
import WalletIcon from './icons/WalletIcon'
|
||||
import { walletBalanceForToken } from './modals/DepositModal'
|
||||
import { walletBalanceForToken } from './DepositForm'
|
||||
import ParticlesBackground from './ParticlesBackground'
|
||||
import EditNftProfilePic from './profile/EditNftProfilePic'
|
||||
import EditProfileForm from './profile/EditProfileForm'
|
||||
|
@ -393,7 +393,7 @@ const UserSetup = ({ onClose }: { onClose: () => void }) => {
|
|||
<div className="mb-4">
|
||||
<InlineNotification
|
||||
type="info"
|
||||
desc={`There is a $${ALPHA_DEPOSIT_LIMIT} deposit limit during alpha testing.`}
|
||||
desc={`There is a $${ALPHA_DEPOSIT_LIMIT} account value limit during alpha testing.`}
|
||||
/>
|
||||
<SolBalanceWarnings
|
||||
amount={depositAmount}
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
import { Bank, HealthType } from '@blockworks-foundation/mango-v4'
|
||||
import {
|
||||
ArrowUpTrayIcon,
|
||||
ChevronDownIcon,
|
||||
ExclamationCircleIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import Decimal from 'decimal.js'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Image from 'next/legacy/image'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { INPUT_TOKEN_DEFAULT } from './../utils/constants'
|
||||
import { notify } from './../utils/notifications'
|
||||
import { floorToDecimal, formatFixedDecimals } from './../utils/numbers'
|
||||
import ActionTokenList from './account/ActionTokenList'
|
||||
import ButtonGroup from './forms/ButtonGroup'
|
||||
import Label from './forms/Label'
|
||||
import Button from './shared/Button'
|
||||
import InlineNotification from './shared/InlineNotification'
|
||||
import Loading from './shared/Loading'
|
||||
import { EnterBottomExitBottom, FadeInFadeOut } from './shared/Transitions'
|
||||
import { withValueLimit } from './swap/SwapForm'
|
||||
import { getMaxWithdrawForBank } from './swap/useTokenMax'
|
||||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import TokenVaultWarnings from '@components/shared/TokenVaultWarnings'
|
||||
|
||||
interface WithdrawFormProps {
|
||||
onSuccess: () => void
|
||||
token?: string
|
||||
}
|
||||
|
||||
function WithdrawForm({ onSuccess, token }: WithdrawFormProps) {
|
||||
const { t } = useTranslation(['common', 'trade'])
|
||||
const { group } = useMangoGroup()
|
||||
const [inputAmount, setInputAmount] = useState('')
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [selectedToken, setSelectedToken] = useState(
|
||||
token || INPUT_TOKEN_DEFAULT
|
||||
)
|
||||
const [showTokenList, setShowTokenList] = useState(false)
|
||||
const [sizePercentage, setSizePercentage] = useState('')
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
|
||||
const bank = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
return group?.banksMapByName.get(selectedToken)?.[0]
|
||||
}, [selectedToken])
|
||||
|
||||
const logoUri = useMemo(() => {
|
||||
let logoURI
|
||||
if (mangoTokens?.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank?.mint.toString()
|
||||
)?.logoURI
|
||||
}
|
||||
return logoURI
|
||||
}, [bank?.mint, mangoTokens])
|
||||
|
||||
const tokenMax = useMemo(() => {
|
||||
if (!bank || !mangoAccount || !group) return new Decimal(0)
|
||||
const amount = getMaxWithdrawForBank(group, bank, mangoAccount)
|
||||
|
||||
return amount && amount.gt(0)
|
||||
? floorToDecimal(amount, bank.mintDecimals)
|
||||
: new Decimal(0)
|
||||
}, [mangoAccount, bank, group])
|
||||
|
||||
const handleSizePercentage = useCallback(
|
||||
(percentage: string) => {
|
||||
setSizePercentage(percentage)
|
||||
const amount = tokenMax.mul(Number(percentage) / 100)
|
||||
setInputAmount(amount.toFixed())
|
||||
},
|
||||
[tokenMax]
|
||||
)
|
||||
|
||||
const handleWithdraw = useCallback(async () => {
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
const actions = mangoStore.getState().actions
|
||||
if (!mangoAccount || !group || !bank) return
|
||||
setSubmitting(true)
|
||||
try {
|
||||
const tx = await client.tokenWithdraw(
|
||||
group,
|
||||
mangoAccount,
|
||||
bank.mint,
|
||||
parseFloat(inputAmount),
|
||||
false
|
||||
)
|
||||
notify({
|
||||
title: 'Transaction confirmed',
|
||||
type: 'success',
|
||||
txid: tx,
|
||||
})
|
||||
actions.reloadMangoAccount()
|
||||
} catch (e: any) {
|
||||
console.error(e)
|
||||
notify({
|
||||
title: 'Transaction failed',
|
||||
description: e.message,
|
||||
txid: e?.txid,
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
setSubmitting(false)
|
||||
onSuccess()
|
||||
}
|
||||
}, [bank, inputAmount])
|
||||
|
||||
const handleSelectToken = useCallback((token: string) => {
|
||||
setSelectedToken(token)
|
||||
setShowTokenList(false)
|
||||
}, [])
|
||||
|
||||
const withdrawBanks = useMemo(() => {
|
||||
if (mangoAccount) {
|
||||
const banks = group?.banksMapByName
|
||||
? Array.from(group?.banksMapByName, ([key, value]) => {
|
||||
const bank: Bank = value[0]
|
||||
const accountBalance = getMaxWithdrawForBank(
|
||||
group,
|
||||
bank,
|
||||
mangoAccount
|
||||
)
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
accountBalance: accountBalance
|
||||
? floorToDecimal(accountBalance, bank.mintDecimals).toNumber()
|
||||
: 0,
|
||||
accountBalanceValue:
|
||||
accountBalance && bank.uiPrice
|
||||
? accountBalance.toNumber() * bank.uiPrice
|
||||
: 0,
|
||||
}
|
||||
})
|
||||
: []
|
||||
return banks
|
||||
}
|
||||
return []
|
||||
}, [mangoAccount, group])
|
||||
|
||||
const initHealth = useMemo(() => {
|
||||
return group && mangoAccount
|
||||
? mangoAccount.getHealthRatioUi(group, HealthType.init)
|
||||
: 100
|
||||
}, [mangoAccount])
|
||||
|
||||
const showInsufficientBalance = Number(inputAmount)
|
||||
? tokenMax.lt(inputAmount)
|
||||
: false
|
||||
|
||||
return (
|
||||
<>
|
||||
<EnterBottomExitBottom
|
||||
className="absolute bottom-0 left-0 z-20 h-full w-full overflow-auto rounded-lg bg-th-bkg-1 p-6"
|
||||
show={showTokenList}
|
||||
>
|
||||
<h2 className="mb-4 text-center text-lg">
|
||||
{t('select-withdraw-token')}
|
||||
</h2>
|
||||
<div className="grid auto-cols-fr grid-flow-col px-4 pb-2">
|
||||
<div className="text-left">
|
||||
<p className="text-xs">{t('token')}</p>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<p className="text-xs">{t('available-balance')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ActionTokenList
|
||||
banks={withdrawBanks}
|
||||
onSelect={handleSelectToken}
|
||||
sortByKey="accountBalanceValue"
|
||||
valueKey="accountBalance"
|
||||
/>
|
||||
</EnterBottomExitBottom>
|
||||
<FadeInFadeOut
|
||||
className="flex h-[386px] flex-col justify-between"
|
||||
show={!showTokenList}
|
||||
>
|
||||
<div>
|
||||
{initHealth <= 0 ? (
|
||||
<div className="mb-4">
|
||||
<InlineNotification
|
||||
type="error"
|
||||
desc="You have no available collateral to withdraw."
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="grid grid-cols-2">
|
||||
<div className="col-span-2 flex justify-between">
|
||||
<Label text={`${t('withdraw')} ${t('token')}`} />
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
label={t('max')}
|
||||
onClick={() => handleSizePercentage('100')}
|
||||
value={tokenMax.toString()}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-input-border bg-th-input-bkg">
|
||||
<button
|
||||
onClick={() => setShowTokenList(true)}
|
||||
className="default-transition flex h-full w-full items-center rounded-lg rounded-r-none py-2 px-3 text-th-fgd-2 hover:cursor-pointer hover:bg-th-bkg-2 hover:text-th-fgd-1"
|
||||
>
|
||||
<div className="mr-2.5 flex min-w-[24px] items-center">
|
||||
<Image
|
||||
alt=""
|
||||
width="24"
|
||||
height="24"
|
||||
src={logoUri || `/icons/${selectedToken.toLowerCase()}.svg`}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="text-xl font-bold">{selectedToken}</div>
|
||||
<ChevronDownIcon className="h-6 w-6" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<NumberFormat
|
||||
name="amountIn"
|
||||
id="amountIn"
|
||||
inputMode="decimal"
|
||||
thousandSeparator=","
|
||||
allowNegative={false}
|
||||
isNumericString={true}
|
||||
decimalScale={bank?.mintDecimals || 6}
|
||||
className="w-full rounded-lg rounded-l-none border border-th-input-border bg-th-input-bkg p-3 text-right font-mono text-xl tracking-wider text-th-fgd-1 focus:border-th-input-border-hover focus:outline-none md:hover:border-th-input-border-hover"
|
||||
placeholder="0.00"
|
||||
value={inputAmount}
|
||||
onValueChange={(e: NumberFormatValues) =>
|
||||
setInputAmount(!Number.isNaN(Number(e.value)) ? e.value : '')
|
||||
}
|
||||
isAllowed={withValueLimit}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 mt-2">
|
||||
<ButtonGroup
|
||||
activeValue={sizePercentage}
|
||||
className="font-mono"
|
||||
onChange={(p) => handleSizePercentage(p)}
|
||||
values={['10', '25', '50', '75', '100']}
|
||||
unit="%"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-6 space-y-2 border-y border-th-bkg-3 px-2 py-4">
|
||||
<HealthImpactTokenChange
|
||||
mintPk={bank!.mint}
|
||||
uiAmount={Number(inputAmount)}
|
||||
/>
|
||||
<div className="flex justify-between">
|
||||
<p>{t('withdraw-value')}</p>
|
||||
<p className="font-mono text-th-fgd-1">
|
||||
{bank?.uiPrice
|
||||
? formatFixedDecimals(
|
||||
bank.uiPrice * Number(inputAmount),
|
||||
true
|
||||
)
|
||||
: '-'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<Button
|
||||
onClick={handleWithdraw}
|
||||
className="flex w-full items-center justify-center"
|
||||
size="large"
|
||||
disabled={
|
||||
!inputAmount || showInsufficientBalance || initHealth <= 0
|
||||
}
|
||||
>
|
||||
{submitting ? (
|
||||
<Loading className="mr-2 h-5 w-5" />
|
||||
) : showInsufficientBalance ? (
|
||||
<div className="flex items-center">
|
||||
<ExclamationCircleIcon className="mr-2 h-5 w-5 flex-shrink-0" />
|
||||
{t('swap:insufficient-balance', {
|
||||
symbol: selectedToken,
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center">
|
||||
<ArrowUpTrayIcon className="mr-2 h-5 w-5" />
|
||||
{t('withdraw')}
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
{bank ? (
|
||||
<div className="pt-4">
|
||||
<TokenVaultWarnings bank={bank} />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</FadeInFadeOut>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default WithdrawForm
|
|
@ -1,9 +1,6 @@
|
|||
import { useMemo, useState } from 'react'
|
||||
import Button, { LinkButton } from '../shared/Button'
|
||||
import DepositModal from '../modals/DepositModal'
|
||||
import WithdrawModal from '../modals/WithdrawModal'
|
||||
import {
|
||||
ArrowDownTrayIcon,
|
||||
ArrowUpTrayIcon,
|
||||
BanknotesIcon,
|
||||
DocumentDuplicateIcon,
|
||||
|
@ -27,15 +24,15 @@ import RepayModal from '@components/modals/RepayModal'
|
|||
import DelegateModal from '@components/modals/DelegateModal'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import BorrowModal from '@components/modals/BorrowModal'
|
||||
|
||||
const AccountActions = () => {
|
||||
const { t } = useTranslation(['common', 'close-account'])
|
||||
const { group } = useMangoGroup()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const [showCloseAccountModal, setShowCloseAccountModal] = useState(false)
|
||||
const [showDepositModal, setShowDepositModal] = useState(false)
|
||||
const [showEditAccountModal, setShowEditAccountModal] = useState(false)
|
||||
const [showWithdrawModal, setShowWithdrawModal] = useState(false)
|
||||
const [showBorrowModal, setShowBorrowModal] = useState(false)
|
||||
const [showRepayModal, setShowRepayModal] = useState(false)
|
||||
const [showDelegateModal, setShowDelegateModal] = useState(false)
|
||||
|
||||
|
@ -74,20 +71,11 @@ const AccountActions = () => {
|
|||
<Button
|
||||
className="flex items-center"
|
||||
disabled={!mangoAccount}
|
||||
onClick={() => setShowDepositModal(true)}
|
||||
onClick={() => setShowBorrowModal(true)}
|
||||
secondary={hasBorrows}
|
||||
>
|
||||
<ArrowDownTrayIcon className="mr-2 h-5 w-5" />
|
||||
{t('deposit')}
|
||||
</Button>
|
||||
<Button
|
||||
className="flex items-center"
|
||||
disabled={!mangoAccount}
|
||||
onClick={() => setShowWithdrawModal(true)}
|
||||
secondary
|
||||
>
|
||||
<ArrowUpTrayIcon className="mr-2 h-5 w-5" />
|
||||
{t('withdraw')}
|
||||
{t('borrow')}
|
||||
</Button>
|
||||
<IconDropMenu
|
||||
icon={<EllipsisHorizontalIcon className="h-5 w-5" />}
|
||||
|
@ -135,22 +123,16 @@ const AccountActions = () => {
|
|||
onClose={() => setShowCloseAccountModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
{showDepositModal ? (
|
||||
<DepositModal
|
||||
isOpen={showDepositModal}
|
||||
onClose={() => setShowDepositModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
{showEditAccountModal ? (
|
||||
<AccountNameModal
|
||||
isOpen={showEditAccountModal}
|
||||
onClose={() => setShowEditAccountModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
{showWithdrawModal ? (
|
||||
<WithdrawModal
|
||||
isOpen={showWithdrawModal}
|
||||
onClose={() => setShowWithdrawModal(false)}
|
||||
{showBorrowModal ? (
|
||||
<BorrowModal
|
||||
isOpen={showBorrowModal}
|
||||
onClose={() => setShowBorrowModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
|
|
@ -6,8 +6,6 @@ import { useTranslation } from 'next-i18next'
|
|||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import AccountActions from './AccountActions'
|
||||
import DepositModal from '../modals/DepositModal'
|
||||
import WithdrawModal from '../modals/WithdrawModal'
|
||||
import mangoStore, { PerformanceDataItem } from '@store/mangoStore'
|
||||
import { formatFixedDecimals } from '../../utils/numbers'
|
||||
import FlipNumbers from 'react-flip-numbers'
|
||||
|
@ -64,8 +62,6 @@ const AccountPage = () => {
|
|||
const totalInterestData = mangoStore(
|
||||
(s) => s.mangoAccount.stats.interestTotals.data
|
||||
)
|
||||
const [showDepositModal, setShowDepositModal] = useState<boolean>(false)
|
||||
const [showWithdrawModal, setShowWithdrawModal] = useState<boolean>(false)
|
||||
const [chartToShow, setChartToShow] = useState<
|
||||
'account-value' | 'cumulative-interest-value' | 'pnl' | ''
|
||||
>('')
|
||||
|
@ -492,18 +488,6 @@ const AccountPage = () => {
|
|||
</button>
|
||||
</div>
|
||||
<AccountTabs />
|
||||
{showDepositModal ? (
|
||||
<DepositModal
|
||||
isOpen={showDepositModal}
|
||||
onClose={() => setShowDepositModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
{showWithdrawModal ? (
|
||||
<WithdrawModal
|
||||
isOpen={showWithdrawModal}
|
||||
onClose={() => setShowWithdrawModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
{!tourSettings?.account_tour_seen && isOnBoarded && connected ? (
|
||||
<AccountOnboardingTour />
|
||||
) : null}
|
||||
|
|
|
@ -4,22 +4,13 @@ import {
|
|||
toUiDecimalsForQuote,
|
||||
} from '@blockworks-foundation/mango-v4'
|
||||
import { formatDecimal, formatFixedDecimals } from '../../utils/numbers'
|
||||
import Button from '../shared/Button'
|
||||
import { useState } from 'react'
|
||||
import DepositModal from '../modals/DepositModal'
|
||||
import WithdrawModal from '../modals/WithdrawModal'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { ArrowDownTrayIcon } from '@heroicons/react/20/solid'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
|
||||
const MangoAccountSummary = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const { connected } = useWallet()
|
||||
const group = mangoStore.getState().group
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
const [showDepositModal, setShowDepositModal] = useState(false)
|
||||
const [showWithdrawModal, setShowWithdrawModal] = useState(false)
|
||||
|
||||
// const leverage = useMemo(() => {
|
||||
// if (!group || !mangoAccount) return 0
|
||||
|
@ -36,7 +27,7 @@ const MangoAccountSummary = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-4 space-y-2">
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<p className="text-sm text-th-fgd-3">{t('health')}</p>
|
||||
<p className="font-mono text-sm text-th-fgd-1">
|
||||
|
@ -95,29 +86,6 @@ const MangoAccountSummary = () => {
|
|||
</p>
|
||||
</div> */}
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
className="flex w-full items-center justify-center"
|
||||
disabled={!mangoAccount || !connected}
|
||||
onClick={() => setShowDepositModal(true)}
|
||||
>
|
||||
<ArrowDownTrayIcon className="mr-2 h-5 w-5" />
|
||||
{t('deposit')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{showDepositModal ? (
|
||||
<DepositModal
|
||||
isOpen={showDepositModal}
|
||||
onClose={() => setShowDepositModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
{showWithdrawModal ? (
|
||||
<WithdrawModal
|
||||
isOpen={showWithdrawModal}
|
||||
onClose={() => setShowWithdrawModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ const AccountNameModal = ({ isOpen, onClose }: ModalProps) => {
|
|||
const [loading, setLoading] = useState(false)
|
||||
const [name, setName] = useState(mangoAccount?.name || '')
|
||||
|
||||
// This doesn't work yet...
|
||||
const handleUpdateccountName = async () => {
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import { ModalProps } from '../../types/modal'
|
||||
import Modal from '../shared/Modal'
|
||||
import { useState } from 'react'
|
||||
import TabUnderline from '@components/shared/TabUnderline'
|
||||
import DepositForm from '@components/DepositForm'
|
||||
import WithdrawForm from '@components/WithdrawForm'
|
||||
|
||||
interface DepositWithdrawModalProps {
|
||||
action: 'deposit' | 'withdraw'
|
||||
token?: string
|
||||
}
|
||||
|
||||
type ModalCombinedProps = DepositWithdrawModalProps & ModalProps
|
||||
|
||||
const DepositWithdrawModal = ({
|
||||
action,
|
||||
isOpen,
|
||||
onClose,
|
||||
token,
|
||||
}: ModalCombinedProps) => {
|
||||
const [activeTab, setActiveTab] = useState(action)
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<div className="h-[448px]">
|
||||
<div className="pb-2">
|
||||
<TabUnderline
|
||||
activeValue={activeTab}
|
||||
values={['deposit', 'withdraw']}
|
||||
onChange={(v) => setActiveTab(v)}
|
||||
/>
|
||||
</div>
|
||||
{activeTab === 'deposit' ? (
|
||||
<DepositForm onSuccess={onClose} token={token} />
|
||||
) : null}
|
||||
{activeTab === 'withdraw' ? (
|
||||
<WithdrawForm onSuccess={onClose} token={token} />
|
||||
) : null}
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default DepositWithdrawModal
|
|
@ -25,7 +25,7 @@ import { EnterBottomExitBottom, FadeInFadeOut } from '../shared/Transitions'
|
|||
import { withValueLimit } from '../swap/SwapForm'
|
||||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
|
||||
import { walletBalanceForToken } from './DepositModal'
|
||||
import { walletBalanceForToken } from '../DepositForm'
|
||||
import SolBalanceWarnings from '@components/shared/SolBalanceWarnings'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
|
|
|
@ -1,318 +0,0 @@
|
|||
import { Bank, HealthType } from '@blockworks-foundation/mango-v4'
|
||||
import {
|
||||
ArrowUpTrayIcon,
|
||||
ChevronDownIcon,
|
||||
ExclamationCircleIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import Decimal from 'decimal.js'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Image from 'next/legacy/image'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import NumberFormat, { NumberFormatValues } from 'react-number-format'
|
||||
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { ModalProps } from '../../types/modal'
|
||||
import { INPUT_TOKEN_DEFAULT } from '../../utils/constants'
|
||||
import { notify } from '../../utils/notifications'
|
||||
import { floorToDecimal, formatFixedDecimals } from '../../utils/numbers'
|
||||
import ActionTokenList from '../account/ActionTokenList'
|
||||
import ButtonGroup from '../forms/ButtonGroup'
|
||||
import Label from '../forms/Label'
|
||||
import Button from '../shared/Button'
|
||||
import InlineNotification from '../shared/InlineNotification'
|
||||
import Loading from '../shared/Loading'
|
||||
import Modal from '../shared/Modal'
|
||||
import { EnterBottomExitBottom, FadeInFadeOut } from '../shared/Transitions'
|
||||
import { withValueLimit } from '../swap/SwapForm'
|
||||
import { getMaxWithdrawForBank } from '../swap/useTokenMax'
|
||||
import MaxAmountButton from '@components/shared/MaxAmountButton'
|
||||
import HealthImpactTokenChange from '@components/HealthImpactTokenChange'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import TokenVaultWarnings from '@components/shared/TokenVaultWarnings'
|
||||
|
||||
interface WithdrawModalProps {
|
||||
token?: string
|
||||
}
|
||||
|
||||
type ModalCombinedProps = WithdrawModalProps & ModalProps
|
||||
|
||||
function WithdrawModal({ isOpen, onClose, token }: ModalCombinedProps) {
|
||||
const { t } = useTranslation(['common', 'trade'])
|
||||
const { group } = useMangoGroup()
|
||||
const [inputAmount, setInputAmount] = useState('')
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [selectedToken, setSelectedToken] = useState(
|
||||
token || INPUT_TOKEN_DEFAULT
|
||||
)
|
||||
const [showTokenList, setShowTokenList] = useState(false)
|
||||
const [sizePercentage, setSizePercentage] = useState('')
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { mangoAccount } = useMangoAccount()
|
||||
|
||||
const bank = useMemo(() => {
|
||||
const group = mangoStore.getState().group
|
||||
return group?.banksMapByName.get(selectedToken)?.[0]
|
||||
}, [selectedToken])
|
||||
|
||||
const logoUri = useMemo(() => {
|
||||
let logoURI
|
||||
if (mangoTokens?.length) {
|
||||
logoURI = mangoTokens.find(
|
||||
(t) => t.address === bank?.mint.toString()
|
||||
)?.logoURI
|
||||
}
|
||||
return logoURI
|
||||
}, [bank?.mint, mangoTokens])
|
||||
|
||||
const tokenMax = useMemo(() => {
|
||||
if (!bank || !mangoAccount || !group) return new Decimal(0)
|
||||
const amount = getMaxWithdrawForBank(group, bank, mangoAccount)
|
||||
|
||||
return amount && amount.gt(0)
|
||||
? floorToDecimal(amount, bank.mintDecimals)
|
||||
: new Decimal(0)
|
||||
}, [mangoAccount, bank, group])
|
||||
|
||||
const handleSizePercentage = useCallback(
|
||||
(percentage: string) => {
|
||||
setSizePercentage(percentage)
|
||||
const amount = tokenMax.mul(Number(percentage) / 100)
|
||||
setInputAmount(amount.toFixed())
|
||||
},
|
||||
[tokenMax]
|
||||
)
|
||||
|
||||
const handleWithdraw = useCallback(async () => {
|
||||
const client = mangoStore.getState().client
|
||||
const group = mangoStore.getState().group
|
||||
const mangoAccount = mangoStore.getState().mangoAccount.current
|
||||
const actions = mangoStore.getState().actions
|
||||
if (!mangoAccount || !group || !bank) return
|
||||
setSubmitting(true)
|
||||
try {
|
||||
const tx = await client.tokenWithdraw(
|
||||
group,
|
||||
mangoAccount,
|
||||
bank.mint,
|
||||
parseFloat(inputAmount),
|
||||
false
|
||||
)
|
||||
notify({
|
||||
title: 'Transaction confirmed',
|
||||
type: 'success',
|
||||
txid: tx,
|
||||
})
|
||||
actions.reloadMangoAccount()
|
||||
} catch (e: any) {
|
||||
console.error(e)
|
||||
notify({
|
||||
title: 'Transaction failed',
|
||||
description: e.message,
|
||||
txid: e?.txid,
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
setSubmitting(false)
|
||||
onClose()
|
||||
}
|
||||
}, [bank, inputAmount])
|
||||
|
||||
const handleSelectToken = useCallback((token: string) => {
|
||||
setSelectedToken(token)
|
||||
setShowTokenList(false)
|
||||
}, [])
|
||||
|
||||
const withdrawBanks = useMemo(() => {
|
||||
if (mangoAccount) {
|
||||
const banks = group?.banksMapByName
|
||||
? Array.from(group?.banksMapByName, ([key, value]) => {
|
||||
const bank: Bank = value[0]
|
||||
const accountBalance = getMaxWithdrawForBank(
|
||||
group,
|
||||
bank,
|
||||
mangoAccount
|
||||
)
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
accountBalance: accountBalance
|
||||
? floorToDecimal(accountBalance, bank.mintDecimals).toNumber()
|
||||
: 0,
|
||||
accountBalanceValue:
|
||||
accountBalance && bank.uiPrice
|
||||
? accountBalance.toNumber() * bank.uiPrice
|
||||
: 0,
|
||||
}
|
||||
})
|
||||
: []
|
||||
return banks
|
||||
}
|
||||
return []
|
||||
}, [mangoAccount, group])
|
||||
|
||||
const initHealth = useMemo(() => {
|
||||
return group && mangoAccount
|
||||
? mangoAccount.getHealthRatioUi(group, HealthType.init)
|
||||
: 100
|
||||
}, [mangoAccount])
|
||||
|
||||
const showInsufficientBalance = Number(inputAmount)
|
||||
? tokenMax.lt(inputAmount)
|
||||
: false
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
<div className="">
|
||||
<EnterBottomExitBottom
|
||||
className="absolute bottom-0 left-0 z-20 h-full w-full overflow-auto rounded-lg bg-th-bkg-1 p-6"
|
||||
show={showTokenList}
|
||||
>
|
||||
<h2 className="mb-4 text-center">{t('select-token')}</h2>
|
||||
<div className="grid auto-cols-fr grid-flow-col px-4 pb-2">
|
||||
<div className="text-left">
|
||||
<p className="text-xs">{t('token')}</p>
|
||||
</div>
|
||||
<div className="flex justify-end">
|
||||
<p className="text-xs">{t('available-balance')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ActionTokenList
|
||||
banks={withdrawBanks}
|
||||
onSelect={handleSelectToken}
|
||||
sortByKey="accountBalanceValue"
|
||||
valueKey="accountBalance"
|
||||
/>
|
||||
</EnterBottomExitBottom>
|
||||
<FadeInFadeOut
|
||||
className="flex h-full flex-col justify-between"
|
||||
show={isOpen}
|
||||
>
|
||||
<div>
|
||||
<h2 className="mb-4 text-center">{t('withdraw')}</h2>
|
||||
{initHealth <= 0 ? (
|
||||
<div className="mb-4">
|
||||
<InlineNotification
|
||||
type="error"
|
||||
desc="You have no available collateral to withdraw."
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="grid grid-cols-2">
|
||||
<div className="col-span-2 flex justify-between">
|
||||
<Label text={t('token')} />
|
||||
<MaxAmountButton
|
||||
className="mb-2"
|
||||
label={t('max')}
|
||||
onClick={() => handleSizePercentage('100')}
|
||||
value={tokenMax.toString()}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-1 rounded-lg rounded-r-none border border-r-0 border-th-input-border bg-th-input-bkg">
|
||||
<button
|
||||
onClick={() => setShowTokenList(true)}
|
||||
className="default-transition flex h-full w-full items-center rounded-lg rounded-r-none py-2 px-3 text-th-fgd-2 hover:cursor-pointer hover:bg-th-bkg-2 hover:text-th-fgd-1"
|
||||
>
|
||||
<div className="mr-2.5 flex min-w-[24px] items-center">
|
||||
<Image
|
||||
alt=""
|
||||
width="24"
|
||||
height="24"
|
||||
src={
|
||||
logoUri || `/icons/${selectedToken.toLowerCase()}.svg`
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="text-xl font-bold">{selectedToken}</div>
|
||||
<ChevronDownIcon className="h-6 w-6" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<NumberFormat
|
||||
name="amountIn"
|
||||
id="amountIn"
|
||||
inputMode="decimal"
|
||||
thousandSeparator=","
|
||||
allowNegative={false}
|
||||
isNumericString={true}
|
||||
decimalScale={bank?.mintDecimals || 6}
|
||||
className="w-full rounded-lg rounded-l-none border border-th-input-border bg-th-input-bkg p-3 text-right font-mono text-xl tracking-wider text-th-fgd-1 focus:border-th-input-border-hover focus:outline-none md:hover:border-th-input-border-hover"
|
||||
placeholder="0.00"
|
||||
value={inputAmount}
|
||||
onValueChange={(e: NumberFormatValues) =>
|
||||
setInputAmount(
|
||||
!Number.isNaN(Number(e.value)) ? e.value : ''
|
||||
)
|
||||
}
|
||||
isAllowed={withValueLimit}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 mt-2">
|
||||
<ButtonGroup
|
||||
activeValue={sizePercentage}
|
||||
className="font-mono"
|
||||
onChange={(p) => handleSizePercentage(p)}
|
||||
values={['10', '25', '50', '75', '100']}
|
||||
unit="%"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-6 space-y-2 border-y border-th-bkg-3 px-2 py-4">
|
||||
<HealthImpactTokenChange
|
||||
mintPk={bank!.mint}
|
||||
uiAmount={Number(inputAmount)}
|
||||
/>
|
||||
<div className="flex justify-between">
|
||||
<p>{t('withdrawal-value')}</p>
|
||||
<p className="font-mono text-th-fgd-1">
|
||||
{bank?.uiPrice
|
||||
? formatFixedDecimals(
|
||||
bank.uiPrice * Number(inputAmount),
|
||||
true
|
||||
)
|
||||
: '-'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<Button
|
||||
onClick={handleWithdraw}
|
||||
className="flex w-full items-center justify-center"
|
||||
size="large"
|
||||
disabled={
|
||||
!inputAmount || showInsufficientBalance || initHealth <= 0
|
||||
}
|
||||
>
|
||||
{submitting ? (
|
||||
<Loading className="mr-2 h-5 w-5" />
|
||||
) : showInsufficientBalance ? (
|
||||
<div className="flex items-center">
|
||||
<ExclamationCircleIcon className="mr-2 h-5 w-5 flex-shrink-0" />
|
||||
{t('swap:insufficient-balance', {
|
||||
symbol: selectedToken,
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center">
|
||||
<ArrowUpTrayIcon className="mr-2 h-5 w-5" />
|
||||
{t('withdraw')}
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
{bank ? (
|
||||
<div className="pt-4">
|
||||
<TokenVaultWarnings bank={bank} />
|
||||
</div>
|
||||
) : null}
|
||||
</FadeInFadeOut>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default WithdrawModal
|
|
@ -1,6 +1,6 @@
|
|||
import { Bank } from '@blockworks-foundation/mango-v4'
|
||||
import BorrowModal from '@components/modals/BorrowModal'
|
||||
import DepositModal from '@components/modals/DepositModal'
|
||||
import DepositWithdrawModal from '@components/modals/DepositWithdrawModal'
|
||||
import Button from '@components/shared/Button'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import useMangoAccount from 'hooks/useMangoAccount'
|
||||
|
@ -87,7 +87,8 @@ const ActionPanel = ({ bank }: { bank: Bank }) => {
|
|||
</div>
|
||||
</div>
|
||||
{showDepositModal ? (
|
||||
<DepositModal
|
||||
<DepositWithdrawModal
|
||||
action="deposit"
|
||||
isOpen={showDepositModal}
|
||||
onClose={() => setShowDepositModal(false)}
|
||||
token={bank!.name}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"borrow": "Borrow",
|
||||
"borrow-amount": "Borrow Amount",
|
||||
"borrow-fee": "Borrow Fee",
|
||||
"borrow-funds": "Borrow Funds",
|
||||
"borrow-rate": "Borrow Rate (APR)",
|
||||
"borrow-value": "Borrow Value",
|
||||
"buy": "Buy",
|
||||
|
@ -93,7 +94,9 @@
|
|||
"repayment-value": "Repayment Value",
|
||||
"rolling-change": "24h Change",
|
||||
"save": "Save",
|
||||
"select-deposit-token": "Select Deposit Token",
|
||||
"select-token": "Select Token",
|
||||
"select-withdraw-token": "Select Withdraw Token",
|
||||
"sell": "Sell",
|
||||
"settings": "Settings",
|
||||
"show-zero-balances": "Show Zero Balances",
|
||||
|
@ -127,6 +130,6 @@
|
|||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
"withdrawal-value": "Withdrawal Value"
|
||||
"withdraw-value": "Withdraw Value"
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
"borrow": "Borrow",
|
||||
"borrow-amount": "Borrow Amount",
|
||||
"borrow-fee": "Borrow Fee",
|
||||
"borrow-funds": "Borrow Funds",
|
||||
"borrow-rate": "Borrow Rate (APR)",
|
||||
"borrow-value": "Borrow Value",
|
||||
"buy": "Buy",
|
||||
|
@ -93,7 +94,9 @@
|
|||
"repayment-value": "Repayment Value",
|
||||
"rolling-change": "24h Change",
|
||||
"save": "Save",
|
||||
"select-deposit-token": "Select Deposit Token",
|
||||
"select-token": "Select Token",
|
||||
"select-withdraw-token": "Select Withdraw Token",
|
||||
"sell": "Sell",
|
||||
"settings": "Settings",
|
||||
"show-zero-balances": "Show Zero Balances",
|
||||
|
@ -127,6 +130,6 @@
|
|||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
"withdrawal-value": "Withdrawal Value"
|
||||
"withdraw-value": "Withdraw Value"
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
"borrow": "Borrow",
|
||||
"borrow-amount": "Borrow Amount",
|
||||
"borrow-fee": "Borrow Fee",
|
||||
"borrow-funds": "Borrow Funds",
|
||||
"borrow-rate": "Borrow Rate (APR)",
|
||||
"borrow-value": "Borrow Value",
|
||||
"buy": "Buy",
|
||||
|
@ -93,7 +94,9 @@
|
|||
"repayment-value": "Repayment Value",
|
||||
"rolling-change": "24h Change",
|
||||
"save": "Save",
|
||||
"select-deposit-token": "Select Deposit Token",
|
||||
"select-token": "Select Token",
|
||||
"select-withdraw-token": "Select Withdraw Token",
|
||||
"sell": "Sell",
|
||||
"settings": "Settings",
|
||||
"show-zero-balances": "Show Zero Balances",
|
||||
|
@ -127,6 +130,6 @@
|
|||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
"withdrawal-value": "Withdrawal Value"
|
||||
"withdraw-value": "Withdraw Value"
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
"borrow": "Borrow",
|
||||
"borrow-amount": "Borrow Amount",
|
||||
"borrow-fee": "Borrow Fee",
|
||||
"borrow-funds": "Borrow Funds",
|
||||
"borrow-rate": "Borrow Rate (APR)",
|
||||
"borrow-value": "Borrow Value",
|
||||
"buy": "Buy",
|
||||
|
@ -93,7 +94,9 @@
|
|||
"repayment-value": "Repayment Value",
|
||||
"rolling-change": "24h Change",
|
||||
"save": "Save",
|
||||
"select-deposit-token": "Select Deposit Token",
|
||||
"select-token": "Select Token",
|
||||
"select-withdraw-token": "Select Withdraw Token",
|
||||
"sell": "Sell",
|
||||
"settings": "Settings",
|
||||
"show-zero-balances": "Show Zero Balances",
|
||||
|
@ -127,6 +130,6 @@
|
|||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
"withdrawal-value": "Withdrawal Value"
|
||||
"withdraw-value": "Withdraw Value"
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
"borrow": "Borrow",
|
||||
"borrow-amount": "Borrow Amount",
|
||||
"borrow-fee": "Borrow Fee",
|
||||
"borrow-funds": "Borrow Funds",
|
||||
"borrow-rate": "Borrow Rate (APR)",
|
||||
"borrow-value": "Borrow Value",
|
||||
"buy": "Buy",
|
||||
|
@ -93,7 +94,9 @@
|
|||
"repayment-value": "Repayment Value",
|
||||
"rolling-change": "24h Change",
|
||||
"save": "Save",
|
||||
"select-deposit-token": "Select Deposit Token",
|
||||
"select-token": "Select Token",
|
||||
"select-withdraw-token": "Select Withdraw Token",
|
||||
"sell": "Sell",
|
||||
"settings": "Settings",
|
||||
"show-zero-balances": "Show Zero Balances",
|
||||
|
@ -127,6 +130,6 @@
|
|||
"wallet-balance": "Wallet Balance",
|
||||
"wallet-disconnected": "Disconnected from wallet",
|
||||
"withdraw": "Withdraw",
|
||||
"withdrawal-value": "Withdrawal Value"
|
||||
"withdraw-value": "Withdraw Value"
|
||||
}
|
||||
|
Loading…
Reference in New Issue