129 lines
4.0 KiB
TypeScript
129 lines
4.0 KiB
TypeScript
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
|
|
import AssetBalanceRow from 'components/Asset/AssetBalanceRow'
|
|
import Button from 'components/Button'
|
|
import DisplayCurrency from 'components/DisplayCurrency'
|
|
import Divider from 'components/Divider'
|
|
import { Logo } from 'components/Icons'
|
|
import Overlay from 'components/Overlay'
|
|
import Text from 'components/Text'
|
|
import { ASSETS } from 'constants/assets'
|
|
import { ORACLE_DENOM } from 'constants/oracle'
|
|
import useAccountId from 'hooks/useAccountId'
|
|
import usePrices from 'hooks/usePrices'
|
|
import useToggle from 'hooks/useToggle'
|
|
import useUnclaimedRewards from 'hooks/useUnclaimedRewards'
|
|
import useStore from 'store'
|
|
import { BNCoin } from 'types/classes/BNCoin'
|
|
import { byDenom } from 'utils/array'
|
|
import { defaultFee } from 'utils/constants'
|
|
import { formatAmountWithSymbol, getCoinValue } from 'utils/formatters'
|
|
|
|
const renderIncentives = (unclaimedRewards: BNCoin[]) => {
|
|
if (unclaimedRewards.length === 0)
|
|
return (
|
|
<Text className='w-full px-4 text-center' size='sm'>
|
|
You have no claimable rewards.
|
|
</Text>
|
|
)
|
|
|
|
return unclaimedRewards.map((reward, index) => {
|
|
const asset = ASSETS.find(byDenom(reward.denom))
|
|
if (!asset) return null
|
|
return (
|
|
<div className='w-full' key={index}>
|
|
{index !== 0 && <Divider />}
|
|
<AssetBalanceRow key={reward.denom} coin={reward} asset={asset} />
|
|
</div>
|
|
)
|
|
})
|
|
}
|
|
|
|
export default function RewardsCenter() {
|
|
const accountId = useAccountId()
|
|
const [isConfirming, setIsConfirming] = useState(false)
|
|
const [estimatedFee, setEstimatedFee] = useState(defaultFee)
|
|
const [showRewardsCenter, setShowRewardsCenter] = useToggle()
|
|
const claimRewards = useStore((s) => s.claimRewards)
|
|
const { data: prices } = usePrices()
|
|
const { data: unclaimedRewards } = useUnclaimedRewards()
|
|
|
|
const totalRewardsCoin = useMemo(() => {
|
|
let total = 0
|
|
unclaimedRewards.forEach((reward) => {
|
|
total = total + getCoinValue(reward, prices).toNumber()
|
|
})
|
|
|
|
return new BNCoin({
|
|
denom: ORACLE_DENOM,
|
|
amount: total.toString(),
|
|
})
|
|
}, [prices, unclaimedRewards])
|
|
|
|
const hasIncentives = unclaimedRewards.length > 0
|
|
|
|
const claimTx = useMemo(() => {
|
|
return claimRewards({
|
|
accountId: accountId || '',
|
|
})
|
|
}, [accountId, claimRewards])
|
|
|
|
useEffect(() => {
|
|
claimTx.estimateFee().then(setEstimatedFee)
|
|
}, [claimTx])
|
|
|
|
const handleClaim = useCallback(async () => {
|
|
if (accountId) {
|
|
setIsConfirming(true)
|
|
|
|
await claimTx.execute()
|
|
setIsConfirming(false)
|
|
}
|
|
}, [accountId, claimTx])
|
|
|
|
return (
|
|
<div className={'relative'}>
|
|
<Button
|
|
variant='solid'
|
|
color='tertiary'
|
|
leftIcon={<Logo />}
|
|
onClick={() => {
|
|
setShowRewardsCenter(!showRewardsCenter)
|
|
}}
|
|
hasFocus={showRewardsCenter}
|
|
>
|
|
<div className='relative flex items-center h-fullx'>
|
|
<DisplayCurrency coin={totalRewardsCoin} />
|
|
</div>
|
|
</Button>
|
|
<Overlay className={'mt-2 right-0'} show={showRewardsCenter} setShow={setShowRewardsCenter}>
|
|
<div className='flex w-[402px] flex-wrap'>
|
|
<Text size='lg' className='w-full px-4 py-5 rounded-t-base bg-white/10'>
|
|
Rewards Center
|
|
</Text>
|
|
<div className='w-full p-4'>
|
|
<div className='flex flex-wrap w-full gap-4 pb-4'>
|
|
{renderIncentives(unclaimedRewards)}
|
|
</div>
|
|
{hasIncentives && (
|
|
<>
|
|
<Button
|
|
variant='solid'
|
|
color='tertiary'
|
|
className='w-full py-2'
|
|
showProgressIndicator={isConfirming}
|
|
text={'Claim total account rewards'}
|
|
onClick={handleClaim}
|
|
/>
|
|
<Text className='w-full py-4 text-center text-white/50' size='sm'>
|
|
Tx Fee: {formatAmountWithSymbol(estimatedFee.amount[0])}
|
|
</Text>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Overlay>
|
|
</div>
|
|
)
|
|
}
|