Mp 2681 interact with credit account modal (#189)
* MP-2681: fixed and simplified fund and withdraw ;. : * MP-2352: created the CreditAccountComposition * fix: adjusted according to feedback * fix: fixed funding account max * fix: fix portfolio
This commit is contained in:
parent
78aa6b3089
commit
5c01ec6872
@ -11,13 +11,18 @@ interface Props {
|
||||
interface Item {
|
||||
title: string
|
||||
content: React.ReactNode
|
||||
open?: boolean
|
||||
}
|
||||
|
||||
export default function Accordion(props: Props) {
|
||||
return (
|
||||
<Card>
|
||||
<Card className='w-full'>
|
||||
{props.items.map((item) => (
|
||||
<details key={item.title} className='group border-b-white/10 [&:not(:last-child)]:border-b'>
|
||||
<details
|
||||
key={item.title}
|
||||
open={item.open}
|
||||
className='group border-b-white/10 [&:not(:last-child)]:border-b'
|
||||
>
|
||||
<summary
|
||||
className={classNames(
|
||||
'mb-0 flex cursor-pointer items-center justify-between border-t border-white/10 bg-white/10 p-4 text-white',
|
||||
|
98
src/components/Account/AccountComposition.tsx
Normal file
98
src/components/Account/AccountComposition.tsx
Normal file
@ -0,0 +1,98 @@
|
||||
'use client'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { ArrowRight } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import useStore from 'store'
|
||||
import {
|
||||
calculateAccountApr,
|
||||
calculateAccountBalance,
|
||||
calculateAccountBorrowRate,
|
||||
calculateAccountDebt,
|
||||
calculateAccountPnL,
|
||||
} from 'utils/accounts'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
account: Account
|
||||
change?: AccountChange
|
||||
}
|
||||
|
||||
interface ItemProps {
|
||||
title: string
|
||||
current: BigNumber
|
||||
change: BigNumber
|
||||
className?: string
|
||||
}
|
||||
|
||||
export default function AccountComposition(props: Props) {
|
||||
const prices = useStore((s) => s.prices)
|
||||
const balance = calculateAccountBalance(props.account, prices)
|
||||
const balanceChange = props.change ? calculateAccountBalance(props.change, prices) : BN(0)
|
||||
const debtBalance = calculateAccountDebt(props.account, prices)
|
||||
const debtBalanceChange = props.change ? calculateAccountDebt(props.change, prices) : BN(0)
|
||||
const pnL = calculateAccountPnL(props.account, prices)
|
||||
const pnLChange = props.change ? calculateAccountPnL(props.change, prices) : BN(0)
|
||||
const apr = calculateAccountApr(props.account, prices)
|
||||
const aprChange = props.change ? calculateAccountPnL(props.change, prices) : BN(0)
|
||||
const borrowRate = calculateAccountBorrowRate(props.account, prices)
|
||||
const borrowRateChange = props.change ? calculateAccountPnL(props.change, prices) : BN(0)
|
||||
|
||||
return (
|
||||
<div className='w-full flex-wrap'>
|
||||
<Item
|
||||
title='Total Position Value'
|
||||
current={balance}
|
||||
change={balance.plus(balanceChange)}
|
||||
className='pb-3'
|
||||
/>
|
||||
<Item
|
||||
title='Total Liabilities'
|
||||
current={debtBalance}
|
||||
change={debtBalance.plus(debtBalanceChange)}
|
||||
className='pb-3'
|
||||
/>
|
||||
<Item
|
||||
title='Unrealized PnL'
|
||||
current={pnL}
|
||||
change={pnL.plus(pnLChange)}
|
||||
className='border border-transparent border-y-white/20 py-3'
|
||||
/>
|
||||
<Item title='APR' current={apr} change={apr.plus(aprChange)} className='py-3' />
|
||||
<Item title='Borrow Rate' current={borrowRate} change={borrowRate.plus(borrowRateChange)} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Item(props: ItemProps) {
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const increase = props.current.isLessThan(props.change)
|
||||
return (
|
||||
<div className={classNames('flex w-full flex-nowrap', props.className)}>
|
||||
<div className='flex flex-shrink items-center'>
|
||||
<Text size='sm' className='text-white/60'>
|
||||
{props.title}
|
||||
</Text>
|
||||
</div>
|
||||
<div className='flex flex-grow items-center justify-end gap-2'>
|
||||
<DisplayCurrency
|
||||
coin={{ amount: props.current.toString(), denom: baseCurrency.denom }}
|
||||
className='text-sm'
|
||||
/>
|
||||
{!props.current.isEqualTo(props.change) && (
|
||||
<>
|
||||
<span className={classNames('w-3', increase ? 'text-profit' : 'text-loss')}>
|
||||
<ArrowRight />
|
||||
</span>
|
||||
<DisplayCurrency
|
||||
coin={{ amount: props.change.toString(), denom: baseCurrency.denom }}
|
||||
className={classNames('text-sm', increase ? 'text-profit' : 'text-loss')}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -15,6 +15,7 @@ import useToggle from 'hooks/useToggle'
|
||||
import useStore from 'store'
|
||||
import { calculateAccountBalance } from 'utils/accounts'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
import { BN } from 'utils/helpers'
|
||||
import useParams, { getRoute } from 'utils/route'
|
||||
|
||||
interface Props {
|
||||
@ -41,7 +42,7 @@ export default function AccountList(props: Props) {
|
||||
const selectedAccountDetails = props.accounts.find((account) => account.id === selectedAccount)
|
||||
const selectedAccountBalance = selectedAccountDetails
|
||||
? calculateAccountBalance(selectedAccountDetails, prices)
|
||||
: 0
|
||||
: BN(0)
|
||||
|
||||
async function deleteAccountHandler() {
|
||||
if (!accountSelected) return
|
||||
@ -107,7 +108,9 @@ export default function AccountList(props: Props) {
|
||||
text='Fund'
|
||||
color='tertiary'
|
||||
leftIcon={<ArrowUpLine />}
|
||||
onClick={() => props.setShowFundAccount(true)}
|
||||
onClick={() => {
|
||||
useStore.setState({ fundAndWithdrawModal: 'fund' })
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
className='w-full'
|
||||
@ -115,9 +118,9 @@ export default function AccountList(props: Props) {
|
||||
leftIcon={<ArrowDownLine />}
|
||||
text='Withdraw'
|
||||
onClick={() => {
|
||||
useStore.setState({ withdrawModal: true })
|
||||
useStore.setState({ fundAndWithdrawModal: 'withdraw' })
|
||||
}}
|
||||
disabled={positionBalance <= 0}
|
||||
disabled={positionBalance.isLessThanOrEqualTo(0)}
|
||||
/>
|
||||
<Button
|
||||
className='w-full'
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import classNames from 'classnames'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import AccountList from 'components/Account/AccountList'
|
||||
import CreateAccount from 'components/Account/CreateAccount'
|
||||
@ -52,6 +52,10 @@ export default function AccountMenuContent(props: Props) {
|
||||
router.push(`/wallets/${params.address}/accounts/${accountId}`)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
useStore.setState({ accounts: props.accounts })
|
||||
}, [props.accounts])
|
||||
|
||||
if (!params.address) return null
|
||||
|
||||
return (
|
||||
|
@ -1,11 +1,12 @@
|
||||
'use client'
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import AccountHealth from 'components/Account/AccountHealth'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import useStore from 'store'
|
||||
|
||||
import AccountHealth from './AccountHealth'
|
||||
|
||||
interface Props {
|
||||
balance: number
|
||||
balance: BigNumber
|
||||
risk: number
|
||||
health: number
|
||||
}
|
||||
|
@ -1,18 +1,35 @@
|
||||
'use client'
|
||||
|
||||
import Accordion from 'components/Accordion'
|
||||
import AccountComposition from 'components/Account/AccountComposition'
|
||||
import AccountHealth from 'components/Account/AccountHealth'
|
||||
import Card from 'components/Card'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { ArrowChartLineUp } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import useParams from 'utils/route'
|
||||
import useStore from 'store'
|
||||
import { calculateAccountBalance } from 'utils/accounts'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export default function AccountSummary() {
|
||||
const params = useParams()
|
||||
interface Props {
|
||||
account?: Account
|
||||
change?: AccountChange
|
||||
}
|
||||
|
||||
export default function AccountSummary(props: Props) {
|
||||
const prices = useStore((s) => s.prices)
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const accountBalance = props.account ? calculateAccountBalance(props.account, prices) : BN(0)
|
||||
if (!props.account) return null
|
||||
|
||||
return (
|
||||
<div className='flex min-w-[320px] flex-col'>
|
||||
<div className='flex basis-[345px] flex-wrap'>
|
||||
<Card className='mb-4 min-w-fit bg-white/10' contentClassName='flex'>
|
||||
<Item>
|
||||
<Text size='sm'>$90,000</Text>
|
||||
<DisplayCurrency
|
||||
coin={{ amount: accountBalance.toString(), denom: baseCurrency.denom }}
|
||||
className='text-sm'
|
||||
/>
|
||||
</Item>
|
||||
<Item>
|
||||
<span className='flex h-4 w-4 items-center'>
|
||||
@ -26,8 +43,11 @@ export default function AccountSummary() {
|
||||
</Card>
|
||||
<Accordion
|
||||
items={[
|
||||
{ title: `Subaccount ${params.accountId} Composition`, content: <p>My content</p> },
|
||||
{ title: 'Risk Score: 60/100', content: <p>My content</p> },
|
||||
{
|
||||
title: `Subaccount ${props.account.id} Composition`,
|
||||
content: <AccountComposition account={props.account} change={props.change} />,
|
||||
open: true,
|
||||
},
|
||||
{ title: 'Balances', content: <p>My content</p> },
|
||||
]}
|
||||
/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { useCallback, useState } from 'react'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
import { Button } from 'components/Button'
|
||||
import { ArrowRight, Cross } from 'components/Icons'
|
||||
@ -11,6 +11,7 @@ import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useStore from 'store'
|
||||
import { getAmount } from 'utils/accounts'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
import { BN } from 'utils/helpers'
|
||||
import useParams from 'utils/route'
|
||||
@ -23,12 +24,15 @@ interface Props {
|
||||
export default function FundAccount(props: Props) {
|
||||
const params = useParams()
|
||||
const deposit = useStore((s) => s.deposit)
|
||||
const balances = useStore((s) => s.balances)
|
||||
|
||||
const [amount, setAmount] = useState(BN(0))
|
||||
const [asset, setAsset] = useState<Asset>(ASSETS[0])
|
||||
const [isLending, setIsLending] = useToggle()
|
||||
const [isFunding, setIsFunding] = useToggle()
|
||||
|
||||
const max = getAmount(asset.denom, balances ?? [])
|
||||
|
||||
const onChangeAmount = useCallback((amount: BigNumber) => {
|
||||
setAmount(amount)
|
||||
}, [])
|
||||
@ -85,10 +89,11 @@ export default function FundAccount(props: Props) {
|
||||
onChange={onChangeAmount}
|
||||
onChangeAsset={onChangeAsset}
|
||||
amount={amount}
|
||||
max={BN(1).shiftedBy(ASSETS[0].decimals)}
|
||||
max={max}
|
||||
className='mb-4'
|
||||
disabled={isFunding}
|
||||
hasSelect
|
||||
balances={balances}
|
||||
/>
|
||||
<div className='mb-4 w-full border-b border-white/10' />
|
||||
<SwitchWithLabel
|
||||
|
@ -53,7 +53,7 @@ export default function Modal(props: Props) {
|
||||
>
|
||||
<Card
|
||||
className={classNames(
|
||||
'relative w-full max-w-full bg-white/5 backdrop-blur-3xl',
|
||||
'relative flex max-w-full flex-grow bg-white/5 backdrop-blur-3xl',
|
||||
props.className,
|
||||
)}
|
||||
>
|
||||
|
@ -11,6 +11,7 @@ import Text from 'components/Text'
|
||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useStore from 'store'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
import { formatPercent, formatValue } from 'utils/formatters'
|
||||
@ -29,6 +30,7 @@ function getAssetLogo(modal: BorrowModal | null) {
|
||||
|
||||
export default function BorrowModal() {
|
||||
const params = useParams()
|
||||
const currentAccount = useCurrentAccount()
|
||||
const [percentage, setPercentage] = useState(0)
|
||||
const [amount, setAmount] = useState(BN(0))
|
||||
const [selectedAccount, setSelectedAccount] = useState(params.accountId)
|
||||
@ -149,7 +151,7 @@ export default function BorrowModal() {
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummary />
|
||||
<AccountSummary account={currentAccount} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
|
140
src/components/Modals/FundAndWithdrawModal.tsx
Normal file
140
src/components/Modals/FundAndWithdrawModal.tsx
Normal file
@ -0,0 +1,140 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import AccountSummary from 'components/Account/AccountSummary'
|
||||
import { Button } from 'components/Button'
|
||||
import Card from 'components/Card'
|
||||
import Divider from 'components/Divider'
|
||||
import { ArrowRight } from 'components/Icons'
|
||||
import Modal from 'components/Modal'
|
||||
import Text from 'components/Text'
|
||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useStore from 'store'
|
||||
import { getAmount } from 'utils/accounts'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export default function FundAndWithdrawModal() {
|
||||
const currentAccount = useCurrentAccount()
|
||||
const modal = useStore((s) => s.fundAndWithdrawModal)
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const withdraw = useStore((s) => s.withdraw)
|
||||
const deposit = useStore((s) => s.deposit)
|
||||
const [amount, setAmount] = useState(BN(0))
|
||||
const [currentAsset, setCurrentAsset] = useState(baseCurrency)
|
||||
const [change, setChange] = useState<AccountChange | undefined>()
|
||||
const [isConfirming, setIsConfirming] = useToggle()
|
||||
const balances = useStore((s) => s.balances)
|
||||
const isFunding = modal === 'fund'
|
||||
|
||||
function resetState() {
|
||||
setCurrentAsset(baseCurrency)
|
||||
setAmount(BN(0))
|
||||
setChange(undefined)
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
resetState()
|
||||
useStore.setState({ fundAndWithdrawModal: null })
|
||||
}
|
||||
|
||||
async function onConfirm() {
|
||||
if (!currentAccount) return
|
||||
setIsConfirming(true)
|
||||
let result
|
||||
if (isFunding) {
|
||||
result = await deposit({
|
||||
fee: hardcodedFee,
|
||||
accountId: currentAccount.id,
|
||||
coin: {
|
||||
denom: currentAsset.denom,
|
||||
amount: amount.toString(),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
result = await withdraw({
|
||||
fee: hardcodedFee,
|
||||
accountId: currentAccount.id,
|
||||
coin: {
|
||||
denom: currentAsset.denom,
|
||||
amount: amount.toString(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
setIsConfirming(false)
|
||||
if (result) {
|
||||
resetState()
|
||||
useStore.setState({ fundAndWithdrawModal: null })
|
||||
}
|
||||
}
|
||||
|
||||
const max = isFunding
|
||||
? getAmount(currentAsset.denom, balances ?? [])
|
||||
: currentAccount
|
||||
? getAmount(currentAsset.denom, currentAccount.deposits)
|
||||
: BN(0)
|
||||
|
||||
useEffect(() => {
|
||||
setChange({
|
||||
deposits: [
|
||||
{
|
||||
amount: isFunding ? BN(0).plus(amount).toString() : BN(0).minus(amount).toString(),
|
||||
denom: currentAsset.denom,
|
||||
},
|
||||
],
|
||||
})
|
||||
}, [amount, currentAsset, currentAccount, isFunding])
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={!!modal}
|
||||
onClose={onClose}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
<Text>
|
||||
{isFunding
|
||||
? `Fund Account ${currentAccount?.id ?? '0'}`
|
||||
: `Withdraw from Account ${currentAccount?.id ?? '0'}`}
|
||||
</Text>
|
||||
</span>
|
||||
}
|
||||
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
|
||||
contentClassName='flex flex-col min-h-[400px]'
|
||||
>
|
||||
<div className='flex flex-grow items-start gap-6 p-6'>
|
||||
<Card
|
||||
className='flex flex-grow bg-white/5 p-4'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<TokenInputWithSlider
|
||||
asset={currentAsset}
|
||||
onChange={(val) => {
|
||||
setAmount(val)
|
||||
}}
|
||||
onChangeAsset={(asset) => {
|
||||
setCurrentAsset(asset)
|
||||
}}
|
||||
amount={amount}
|
||||
max={max}
|
||||
hasSelect
|
||||
balances={isFunding ? balances : currentAccount?.deposits ?? []}
|
||||
accountId={!isFunding ? currentAccount?.id ?? '0' : undefined}
|
||||
/>
|
||||
<Divider />
|
||||
<Button
|
||||
onClick={onConfirm}
|
||||
showProgressIndicator={isConfirming}
|
||||
className='w-full'
|
||||
text={isFunding ? 'Fund' : 'Withdraw'}
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummary account={currentAccount} change={change} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
'use client'
|
||||
|
||||
import WithdrawModal from 'components/Modals//WithdrawModal'
|
||||
import BorrowModal from 'components/Modals/BorrowModal'
|
||||
import FundAndWithdrawModal from 'components/Modals/FundAndWithdrawModal'
|
||||
import VaultModal from 'components/Modals/VaultModal'
|
||||
|
||||
export default function ModalsContainer() {
|
||||
return (
|
||||
<>
|
||||
<BorrowModal />
|
||||
<WithdrawModal />
|
||||
<FundAndWithdrawModal />
|
||||
<VaultModal />
|
||||
</>
|
||||
)
|
||||
|
@ -22,11 +22,11 @@ import { formatValue } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export default function VaultModal() {
|
||||
const currentAccount = useCurrentAccount()
|
||||
const modal = useStore((s) => s.vaultModal)
|
||||
const [amount, setAmount] = useState(BN(0))
|
||||
const [percentage, setPercentage] = useState(0)
|
||||
const [isCustomAmount, setIsCustomAmount] = useState(false)
|
||||
const currentAccount = useCurrentAccount()
|
||||
|
||||
function handleSwitch() {
|
||||
setIsCustomAmount(() => !isCustomAmount)
|
||||
@ -80,7 +80,7 @@ export default function VaultModal() {
|
||||
</div>
|
||||
<div className='flex flex-grow items-start gap-6 p-6'>
|
||||
<Card
|
||||
className='w-full bg-white/5 p-4'
|
||||
className='flex flex-grow bg-white/5 p-4'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<TokenInput
|
||||
@ -112,7 +112,7 @@ export default function VaultModal() {
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummary />
|
||||
<AccountSummary account={currentAccount} />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
|
@ -1,96 +0,0 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
import AccountSummary from 'components/Account/AccountSummary'
|
||||
import { Button } from 'components/Button'
|
||||
import Card from 'components/Card'
|
||||
import Divider from 'components/Divider'
|
||||
import { ArrowRight } from 'components/Icons'
|
||||
import Modal from 'components/Modal'
|
||||
import Text from 'components/Text'
|
||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import useStore from 'store'
|
||||
import { getAmount } from 'utils/accounts'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export default function WithdrawModal() {
|
||||
const currentAccount = useCurrentAccount()
|
||||
const modal = useStore((s) => s.withdrawModal)
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const withdraw = useStore((s) => s.withdraw)
|
||||
const [amount, setAmount] = useState(BN(0))
|
||||
const [currentAsset, setCurrentAsset] = useState(baseCurrency)
|
||||
const [isWithdrawing, setIsWithdrawing] = useToggle()
|
||||
|
||||
function onClose() {
|
||||
useStore.setState({ withdrawModal: false })
|
||||
setAmount(BN(0))
|
||||
}
|
||||
|
||||
async function onWithdraw() {
|
||||
if (!currentAccount) return
|
||||
setIsWithdrawing(true)
|
||||
const result = await withdraw({
|
||||
fee: hardcodedFee,
|
||||
accountId: currentAccount.id,
|
||||
coin: {
|
||||
denom: currentAsset.denom,
|
||||
amount: amount.toString(),
|
||||
},
|
||||
})
|
||||
setIsWithdrawing(false)
|
||||
if (result) {
|
||||
useStore.setState({ withdrawModal: false })
|
||||
}
|
||||
}
|
||||
|
||||
const maxWithdraw = currentAccount
|
||||
? getAmount(currentAsset.denom, currentAccount.deposits)
|
||||
: BN(0)
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={modal}
|
||||
onClose={onClose}
|
||||
header={
|
||||
<span className='flex items-center gap-4 px-4'>
|
||||
<Text>{`Withdraw from Account ${currentAccount?.id ?? '0'}`}</Text>
|
||||
</span>
|
||||
}
|
||||
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b'
|
||||
contentClassName='flex flex-col min-h-[400px]'
|
||||
>
|
||||
<div className='flex flex-grow items-start gap-6 p-6'>
|
||||
<Card
|
||||
className='w-full bg-white/5 p-4'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<TokenInputWithSlider
|
||||
asset={currentAsset}
|
||||
onChange={(val) => {
|
||||
setAmount(val)
|
||||
}}
|
||||
onChangeAsset={(asset) => {
|
||||
setCurrentAsset(asset)
|
||||
}}
|
||||
amount={amount}
|
||||
max={maxWithdraw}
|
||||
hasSelect
|
||||
currentAccount={currentAccount}
|
||||
/>
|
||||
<Divider />
|
||||
<Button
|
||||
onClick={onWithdraw}
|
||||
showProgressIndicator={isWithdrawing}
|
||||
className='w-full'
|
||||
text='Withdraw'
|
||||
rightIcon={<ArrowRight />}
|
||||
/>
|
||||
</Card>
|
||||
<AccountSummary />
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
@ -31,7 +31,7 @@ async function Content(props: PageProps) {
|
||||
{account.map((account: Account, index: number) => (
|
||||
<Card
|
||||
className='h-fit w-full bg-white/5'
|
||||
title={`Account ${account}`}
|
||||
title={`Account ${account.id}`}
|
||||
key={index}
|
||||
contentClassName='px-4 py-6'
|
||||
>
|
||||
|
@ -1,3 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import classNames from 'classnames'
|
||||
import { ChangeEvent, useRef, useState } from 'react'
|
||||
import Draggable from 'react-draggable'
|
||||
|
@ -19,7 +19,8 @@ interface Props {
|
||||
onChange: (amount: BigNumber) => void
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
currentAccount?: Account
|
||||
balances?: Coin[] | null
|
||||
accountId?: string
|
||||
}
|
||||
|
||||
interface SingleProps extends Props {
|
||||
@ -37,7 +38,6 @@ interface SelectProps extends Props {
|
||||
}
|
||||
|
||||
export default function TokenInput(props: SingleProps | SelectProps) {
|
||||
const balances = useStore((s) => s.balances)
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
const [asset, setAsset] = useState<Asset>(props.asset ? props.asset : baseCurrency)
|
||||
const [coin, setCoin] = useState<Coin>({
|
||||
@ -45,26 +45,24 @@ export default function TokenInput(props: SingleProps | SelectProps) {
|
||||
amount: '0',
|
||||
})
|
||||
|
||||
const selectableBalances = props.currentAccount?.deposits ?? balances
|
||||
|
||||
const selectedAssetDenom = props.asset ? props.asset.denom : baseCurrency.denom
|
||||
|
||||
const updateAsset = useCallback(
|
||||
(coinDenom: string) => {
|
||||
const newAsset = ASSETS.find((asset) => asset.denom === coinDenom) ?? baseCurrency
|
||||
const newCoin = selectableBalances?.find((coin) => coin.denom === coinDenom)
|
||||
const newCoin = props.balances?.find((coin) => coin.denom === coinDenom)
|
||||
setAsset(newAsset)
|
||||
setCoin(newCoin ?? { denom: coinDenom, amount: '0' })
|
||||
},
|
||||
[selectableBalances, baseCurrency],
|
||||
[props.balances, baseCurrency],
|
||||
)
|
||||
|
||||
function setDefaultAsset() {
|
||||
if (!selectableBalances || selectableBalances?.length === 0) return setAsset(baseCurrency)
|
||||
if (selectableBalances.length === 1)
|
||||
return setAsset(
|
||||
ASSETS.find((asset) => asset.denom === selectableBalances[0].denom) ?? baseCurrency,
|
||||
)
|
||||
if (!props.balances || props.balances?.length === 0) return setAsset(baseCurrency)
|
||||
if (props.balances.length === 1) {
|
||||
const balances = props.balances ?? []
|
||||
return setAsset(ASSETS.find((asset) => asset.denom === balances[0].denom) ?? baseCurrency)
|
||||
}
|
||||
return setAsset(ASSETS.find((asset) => asset.denom === selectedAssetDenom) ?? baseCurrency)
|
||||
}
|
||||
|
||||
@ -91,12 +89,12 @@ export default function TokenInput(props: SingleProps | SelectProps) {
|
||||
)}
|
||||
>
|
||||
<div className='relative isolate z-40 box-content flex h-11 w-full rounded-sm border border-white/20 bg-white/5'>
|
||||
{props.hasSelect && selectableBalances ? (
|
||||
{props.hasSelect && props.balances ? (
|
||||
<Select
|
||||
options={selectableBalances}
|
||||
options={props.balances}
|
||||
defaultValue={coin.denom}
|
||||
onChange={(value) => updateAsset(value)}
|
||||
title={props.currentAccount ? `Account ${props.currentAccount.id}` : 'Your Wallet'}
|
||||
title={props.accountId ? `Account ${props.accountId}` : 'Your Wallet'}
|
||||
className='border-r border-white/20 bg-white/5'
|
||||
/>
|
||||
) : (
|
||||
|
@ -1,5 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import Slider from 'components/Slider'
|
||||
import TokenInput from 'components/TokenInput'
|
||||
@ -11,7 +13,8 @@ interface Props {
|
||||
onChange: (amount: BigNumber) => void
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
currentAccount?: Account
|
||||
balances?: Coin[] | null
|
||||
accountId?: string
|
||||
}
|
||||
|
||||
interface SingleProps extends Props {
|
||||
@ -64,6 +67,15 @@ export default function TokenInputWithSlider(props: SingleProps | SelectProps) {
|
||||
[props],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (props.max?.isEqualTo(max)) return
|
||||
|
||||
setMax(props.max ?? BN(0))
|
||||
setPercentage(0)
|
||||
setAmount(BN(0))
|
||||
setAsset(props.asset ?? ASSETS[0])
|
||||
}, [props.max, props.asset, max])
|
||||
|
||||
return (
|
||||
<div className={props.className}>
|
||||
<TokenInput
|
||||
@ -75,7 +87,8 @@ export default function TokenInputWithSlider(props: SingleProps | SelectProps) {
|
||||
className='mb-4'
|
||||
disabled={props.disabled}
|
||||
hasSelect={props.hasSelect}
|
||||
currentAccount={props.currentAccount}
|
||||
balances={props.balances}
|
||||
accountId={props.accountId}
|
||||
/>
|
||||
<Slider
|
||||
value={percentage}
|
||||
|
@ -6,7 +6,7 @@ export default function createModalSlice(set: SetState<ModalSlice>, get: GetStat
|
||||
createAccountModal: false,
|
||||
deleteAccountModal: false,
|
||||
fundAccountModal: false,
|
||||
withdrawModal: false,
|
||||
fundAndWithdrawModal: null,
|
||||
vaultModal: null,
|
||||
}
|
||||
}
|
||||
|
7
src/types/interfaces/account.d.ts
vendored
7
src/types/interfaces/account.d.ts
vendored
@ -5,3 +5,10 @@ interface Account {
|
||||
lends: Coin[]
|
||||
vaults: import('types/generated/mars-mock-credit-manager/MarsMockCreditManager.types').ArrayOfVaultInfoResponse
|
||||
}
|
||||
|
||||
interface AccountChange {
|
||||
deposits?: Coin[]
|
||||
debts?: Coin[]
|
||||
lends?: Coin[]
|
||||
vaults?: import('types/generated/mars-mock-credit-manager/MarsMockCreditManager.types').ArrayOfVaultInfoResponse
|
||||
}
|
||||
|
2
src/types/interfaces/store/modals.d.ts
vendored
2
src/types/interfaces/store/modals.d.ts
vendored
@ -3,7 +3,7 @@ interface ModalSlice {
|
||||
createAccountModal: boolean
|
||||
deleteAccountModal: boolean
|
||||
fundAccountModal: boolean
|
||||
withdrawModal: boolean
|
||||
fundAndWithdrawModal: 'fund' | 'withdraw' | null
|
||||
vaultModal: {
|
||||
vault: Vault
|
||||
} | null
|
||||
|
@ -1,21 +1,61 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export const calculateAccountBalance = (account: Account, prices: Coin[]) => {
|
||||
const totalDepositValue = account.deposits.reduce((acc, deposit) => {
|
||||
export const calculateAccountBalance = (
|
||||
account: Account | AccountChange,
|
||||
prices: Coin[],
|
||||
): BigNumber => {
|
||||
const totalDepositValue = calculateAccountDeposits(account, prices)
|
||||
const totalDebtValue = calculateAccountDebt(account, prices)
|
||||
|
||||
return totalDepositValue.minus(totalDebtValue)
|
||||
}
|
||||
|
||||
export const calculateAccountDeposits = (
|
||||
account: Account | AccountChange,
|
||||
prices: Coin[],
|
||||
): BigNumber => {
|
||||
if (!account.deposits) return BN(0)
|
||||
return account.deposits.reduce((acc, deposit) => {
|
||||
const price = prices.find((price) => price.denom === deposit.denom)?.amount ?? 0
|
||||
const depositValue = BN(deposit.amount).multipliedBy(price)
|
||||
return acc.plus(depositValue)
|
||||
}, BN(0))
|
||||
|
||||
const totalDebtValue = account.debts.reduce((acc, debt) => {
|
||||
}
|
||||
export const calculateAccountDebt = (
|
||||
account: Account | AccountChange,
|
||||
prices: Coin[],
|
||||
): BigNumber => {
|
||||
if (!account.debts) return BN(0)
|
||||
return account.debts.reduce((acc, debt) => {
|
||||
const price = prices.find((price) => price.denom === debt.denom)?.amount ?? 0
|
||||
const debtValue = BN(debt.amount).multipliedBy(price)
|
||||
return acc.plus(debtValue)
|
||||
}, BN(0))
|
||||
|
||||
return totalDepositValue.minus(totalDebtValue).toNumber()
|
||||
}
|
||||
|
||||
export function getAmount(denom: string, coins: Coin[]) {
|
||||
export const calculateAccountPnL = (
|
||||
account: Account | AccountChange,
|
||||
prices: Coin[],
|
||||
): BigNumber => {
|
||||
return BN(0)
|
||||
}
|
||||
|
||||
export const calculateAccountApr = (
|
||||
account: Account | AccountChange,
|
||||
prices: Coin[],
|
||||
): BigNumber => {
|
||||
return BN(0)
|
||||
}
|
||||
|
||||
export const calculateAccountBorrowRate = (
|
||||
account: Account | AccountChange,
|
||||
prices: Coin[],
|
||||
): BigNumber => {
|
||||
return BN(0)
|
||||
}
|
||||
|
||||
export function getAmount(denom: string, coins: Coin[]): BigNumber {
|
||||
return BN(coins.find((asset) => asset.denom === denom)?.amount ?? 0)
|
||||
}
|
||||
|
@ -2,8 +2,7 @@ import { usePathname } from 'next/navigation'
|
||||
|
||||
export default function useParams() {
|
||||
const pathname = usePathname()
|
||||
|
||||
return getParamsFromUrl(pathname || '')
|
||||
return getParamsFromUrl(pathname ?? '')
|
||||
}
|
||||
|
||||
export function getRouteParams(url: string | null): PageParams {
|
||||
|
Loading…
Reference in New Issue
Block a user