MP-3128: added conditional ActionButtons (#324)
* MP-3128: added conditional ActionButtons * feat: added Create Account button * fix: simplified the ActionsButton according to feedback * fix: moved the onClick handler to the card of an account summary instead of the title * fix: fixed the health and balance display bug * fix: remove Leverage static number * fix: small style fix
This commit is contained in:
parent
bd07c20e47
commit
fec03d030f
@ -51,14 +51,6 @@ function AccountDetails(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
<div className='w-full border border-x-0 border-white/20 py-4'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Leverage
|
||||
</Text>
|
||||
<Text size='xs' className='w-full text-center'>
|
||||
4.5x
|
||||
</Text>
|
||||
</div>
|
||||
<div className='w-full px-1 py-4'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Balance
|
||||
</Text>
|
||||
|
@ -10,14 +10,10 @@ import { ArrowCircledTopRight, ArrowDownLine, ArrowUpLine, TrashBin } from 'comp
|
||||
import Radio from 'components/Radio'
|
||||
import SwitchWithLabel from 'components/SwitchWithLabel'
|
||||
import Text from 'components/Text'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { DISPLAY_CURRENCY_KEY } from 'constants/localStore'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||
import useLocalStorage from 'hooks/useLocalStorage'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { calculateAccountBalanceValue, calculateAccountDepositsValue } from 'utils/accounts'
|
||||
import { calculateAccountDepositsValue } from 'utils/accounts'
|
||||
import { hardcodedFee } from 'utils/constants'
|
||||
import { getPage, getRoute } from 'utils/route'
|
||||
|
||||
@ -28,6 +24,7 @@ interface Props {
|
||||
const accountCardHeaderClasses = classNames(
|
||||
'flex w-full items-center justify-between bg-white/20 px-4 py-2.5 text-white/70',
|
||||
'border border-transparent border-b-white/20',
|
||||
'group-hover/account:bg-white/30',
|
||||
)
|
||||
|
||||
export default function AccountList(props: Props) {
|
||||
@ -38,10 +35,6 @@ export default function AccountList(props: Props) {
|
||||
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
||||
const deleteAccount = useStore((s) => s.deleteAccount)
|
||||
const accountSelected = !!accountId && !isNaN(Number(accountId))
|
||||
const selectedAccountDetails = props.accounts.find((account) => account.id === accountId)
|
||||
const selectedAccountBalance = selectedAccountDetails
|
||||
? calculateAccountBalanceValue(selectedAccountDetails, prices)
|
||||
: BN_ZERO
|
||||
|
||||
async function deleteAccountHandler() {
|
||||
if (!accountSelected) return
|
||||
@ -72,31 +65,25 @@ export default function AccountList(props: Props) {
|
||||
<Card
|
||||
id={`account-${account.id}`}
|
||||
key={account.id}
|
||||
className='w-full'
|
||||
contentClassName='bg-white/10'
|
||||
className={classNames('w-full', !isActive && 'group/account hover:cursor-pointer')}
|
||||
contentClassName='bg-white/10 group-hover/account:bg-white/20'
|
||||
onClick={() => {
|
||||
if (isActive) return
|
||||
navigate(getRoute(getPage(pathname), address, account.id))
|
||||
}}
|
||||
title={
|
||||
<div
|
||||
className={classNames(
|
||||
accountCardHeaderClasses,
|
||||
!isActive && 'group hover:cursor-pointer',
|
||||
)}
|
||||
role={!isActive ? 'button' : undefined}
|
||||
onClick={() => {
|
||||
if (isActive) return
|
||||
navigate(getRoute(getPage(pathname), address, account.id))
|
||||
}}
|
||||
>
|
||||
<div className={accountCardHeaderClasses} role={!isActive ? 'button' : undefined}>
|
||||
<Text size='xs' className='flex flex-1'>
|
||||
Credit Account {account.id}
|
||||
</Text>
|
||||
<Radio active={isActive} className='group-hover:opacity-100' />
|
||||
<Radio active={isActive} className='group-hover/account:opacity-100' />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{isActive ? (
|
||||
<>
|
||||
<div className='w-full border border-transparent border-b-white/20 p-4'>
|
||||
<AccountStats balance={selectedAccountBalance} risk={75} health={85} />
|
||||
<AccountStats account={account} />
|
||||
</div>
|
||||
<div className='grid grid-flow-row grid-cols-2 gap-4 p-4'>
|
||||
<Button
|
||||
@ -149,7 +136,7 @@ export default function AccountList(props: Props) {
|
||||
</>
|
||||
) : (
|
||||
<div className='w-full p-4'>
|
||||
<AccountStats balance={positionBalance} risk={60} health={50} />
|
||||
<AccountStats account={account} />
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
|
@ -1,25 +1,30 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import AccountHealth from 'components/Account/AccountHealth'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import useHealthComputer from 'hooks/useHealthComputer'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { calculateAccountDepositsValue } from 'utils/accounts'
|
||||
import { formatHealth } from 'utils/formatters'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
interface Props {
|
||||
balance: BigNumber
|
||||
risk: number
|
||||
health: number
|
||||
account: Account
|
||||
}
|
||||
|
||||
export default function AccountStats(props: Props) {
|
||||
const { data: prices } = usePrices()
|
||||
const positionBalance = calculateAccountDepositsValue(props.account, prices)
|
||||
const { health } = useHealthComputer(props.account)
|
||||
const healthFactor = BN(100).minus(formatHealth(health)).toNumber()
|
||||
return (
|
||||
<div className='w-full flex-wrap'>
|
||||
<DisplayCurrency
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, props.balance)}
|
||||
coin={BNCoin.fromDenomAndBigNumber(ORACLE_DENOM, positionBalance)}
|
||||
className='w-full text-xl'
|
||||
/>
|
||||
<div className='mt-1 flex w-full items-center'>
|
||||
<AccountHealth health={props.health} classNames='w-[140px]' hasLabel />
|
||||
<AccountHealth health={healthFactor} classNames='w-[140px]' hasLabel />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import ActionButton from 'components/Button/ActionButton'
|
||||
import { Plus, ReceiptCheck } from 'components/Icons'
|
||||
import useStore from 'store'
|
||||
import { getEnabledMarketAssets } from 'utils/assets'
|
||||
@ -28,7 +29,7 @@ export default function BorrowActionButtons(props: Props) {
|
||||
|
||||
return (
|
||||
<div className='flex flex-row space-x-2'>
|
||||
<Button
|
||||
<ActionButton
|
||||
leftIcon={<Plus className='w-3' />}
|
||||
onClick={borrowHandler}
|
||||
color='secondary'
|
||||
|
46
src/components/Button/ActionButton.tsx
Normal file
46
src/components/Button/ActionButton.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
|
||||
import AccountCreateFirst from 'components/Account/AccountCreateFirst'
|
||||
import { ACCOUNT_MENU_BUTTON_ID } from 'components/Account/AccountMenuContent'
|
||||
import Button from 'components/Button'
|
||||
import { Account, PlusCircled } from 'components/Icons'
|
||||
import WalletConnectButton from 'components/Wallet/WalletConnectButton'
|
||||
import useStore from 'store'
|
||||
|
||||
export default function ActionButton(props: ButtonProps) {
|
||||
const { className, color, variant, size } = props
|
||||
const defaultProps = { className, color, variant, size }
|
||||
const address = useStore((s) => s.address)
|
||||
const accounts = useStore((s) => s.accounts)
|
||||
const { accountId } = useParams()
|
||||
|
||||
const handleCreateAccountClick = useCallback(() => {
|
||||
useStore.setState({ focusComponent: <AccountCreateFirst /> })
|
||||
}, [])
|
||||
|
||||
if (!address) return <WalletConnectButton {...defaultProps} />
|
||||
|
||||
if (accounts && accounts.length === 0)
|
||||
return (
|
||||
<Button
|
||||
onClick={handleCreateAccountClick}
|
||||
leftIcon={<PlusCircled />}
|
||||
text='Create Account'
|
||||
{...defaultProps}
|
||||
/>
|
||||
)
|
||||
|
||||
if (!accountId)
|
||||
return (
|
||||
<Button
|
||||
text='Select Account'
|
||||
onClick={() => document.getElementById(ACCOUNT_MENU_BUTTON_ID)?.click()}
|
||||
leftIcon={<Account />}
|
||||
rightIcon={undefined}
|
||||
{...defaultProps}
|
||||
/>
|
||||
)
|
||||
|
||||
return <Button {...props} />
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
export function glowElement(enableAnimations: boolean) {
|
||||
export function glowElement(enableAnimations: boolean, className?: string) {
|
||||
return (
|
||||
<svg
|
||||
className={classNames(
|
||||
|
@ -7,6 +7,7 @@ interface Props {
|
||||
children: ReactNode
|
||||
className?: string
|
||||
contentClassName?: string
|
||||
onClick?: () => void
|
||||
title?: string | ReactElement
|
||||
id?: string
|
||||
}
|
||||
@ -15,6 +16,7 @@ export default function Card(props: Props) {
|
||||
return (
|
||||
<section
|
||||
id={props.id}
|
||||
onClick={props.onClick}
|
||||
className={classNames(
|
||||
props.className,
|
||||
'flex flex-col',
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
import classNames from 'classnames'
|
||||
import React from 'react'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import ActionButton from 'components/Button/ActionButton'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import VaultExpanded from 'components/Earn/Farm/VaultExpanded'
|
||||
import VaultLogo from 'components/Earn/Farm/VaultLogo'
|
||||
@ -205,9 +205,7 @@ export const VaultTable = (props: Props) => {
|
||||
<ChevronDown />
|
||||
</div>
|
||||
) : (
|
||||
<Button onClick={enterVaultHandler} color='tertiary'>
|
||||
Deposit
|
||||
</Button>
|
||||
<ActionButton onClick={enterVaultHandler} color='tertiary' text='Deposit' />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
|
||||
import { ACCOUNT_MENU_BUTTON_ID } from 'components/Account/AccountMenuContent'
|
||||
import Button from 'components/Button'
|
||||
import ActionButton from 'components/Button/ActionButton'
|
||||
import { ArrowDownLine, ArrowUpLine, Enter } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import { Tooltip } from 'components/Tooltip'
|
||||
@ -10,6 +12,7 @@ import useAlertDialog from 'hooks/useAlertDialog'
|
||||
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||
import useCurrentAccountDeposits from 'hooks/useCurrentAccountDeposits'
|
||||
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
|
||||
import useStore from 'store'
|
||||
import { byDenom } from 'utils/array'
|
||||
|
||||
interface Props {
|
||||
@ -26,6 +29,9 @@ export default function LendingActionButtons(props: Props) {
|
||||
const { open: showAlertDialog } = useAlertDialog()
|
||||
const { isAutoLendEnabledForCurrentAccount } = useAutoLendEnabledAccountIds()
|
||||
const assetDepositAmount = accountDeposits.find(byDenom(asset.denom))?.amount
|
||||
const address = useStore((s) => s.address)
|
||||
const { accountId } = useParams()
|
||||
const hasNoDeposit = !!(!assetDepositAmount && address && accountId)
|
||||
|
||||
const handleWithdraw = useCallback(() => {
|
||||
if (isAutoLendEnabledForCurrentAccount) {
|
||||
@ -64,7 +70,7 @@ export default function LendingActionButtons(props: Props) {
|
||||
)}
|
||||
|
||||
<ConditionalWrapper
|
||||
condition={!assetDepositAmount}
|
||||
condition={hasNoDeposit}
|
||||
wrapper={(children) => (
|
||||
<Tooltip
|
||||
type='warning'
|
||||
@ -76,16 +82,15 @@ export default function LendingActionButtons(props: Props) {
|
||||
</Tooltip>
|
||||
)}
|
||||
>
|
||||
<Button
|
||||
<ActionButton
|
||||
leftIcon={<ArrowUpLine />}
|
||||
iconClassName={iconClassnames}
|
||||
disabled={!assetDepositAmount}
|
||||
disabled={hasNoDeposit}
|
||||
color='secondary'
|
||||
onClick={() => openLend(props.data)}
|
||||
className={buttonClassnames}
|
||||
>
|
||||
Lend
|
||||
</Button>
|
||||
text='Lend'
|
||||
/>
|
||||
</ConditionalWrapper>
|
||||
</div>
|
||||
)
|
||||
|
@ -7,11 +7,11 @@ import { byDenom } from 'utils/array'
|
||||
import { getAssetByDenom } from 'utils/assets'
|
||||
|
||||
interface Props {
|
||||
defaultSelectedDenoms: string[]
|
||||
onChangeDenoms: (denoms: string[]) => void
|
||||
}
|
||||
|
||||
export default function WalletAssetsModalContent(props: Props) {
|
||||
const { onChangeDenoms } = props
|
||||
const [searchString, setSearchString] = useState<string>('')
|
||||
const balances = useStore((s) => s.balances)
|
||||
|
||||
@ -39,12 +39,12 @@ export default function WalletAssetsModalContent(props: Props) {
|
||||
currentSelectedDenom?.filter((denom) => filteredAssets.findIndex(byDenom(denom))) || [],
|
||||
)
|
||||
|
||||
const onChangeDenoms = useCallback(
|
||||
const onChangeSelect = useCallback(
|
||||
(denoms: string[]) => {
|
||||
setSelectedDenoms(denoms)
|
||||
props.onChangeDenoms(denoms)
|
||||
onChangeDenoms(denoms)
|
||||
},
|
||||
[props.onChangeDenoms],
|
||||
[onChangeDenoms],
|
||||
)
|
||||
|
||||
return (
|
||||
@ -59,7 +59,7 @@ export default function WalletAssetsModalContent(props: Props) {
|
||||
<div className='max-h-[446px] overflow-y-scroll scrollbar-hide'>
|
||||
<AssetSelectTable
|
||||
assets={filteredAssets}
|
||||
onChangeSelected={onChangeDenoms}
|
||||
onChangeSelected={onChangeSelect}
|
||||
selectedDenoms={selectedDenoms}
|
||||
/>
|
||||
</div>
|
||||
|
@ -25,10 +25,7 @@ export default function WalletAssetsModal() {
|
||||
modalClassName='max-w-modal-xs'
|
||||
headerClassName='bg-white/10 border-b-white/5 border-b items-center p-4'
|
||||
>
|
||||
<WalletAssetsModalContent
|
||||
defaultSelectedDenoms={modal.selectedDenoms}
|
||||
onChangeDenoms={setSelectedDenoms}
|
||||
/>
|
||||
<WalletAssetsModalContent onChangeDenoms={setSelectedDenoms} />
|
||||
<div className='flex w-full p-4'>
|
||||
<Button className='w-full' onClick={onClose} color='tertiary' text='Select Assets' />
|
||||
</div>
|
||||
|
@ -1,11 +1,11 @@
|
||||
import classNames from 'classnames'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import ActionButton from 'components/Button/ActionButton'
|
||||
import useSwapRoute from 'hooks/useSwapRoute'
|
||||
import { getAssetByDenom } from 'utils/assets'
|
||||
import { hardcodedFee } from 'utils/constants'
|
||||
import { formatAmountWithSymbol } from 'utils/formatters'
|
||||
import { getAssetByDenom } from 'utils/assets'
|
||||
import useSwapRoute from 'hooks/useSwapRoute'
|
||||
|
||||
interface Props {
|
||||
buyAsset: Asset
|
||||
@ -53,12 +53,14 @@ export default function TradeSummary(props: Props) {
|
||||
<span>{parsedRoutes}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
<ActionButton
|
||||
disabled={routes.length === 0 || buyButtonDisabled}
|
||||
showProgressIndicator={isButtonBusy || isRouteLoading}
|
||||
text={buttonText}
|
||||
onClick={handleBuyClick}
|
||||
size='md'
|
||||
color='primary'
|
||||
className='w-full'
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
@ -11,6 +11,10 @@ import useStore from 'store'
|
||||
interface Props {
|
||||
textOverride?: string | ReactNode
|
||||
disabled?: boolean
|
||||
className?: string
|
||||
color?: ButtonProps['color']
|
||||
variant?: ButtonProps['variant']
|
||||
size?: ButtonProps['size']
|
||||
}
|
||||
|
||||
export default function WalletConnectButton(props: Props) {
|
||||
@ -24,14 +28,15 @@ export default function WalletConnectButton(props: Props) {
|
||||
return (
|
||||
<div className='relative'>
|
||||
<Button
|
||||
variant='solid'
|
||||
color='tertiary'
|
||||
variant={props.variant ?? 'solid'}
|
||||
color={props.color ?? 'tertiary'}
|
||||
size={props.size ?? 'sm'}
|
||||
disabled={props.disabled}
|
||||
onClick={handleClick}
|
||||
leftIcon={<Wallet />}
|
||||
>
|
||||
<span>{props.textOverride || 'Connect Wallet'}</span>
|
||||
</Button>
|
||||
className={props.className}
|
||||
text={props.textOverride ?? 'Connect Wallet'}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import BigNumber from 'bignumber.js'
|
||||
import classNames from 'classnames'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import useClipboard from 'react-use-clipboard'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
|
||||
import Button from 'components/Button'
|
||||
import { CircularProgress } from 'components/CircularProgress'
|
||||
@ -20,6 +21,7 @@ import useStore from 'store'
|
||||
import { ChainInfoID } from 'types/enums/wallet'
|
||||
import { getBaseAsset, getEnabledMarketAssets } from 'utils/assets'
|
||||
import { truncate } from 'utils/formatters'
|
||||
import { getPage, getRoute } from 'utils/route'
|
||||
|
||||
export default function WalletConnectedButton() {
|
||||
// ---------------
|
||||
@ -33,6 +35,8 @@ export default function WalletConnectedButton() {
|
||||
const network = useStore((s) => s.client?.connectedWallet.network)
|
||||
const baseAsset = getBaseAsset()
|
||||
const { data: walletBalances, isLoading } = useWalletBalances(address)
|
||||
const navigate = useNavigate()
|
||||
const { pathname } = useLocation()
|
||||
|
||||
// ---------------
|
||||
// LOCAL STATE
|
||||
@ -57,6 +61,7 @@ export default function WalletConnectedButton() {
|
||||
if (!currentWallet) return
|
||||
disconnectWallet(currentWallet)
|
||||
useStore.setState({ client: undefined, balances: [] })
|
||||
navigate(getRoute(getPage(pathname)))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
Loading…
Reference in New Issue
Block a user