feat: auto-lend foundation (#283)
This commit is contained in:
parent
21c8d04824
commit
0123685f79
@ -9,13 +9,13 @@ import { ArrowCircledTopRight, ArrowDownLine, ArrowUpLine, TrashBin } from 'comp
|
|||||||
import Radio from 'components/Radio'
|
import Radio from 'components/Radio'
|
||||||
import SwitchWithLabel from 'components/SwitchWithLabel'
|
import SwitchWithLabel from 'components/SwitchWithLabel'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import useToggle from 'hooks/useToggle'
|
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { calculateAccountDeposits } from 'utils/accounts'
|
import { calculateAccountDeposits } from 'utils/accounts'
|
||||||
import { hardcodedFee } from 'utils/constants'
|
import { hardcodedFee } from 'utils/constants'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
import { getPage, getRoute } from 'utils/route'
|
import { getPage, getRoute } from 'utils/route'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
|
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
setShowFundAccount: (showFundAccount: boolean) => void
|
setShowFundAccount: (showFundAccount: boolean) => void
|
||||||
@ -32,10 +32,9 @@ export default function AccountList(props: Props) {
|
|||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const { accountId, address } = useParams()
|
const { accountId, address } = useParams()
|
||||||
const { data: prices } = usePrices()
|
const { data: prices } = usePrices()
|
||||||
|
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
||||||
const deleteAccount = useStore((s) => s.deleteAccount)
|
const deleteAccount = useStore((s) => s.deleteAccount)
|
||||||
|
|
||||||
const [isLending, setIsLending] = useToggle()
|
|
||||||
const accountSelected = !!accountId && !isNaN(Number(accountId))
|
const accountSelected = !!accountId && !isNaN(Number(accountId))
|
||||||
const selectedAccountDetails = props.accounts.find((account) => account.id === accountId)
|
const selectedAccountDetails = props.accounts.find((account) => account.id === accountId)
|
||||||
const selectedAccountBalance = selectedAccountDetails
|
const selectedAccountBalance = selectedAccountDetails
|
||||||
@ -50,11 +49,6 @@ export default function AccountList(props: Props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChangeLendSwitch() {
|
|
||||||
setIsLending(!isLending)
|
|
||||||
/* TODO: handle lending assets */
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const element = document.getElementById(`account-${accountId}`)
|
const element = document.getElementById(`account-${accountId}`)
|
||||||
if (element) {
|
if (element) {
|
||||||
@ -69,6 +63,8 @@ export default function AccountList(props: Props) {
|
|||||||
{props.accounts.map((account) => {
|
{props.accounts.map((account) => {
|
||||||
const positionBalance = calculateAccountDeposits(account, prices)
|
const positionBalance = calculateAccountDeposits(account, prices)
|
||||||
const isActive = accountId === account.id
|
const isActive = accountId === account.id
|
||||||
|
const isAutoLendEnabled = autoLendEnabledAccountIds.includes(account.id)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={account.id} id={`account-${account.id}`} className='w-full pt-4'>
|
<div key={account.id} id={`account-${account.id}`} className='w-full pt-4'>
|
||||||
<Card
|
<Card
|
||||||
@ -138,8 +134,8 @@ export default function AccountList(props: Props) {
|
|||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
name='isLending'
|
name='isLending'
|
||||||
label='Lend assets to earn yield'
|
label='Lend assets to earn yield'
|
||||||
value={isLending}
|
value={isAutoLendEnabled}
|
||||||
onChange={onChangeLendSwitch}
|
onChange={() => toggleAutoLend(account.id)}
|
||||||
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!`}
|
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>
|
</div>
|
||||||
|
@ -16,6 +16,7 @@ import { hardcodedFee } from 'utils/constants'
|
|||||||
import { isNumber } from 'utils/parsers'
|
import { isNumber } from 'utils/parsers'
|
||||||
|
|
||||||
const menuClasses = 'absolute isolate flex w-full flex-wrap scrollbar-hide'
|
const menuClasses = 'absolute isolate flex w-full flex-wrap scrollbar-hide'
|
||||||
|
const ACCOUNT_MENU_BUTTON_ID = 'account-menu-button'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
accounts: Account[]
|
accounts: Account[]
|
||||||
@ -57,6 +58,7 @@ export default function AccountMenuContent(props: Props) {
|
|||||||
return (
|
return (
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<Button
|
<Button
|
||||||
|
id={ACCOUNT_MENU_BUTTON_ID}
|
||||||
onClick={hasCreditAccounts ? () => setShowMenu(!showMenu) : createAccountHandler}
|
onClick={hasCreditAccounts ? () => setShowMenu(!showMenu) : createAccountHandler}
|
||||||
leftIcon={hasCreditAccounts ? <Account /> : <PlusCircled />}
|
leftIcon={hasCreditAccounts ? <Account /> : <PlusCircled />}
|
||||||
color={hasCreditAccounts ? 'tertiary' : 'primary'}
|
color={hasCreditAccounts ? 'tertiary' : 'primary'}
|
||||||
@ -133,3 +135,5 @@ export default function AccountMenuContent(props: Props) {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { ACCOUNT_MENU_BUTTON_ID }
|
||||||
|
@ -13,6 +13,7 @@ import useStore from 'store'
|
|||||||
import { getAmount } from 'utils/accounts'
|
import { getAmount } from 'utils/accounts'
|
||||||
import { hardcodedFee } from 'utils/constants'
|
import { hardcodedFee } from 'utils/constants'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
setShowFundAccount: (show: boolean) => void
|
setShowFundAccount: (show: boolean) => void
|
||||||
@ -26,7 +27,7 @@ export default function FundAccount(props: Props) {
|
|||||||
|
|
||||||
const [amount, setAmount] = useState(BN(0))
|
const [amount, setAmount] = useState(BN(0))
|
||||||
const [asset, setAsset] = useState<Asset>(ASSETS[0])
|
const [asset, setAsset] = useState<Asset>(ASSETS[0])
|
||||||
const [isLending, setIsLending] = useToggle()
|
const { autoLendEnabledAccountIds, toggleAutoLend } = useAutoLendEnabledAccountIds()
|
||||||
const [isFunding, setIsFunding] = useToggle()
|
const [isFunding, setIsFunding] = useToggle()
|
||||||
|
|
||||||
const max = getAmount(asset.denom, balances ?? [])
|
const max = getAmount(asset.denom, balances ?? [])
|
||||||
@ -39,14 +40,6 @@ export default function FundAccount(props: Props) {
|
|||||||
setAsset(asset)
|
setAsset(asset)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleLendAssets = useCallback(
|
|
||||||
(val: boolean) => {
|
|
||||||
setIsLending(val)
|
|
||||||
/* TODO: handle lending assets */
|
|
||||||
},
|
|
||||||
[setIsLending],
|
|
||||||
)
|
|
||||||
|
|
||||||
async function onDeposit() {
|
async function onDeposit() {
|
||||||
if (!accountId) return
|
if (!accountId) return
|
||||||
setIsFunding(true)
|
setIsFunding(true)
|
||||||
@ -65,6 +58,8 @@ export default function FundAccount(props: Props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!accountId) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className='absolute right-4 top-4'>
|
<div className='absolute right-4 top-4'>
|
||||||
@ -100,8 +95,8 @@ export default function FundAccount(props: Props) {
|
|||||||
<SwitchWithLabel
|
<SwitchWithLabel
|
||||||
name='isLending'
|
name='isLending'
|
||||||
label='Lend assets to earn yield'
|
label='Lend assets to earn yield'
|
||||||
value={isLending}
|
value={autoLendEnabledAccountIds.includes(accountId)}
|
||||||
onChange={() => handleLendAssets(!isLending)}
|
onChange={() => toggleAutoLend(accountId)}
|
||||||
className='mb-4'
|
className='mb-4'
|
||||||
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!"
|
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!"
|
||||||
disabled={isFunding || amount.isEqualTo(0)}
|
disabled={isFunding || amount.isEqualTo(0)}
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import { ArrowDownLine, ArrowUpLine } from 'components/Icons'
|
import { ArrowDownLine, ArrowUpLine, Enter } from 'components/Icons'
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import { Tooltip } from 'components/Tooltip'
|
import { Tooltip } from 'components/Tooltip'
|
||||||
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
import ConditionalWrapper from 'hocs/ConditionalWrapper'
|
||||||
|
import useAlertDialog from 'hooks/useAlertDialog'
|
||||||
import useCurrentAccountDeposits from 'hooks/useCurrentAccountDeposits'
|
import useCurrentAccountDeposits from 'hooks/useCurrentAccountDeposits'
|
||||||
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
|
import useLendAndReclaimModal from 'hooks/useLendAndReclaimModal'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
|
import useAutoLendEnabledAccountIds from 'hooks/useAutoLendEnabledAccountIds'
|
||||||
|
import { ACCOUNT_MENU_BUTTON_ID } from 'components/Account/AccountMenuContent'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
data: LendingMarketTableData
|
data: LendingMarketTableData
|
||||||
@ -18,8 +23,32 @@ function LendingActionButtons(props: Props) {
|
|||||||
const { asset, accountLentValue: accountLendValue } = props.data
|
const { asset, accountLentValue: accountLendValue } = props.data
|
||||||
const accountDeposits = useCurrentAccountDeposits()
|
const accountDeposits = useCurrentAccountDeposits()
|
||||||
const { openLend, openReclaim } = useLendAndReclaimModal()
|
const { openLend, openReclaim } = useLendAndReclaimModal()
|
||||||
|
const { open: showAlertDialog } = useAlertDialog()
|
||||||
|
const { isAutoLendEnabledForCurrentAccount } = useAutoLendEnabledAccountIds()
|
||||||
const assetDepositAmount = accountDeposits.find(byDenom(asset.denom))?.amount
|
const assetDepositAmount = accountDeposits.find(byDenom(asset.denom))?.amount
|
||||||
|
|
||||||
|
const handleWithdraw = useCallback(() => {
|
||||||
|
if (isAutoLendEnabledForCurrentAccount) {
|
||||||
|
showAlertDialog({
|
||||||
|
title: 'Disable Automatically Lend Assets',
|
||||||
|
description:
|
||||||
|
"Your auto-lend feature is currently enabled. To recover your funds, please confirm if you'd like to disable this feature in order to continue.",
|
||||||
|
positiveButton: {
|
||||||
|
onClick: () => document.getElementById(ACCOUNT_MENU_BUTTON_ID)?.click(),
|
||||||
|
text: 'Continue to Account Settings',
|
||||||
|
icon: <Enter />,
|
||||||
|
},
|
||||||
|
negativeButton: {
|
||||||
|
text: 'Cancel',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
openReclaim(props.data)
|
||||||
|
}, [isAutoLendEnabledForCurrentAccount, openReclaim, props.data, showAlertDialog])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-row space-x-2'>
|
<div className='flex flex-row space-x-2'>
|
||||||
{accountLendValue && (
|
{accountLendValue && (
|
||||||
@ -27,7 +56,7 @@ function LendingActionButtons(props: Props) {
|
|||||||
leftIcon={<ArrowDownLine />}
|
leftIcon={<ArrowDownLine />}
|
||||||
iconClassName={iconClassnames}
|
iconClassName={iconClassnames}
|
||||||
color='secondary'
|
color='secondary'
|
||||||
onClick={() => openReclaim(props.data)}
|
onClick={handleWithdraw}
|
||||||
className={buttonClassnames}
|
className={buttonClassnames}
|
||||||
>
|
>
|
||||||
Withdraw
|
Withdraw
|
||||||
|
@ -117,7 +117,7 @@ function LendingMarketsTable(props: Props) {
|
|||||||
header: 'Manage',
|
header: 'Manage',
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<div className='flex items-center justify-end'>
|
<div className='flex items-center justify-end'>
|
||||||
<div className='w-4'>{row.getIsExpanded() ? <ChevronUp /> : <ChevronDown />}</div>
|
<div className='w-4'>{row.getIsExpanded() ? <ChevronDown /> : <ChevronUp />}</div>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
17
src/components/Modals/AlertDialog/ButtonIcons.tsx
Normal file
17
src/components/Modals/AlertDialog/ButtonIcons.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Enter } from 'components/Icons'
|
||||||
|
|
||||||
|
export function NoIcon() {
|
||||||
|
return (
|
||||||
|
<div className='ml-1 flex items-center rounded-xs border-[1px] border-white/5 bg-white/5 px-1 py-0.5 text-[8px] font-bold leading-[10px] text-white/60 '>
|
||||||
|
ESC
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function YesIcon() {
|
||||||
|
return (
|
||||||
|
<div className='ml-1 rounded-xs border-[1px] border-white/5 bg-white/5 px-1 py-0.5'>
|
||||||
|
<Enter width={12} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
66
src/components/Modals/AlertDialog/index.tsx
Normal file
66
src/components/Modals/AlertDialog/index.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import Button from 'components/Button'
|
||||||
|
import { ExclamationMarkCircled } from 'components/Icons'
|
||||||
|
import Modal from 'components/Modal'
|
||||||
|
import Text from 'components/Text'
|
||||||
|
import useAlertDialog from 'hooks/useAlertDialog'
|
||||||
|
import { NoIcon, YesIcon } from 'components/Modals/AlertDialog/ButtonIcons'
|
||||||
|
|
||||||
|
function AlertDialogController() {
|
||||||
|
const { config, close } = useAlertDialog()
|
||||||
|
|
||||||
|
if (!config) return null
|
||||||
|
|
||||||
|
return <AlertDialog config={config} close={close} />
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
config: AlertDialogConfig
|
||||||
|
close: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function AlertDialog(props: Props) {
|
||||||
|
const { title, icon, description, negativeButton, positiveButton } = props.config
|
||||||
|
|
||||||
|
const handleButtonClick = (button?: AlertDialogButton) => {
|
||||||
|
button?.onClick && button.onClick()
|
||||||
|
props.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open
|
||||||
|
onClose={props.close}
|
||||||
|
header={
|
||||||
|
<div className='grid h-12 w-12 place-items-center rounded-sm bg-white/5'>
|
||||||
|
{icon ?? <ExclamationMarkCircled width={18} />}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
modalClassName='w-[577px]'
|
||||||
|
headerClassName='p-8'
|
||||||
|
contentClassName='px-8 pb-8'
|
||||||
|
hideCloseBtn
|
||||||
|
>
|
||||||
|
<Text size='xl'>{title}</Text>
|
||||||
|
<Text className='mt-2 text-white/60'>{description}</Text>
|
||||||
|
<div className='mt-10 flex flex-row-reverse justify-between'>
|
||||||
|
<Button
|
||||||
|
text={positiveButton.text ?? 'Yes'}
|
||||||
|
color='tertiary'
|
||||||
|
className='px-6'
|
||||||
|
rightIcon={positiveButton.icon ?? <YesIcon />}
|
||||||
|
onClick={() => handleButtonClick(positiveButton)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
text={negativeButton?.text ?? 'No'}
|
||||||
|
color='secondary'
|
||||||
|
className='px-6'
|
||||||
|
rightIcon={negativeButton?.icon ?? <NoIcon />}
|
||||||
|
tabIndex={1}
|
||||||
|
onClick={() => handleButtonClick(negativeButton)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AlertDialogController
|
@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
AddVaultBorrowAssetsModal,
|
AddVaultBorrowAssetsModal,
|
||||||
|
AlertDialogController,
|
||||||
BorrowModal,
|
BorrowModal,
|
||||||
FundAndWithdrawModal,
|
FundAndWithdrawModal,
|
||||||
LendAndReclaimModalController,
|
LendAndReclaimModalController,
|
||||||
@ -18,6 +19,7 @@ export default function ModalsContainer() {
|
|||||||
<UnlockModal />
|
<UnlockModal />
|
||||||
<LendAndReclaimModalController />
|
<LendAndReclaimModalController />
|
||||||
<WithdrawFromVaults />
|
<WithdrawFromVaults />
|
||||||
|
<AlertDialogController />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,32 +2,16 @@ import { useState } from 'react'
|
|||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
|
|
||||||
import Button from 'components/Button'
|
import Button from 'components/Button'
|
||||||
import { Enter } from 'components/Icons'
|
|
||||||
import Text from 'components/Text'
|
import Text from 'components/Text'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { hardcodedFee } from 'utils/constants'
|
import { hardcodedFee } from 'utils/constants'
|
||||||
|
import { NoIcon, YesIcon } from 'components/Modals/AlertDialog/ButtonIcons'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
depositedVault: DepositedVault
|
depositedVault: DepositedVault
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function NoIcon() {
|
|
||||||
return (
|
|
||||||
<div className='ml-1 flex items-center rounded-xs border-[1px] border-white/5 bg-white/5 px-1 py-0.5 text-[8px] font-bold leading-[10px] text-white/60 '>
|
|
||||||
ESC
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function YesIcon() {
|
|
||||||
return (
|
|
||||||
<div className='ml-1 rounded-xs border-[1px] border-white/5 bg-white/5 px-1 py-0.5'>
|
|
||||||
<Enter width={12} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function UnlockModalContent(props: Props) {
|
export default function UnlockModalContent(props: Props) {
|
||||||
const unlock = useStore((s) => s.unlock)
|
const unlock = useStore((s) => s.unlock)
|
||||||
const [isWating, setIsConfirming] = useState(false)
|
const [isWating, setIsConfirming] = useState(false)
|
||||||
|
@ -5,3 +5,4 @@ export { default as LendAndReclaimModalController } from 'components/Modals/Lend
|
|||||||
export { default as UnlockModal } from 'components/Modals/Unlock/UnlockModal'
|
export { default as UnlockModal } from 'components/Modals/Unlock/UnlockModal'
|
||||||
export { default as VaultModal } from 'components/Modals/Vault'
|
export { default as VaultModal } from 'components/Modals/Vault'
|
||||||
export { default as WithdrawFromVaults } from 'components/Modals/WithdrawFromVaults/WithdrawFromVaults'
|
export { default as WithdrawFromVaults } from 'components/Modals/WithdrawFromVaults/WithdrawFromVaults'
|
||||||
|
export { default as AlertDialogController } from 'components/Modals/AlertDialog'
|
||||||
|
@ -13,6 +13,7 @@ export const ASSETS: Asset[] = [
|
|||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
isMarket: true,
|
isMarket: true,
|
||||||
isDisplayCurrency: true,
|
isDisplayCurrency: true,
|
||||||
|
isAutoLendEnabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
symbol: 'ATOM',
|
symbol: 'ATOM',
|
||||||
@ -28,6 +29,7 @@ export const ASSETS: Asset[] = [
|
|||||||
isEnabled: true,
|
isEnabled: true,
|
||||||
isMarket: true,
|
isMarket: true,
|
||||||
isDisplayCurrency: true,
|
isDisplayCurrency: true,
|
||||||
|
isAutoLendEnabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
symbol: 'stATOM',
|
symbol: 'stATOM',
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export const DISPLAY_CURRENCY_KEY = 'displayCurrency'
|
export const DISPLAY_CURRENCY_KEY = 'displayCurrency'
|
||||||
export const ENABLE_ANIMATIONS_KEY = 'enableAnimations'
|
export const ENABLE_ANIMATIONS_KEY = 'enableAnimations'
|
||||||
export const FAVORITE_ASSETS = 'favoriteAssets'
|
export const FAVORITE_ASSETS = 'favoriteAssets'
|
||||||
|
export const AUTO_LEND_ENABLED_ACCOUNT_IDS_KEY = 'autoLendEnabledAccountIds'
|
||||||
|
19
src/hooks/useAlertDialog.ts
Normal file
19
src/hooks/useAlertDialog.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
|
function useAlertDialog() {
|
||||||
|
const config = useStore((s) => s.alertDialog)
|
||||||
|
|
||||||
|
const open = useCallback((config: AlertDialogConfig) => {
|
||||||
|
useStore.setState({ alertDialog: config })
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const close = useCallback(() => {
|
||||||
|
useStore.setState({ alertDialog: null })
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return { config, open, close }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useAlertDialog
|
33
src/hooks/useAutoLendEnabledAccountIds.ts
Normal file
33
src/hooks/useAutoLendEnabledAccountIds.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import useLocalStorage from 'hooks/useLocalStorage'
|
||||||
|
import { AUTO_LEND_ENABLED_ACCOUNT_IDS_KEY } from 'constants/localStore'
|
||||||
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
|
|
||||||
|
function useAutoLendEnabledAccountIds(): {
|
||||||
|
autoLendEnabledAccountIds: string[]
|
||||||
|
toggleAutoLend: (accountId: string) => void
|
||||||
|
isAutoLendEnabledForCurrentAccount: boolean
|
||||||
|
} {
|
||||||
|
const currentAccount = useCurrentAccount()
|
||||||
|
const [autoLendEnabledAccountIds, setAutoLendEnabledAccountIds] = useLocalStorage<string[]>(
|
||||||
|
AUTO_LEND_ENABLED_ACCOUNT_IDS_KEY,
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
const toggleAutoLend = (accountId: string) => {
|
||||||
|
const setOfAccountIds = new Set(autoLendEnabledAccountIds)
|
||||||
|
|
||||||
|
setOfAccountIds.has(accountId)
|
||||||
|
? setOfAccountIds.delete(accountId)
|
||||||
|
: setOfAccountIds.add(accountId)
|
||||||
|
|
||||||
|
setAutoLendEnabledAccountIds(Array.from(setOfAccountIds))
|
||||||
|
}
|
||||||
|
|
||||||
|
const isAutoLendEnabledForCurrentAccount = currentAccount
|
||||||
|
? autoLendEnabledAccountIds.includes(currentAccount.id)
|
||||||
|
: false
|
||||||
|
|
||||||
|
return { autoLendEnabledAccountIds, toggleAutoLend, isAutoLendEnabledForCurrentAccount }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useAutoLendEnabledAccountIds
|
45
src/hooks/useLocalStorage.ts
Normal file
45
src/hooks/useLocalStorage.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
|
export default function useLocalStorage<T>(key: string, defaultValue: T): [T, (value: T) => void] {
|
||||||
|
const keyRef = useRef(key)
|
||||||
|
const defaultValueRef = useRef(defaultValue)
|
||||||
|
const [value, _setValue] = useState(defaultValueRef.current)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const savedItem = localStorage.getItem(keyRef.current)
|
||||||
|
|
||||||
|
if (!savedItem) {
|
||||||
|
localStorage.setItem(keyRef.current, JSON.stringify(defaultValueRef.current))
|
||||||
|
}
|
||||||
|
|
||||||
|
_setValue(savedItem ? JSON.parse(savedItem) : defaultValueRef.current)
|
||||||
|
|
||||||
|
function handler(e: StorageEvent) {
|
||||||
|
if (e.key !== keyRef.current) return
|
||||||
|
|
||||||
|
const item = localStorage.getItem(keyRef.current)
|
||||||
|
_setValue(JSON.parse(item ?? JSON.stringify(defaultValueRef.current)))
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('storage', handler)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('storage', handler)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const setValue = useCallback((value: T) => {
|
||||||
|
try {
|
||||||
|
_setValue(value)
|
||||||
|
|
||||||
|
localStorage.setItem(keyRef.current, JSON.stringify(value))
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
window.dispatchEvent(new StorageEvent('storage', { key: keyRef.current }))
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return [value, setValue]
|
||||||
|
}
|
@ -12,5 +12,6 @@ export default function createModalSlice(set: SetState<ModalSlice>, get: GetStat
|
|||||||
lendAndReclaimModal: null,
|
lendAndReclaimModal: null,
|
||||||
vaultModal: null,
|
vaultModal: null,
|
||||||
withdrawFromVaultsModal: null,
|
withdrawFromVaultsModal: null,
|
||||||
|
alertDialog: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
src/types/interfaces/asset.d.ts
vendored
1
src/types/interfaces/asset.d.ts
vendored
@ -15,6 +15,7 @@ interface Asset {
|
|||||||
isDisplayCurrency?: boolean
|
isDisplayCurrency?: boolean
|
||||||
isStable?: boolean
|
isStable?: boolean
|
||||||
isFavorite?: boolean
|
isFavorite?: boolean
|
||||||
|
isAutoLendEnabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OtherAsset extends Omit<Asset, 'symbol'> {
|
interface OtherAsset extends Omit<Asset, 'symbol'> {
|
||||||
|
15
src/types/interfaces/store/modals.d.ts
vendored
15
src/types/interfaces/store/modals.d.ts
vendored
@ -9,6 +9,21 @@ interface ModalSlice {
|
|||||||
withdrawFromVaultsModal: DepositedVault[] | null
|
withdrawFromVaultsModal: DepositedVault[] | null
|
||||||
unlockModal: UnlockModal | null
|
unlockModal: UnlockModal | null
|
||||||
lendAndReclaimModal: LendAndReclaimModalConfig | null
|
lendAndReclaimModal: LendAndReclaimModalConfig | null
|
||||||
|
alertDialog: AlertDialogConfig | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AlertDialogButton {
|
||||||
|
text?: string
|
||||||
|
icon?: JSX.Element
|
||||||
|
onClick?: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AlertDialogConfig {
|
||||||
|
icon?: JSX.Element
|
||||||
|
title: JSX.Element | string
|
||||||
|
description: JSX.Element | string
|
||||||
|
negativeButton?: AlertDialogButton
|
||||||
|
positiveButton: AlertDialogButton
|
||||||
}
|
}
|
||||||
|
|
||||||
type LendAndReclaimModalAction = 'lend' | 'reclaim'
|
type LendAndReclaimModalAction = 'lend' | 'reclaim'
|
||||||
|
Loading…
Reference in New Issue
Block a user