mars-v2-frontend/src/components/Account/AccountFund.tsx
2023-08-04 15:10:30 +02:00

172 lines
6.1 KiB
TypeScript

import { useCallback, useEffect, useMemo, useState } from 'react'
import { useParams } from 'react-router-dom'
import Button from 'components/Button'
import Card from 'components/Card'
import FullOverlayContent from 'components/FullOverlayContent'
import { Plus } from 'components/Icons'
import SwitchWithLabel from 'components/SwitchWithLabel'
import Text from 'components/Text'
import TokenInputWithSlider from 'components/TokenInput/TokenInputWithSlider'
import WalletBridges from 'components/Wallet/WalletBridges'
import { BN_ZERO } from 'constants/math'
import useAccounts from 'hooks/useAccounts'
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
import useCurrentAccount from 'hooks/useCurrentAccount'
import useToggle from 'hooks/useToggle'
import useWalletBalances from 'hooks/useWalletBalances'
import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin'
import { byDenom } from 'utils/array'
import { getAssetByDenom, getBaseAsset } from 'utils/assets'
import { hardcodedFee } from 'utils/constants'
import { BN } from 'utils/helpers'
export default function AccountFund() {
const address = useStore((s) => s.address)
const deposit = useStore((s) => s.deposit)
const walletAssetModal = useStore((s) => s.walletAssetsModal)
const { accountId } = useParams()
const { data: accounts } = useAccounts(address)
const currentAccount = useCurrentAccount()
const [isFunding, setIsFunding] = useToggle(false)
const [selectedAccountId, setSelectedAccountId] = useState<null | string>(null)
const [fundingAssets, setFundingAssets] = useState<BNCoin[]>([])
const { data: walletBalances } = useWalletBalances(address)
const baseAsset = getBaseAsset()
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(accountId ?? '0')
const hasAssetSelected = fundingAssets.length > 0
const hasFundingAssets =
fundingAssets.length > 0 && fundingAssets.every((a) => a.toCoin().amount !== '0')
const baseBalance = useMemo(
() => walletBalances.find(byDenom(baseAsset.denom))?.amount ?? '0',
[walletBalances, baseAsset],
)
const selectedDenoms = useMemo(() => {
return walletAssetModal?.selectedDenoms ?? []
}, [walletAssetModal?.selectedDenoms])
const handleClick = useCallback(async () => {
setIsFunding(true)
if (!accountId) return
const result = await deposit({
fee: hardcodedFee,
accountId,
coins: fundingAssets,
})
setIsFunding(false)
if (result) useStore.setState({ focusComponent: null, walletAssetsModal: null })
}, [fundingAssets, accountId, setIsFunding, deposit])
const handleSelectAssetsClick = useCallback(() => {
useStore.setState({
walletAssetsModal: {
isOpen: true,
selectedDenoms,
},
})
}, [selectedDenoms])
useEffect(() => {
const currentSelectedDenom = fundingAssets.map((asset) => asset.denom)
if (
selectedDenoms.every((denom) => currentSelectedDenom.includes(denom)) &&
selectedDenoms.length === currentSelectedDenom.length
)
return
const newFundingAssets = selectedDenoms.map((denom) =>
BNCoin.fromDenomAndBigNumber(denom, BN(fundingAssets.find(byDenom(denom))?.amount ?? '0')),
)
setFundingAssets(newFundingAssets)
}, [selectedDenoms, fundingAssets])
const updateFundingAssets = useCallback(
(amount: BigNumber, denom: string) => {
const assetToUpdate = fundingAssets.find((asset) => asset.denom === denom)
if (assetToUpdate) {
assetToUpdate.amount = amount
setFundingAssets([...fundingAssets.filter((a) => a.denom !== denom), assetToUpdate])
}
},
[fundingAssets],
)
useEffect(() => {
if (BN(baseBalance).isLessThan(hardcodedFee.amount[0].amount)) {
useStore.setState({ focusComponent: <WalletBridges /> })
}
}, [baseBalance])
useEffect(() => {
if (accounts && !selectedAccountId && accountId)
setSelectedAccountId(currentAccount?.id ?? accountId)
}, [accounts, selectedAccountId, accountId, currentAccount])
if (!selectedAccountId) return null
return (
<FullOverlayContent
title={`Fund Credit Account #${selectedAccountId}`}
copy='In order to start trading with this account, you need to deposit funds.'
docs='fund'
>
<Card className='w-full bg-white/5 p-6'>
{!hasAssetSelected && <Text>Please select an asset.</Text>}
{selectedDenoms.map((denom) => {
const asset = getAssetByDenom(denom) as Asset
const balance = walletBalances.find(byDenom(asset.denom))?.amount ?? '0'
return (
<div
key={asset.symbol}
className='w-full rounded-base border border-white/20 bg-white/5 p-4'
>
<TokenInputWithSlider
asset={asset}
onChange={(amount) => updateFundingAssets(amount, asset.denom)}
amount={BN_ZERO}
max={BN(balance)}
balances={walletBalances}
maxText='Max'
/>
</div>
)
})}
<Button
className='mt-4 w-full'
text='Select assets'
color='tertiary'
rightIcon={<Plus />}
iconClassName='w-3'
onClick={handleSelectAssetsClick}
/>
<div className='mt-4 border border-transparent border-t-white/10 pt-4'>
<SwitchWithLabel
name='isLending'
label='Lend assets to earn yield'
value={isAutoLendEnabled}
onChange={() => toggleAutoLend(selectedAccountId)}
tooltip={`Fund your account and lend assets effortlessly! By lending, you'll earn attractive interest (APY) without impacting your LTV. It's a win-win situation - don't miss out on this easy opportunity to grow your holdings!`}
/>
</div>
<Button
className='mt-4 w-full'
text='Fund account'
color='tertiary'
disabled={!hasFundingAssets}
showProgressIndicator={isFunding}
onClick={handleClick}
size='lg'
/>
</Card>
</FullOverlayContent>
)
}