diff --git a/src/assets/svg/ic_claim.svg b/src/assets/svg/ic_claim.svg
new file mode 100644
index 0000000000..8348f729eb
--- /dev/null
+++ b/src/assets/svg/ic_claim.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/pages/Earns/UserPositions/TableContent.tsx b/src/pages/Earns/UserPositions/TableContent.tsx
new file mode 100644
index 0000000000..157e9997cb
--- /dev/null
+++ b/src/pages/Earns/UserPositions/TableContent.tsx
@@ -0,0 +1,270 @@
+import { t } from '@lingui/macro'
+import { Minus, Plus } from 'react-feather'
+import { Link, useNavigate } from 'react-router-dom'
+import { useMedia } from 'react-use'
+import { Flex, Text } from 'rebass'
+import { EarnPosition, PositionStatus } from 'services/zapEarn'
+
+import { ReactComponent as IconClaim } from 'assets/svg/ic_claim.svg'
+import { ReactComponent as IconEarnNotFound } from 'assets/svg/ic_earn_not_found.svg'
+import CopyHelper from 'components/Copy'
+import { MouseoverTooltipDesktopOnly } from 'components/Tooltip'
+import { APP_PATHS } from 'constants/index'
+import { useActiveWeb3React } from 'hooks'
+import useTheme from 'hooks/useTheme'
+import { useWalletModalToggle } from 'state/application/hooks'
+import { MEDIA_WIDTHS } from 'theme'
+import { shortenAddress } from 'utils'
+import { formatDisplayNumber } from 'utils/numbers'
+
+import { CurrencyRoundedImage, CurrencySecondImage } from '../PoolExplorer/styles'
+import { PositionAction as PositionActionBtn } from '../PositionDetail/styles'
+import {
+ Badge,
+ BadgeType,
+ ChainImage,
+ DexImage,
+ Divider,
+ EmptyPositionText,
+ ImageContainer,
+ PositionAction,
+ PositionOverview,
+ PositionRow,
+ PositionTableBody,
+ PositionValueLabel,
+ PositionValueWrapper,
+} from './styles'
+
+export default function TableContent({
+ positions,
+ onOpenZapInWidget,
+ onOpenZapOut,
+}: {
+ positions: Array | undefined
+ onOpenZapInWidget: (pool: { exchange: string; chainId?: number; address: string }, positionId?: string) => void
+ onOpenZapOut: (position: { dex: string; chainId: number; poolAddress: string; id: string }) => void
+}) {
+ const { account } = useActiveWeb3React()
+ const navigate = useNavigate()
+ const toggleWalletModal = useWalletModalToggle()
+ const theme = useTheme()
+ const upToLarge = useMedia(`(max-width: ${MEDIA_WIDTHS.upToLarge}px)`)
+ const upToSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToSmall}px)`)
+
+ const handleOpenIncreaseLiquidityWidget = (e: React.MouseEvent, position: EarnPosition) => {
+ e.stopPropagation()
+ onOpenZapInWidget(
+ {
+ exchange: position.pool.project || '',
+ chainId: position.chainId,
+ address: position.pool.poolAddress,
+ },
+ position.tokenId,
+ )
+ }
+
+ const handleOpenZapOut = (e: React.MouseEvent, position: EarnPosition) => {
+ e.stopPropagation()
+ onOpenZapOut({
+ dex: position.pool.project || '',
+ chainId: position.chainId,
+ id: position.tokenId,
+ poolAddress: position.pool.poolAddress,
+ })
+ }
+
+ return (
+
+ {account && positions && positions.length > 0 ? (
+ positions.map(position => {
+ const { id, status, chainId: poolChainId } = position
+ const positionId = position.tokenId
+ const chainImage = position.chainLogo
+ const dexImage = position.pool.projectLogo
+ const dexVersion = position.pool.project?.split(' ')?.[1] || ''
+ const token0Logo = position.pool.tokenAmounts[0]?.token.logo
+ const token1Logo = position.pool.tokenAmounts[1]?.token.logo
+ const token0Symbol = position.pool.tokenAmounts[0]?.token.symbol
+ const token1Symbol = position.pool.tokenAmounts[1]?.token.symbol
+ const poolFee = position.pool.fees?.[0]
+ const poolAddress = position.pool.poolAddress
+ const totalValue = position.currentPositionValue
+ const token0TotalProvide =
+ position.currentAmounts[0]?.quotes.usd.value / position.currentAmounts[0]?.quotes.usd.price
+ const token1TotalProvide =
+ position.currentAmounts[1]?.quotes.usd.value / position.currentAmounts[1]?.quotes.usd.price
+ const token0EarnedAmount =
+ position.feePending[0]?.quotes.usd.value / position.feePending[0]?.quotes.usd.price +
+ position.feesClaimed[0]?.quotes.usd.value / position.feesClaimed[0]?.quotes.usd.price
+ const token1EarnedAmount =
+ position.feePending[1]?.quotes.usd.value / position.feePending[1]?.quotes.usd.price +
+ position.feesClaimed[1]?.quotes.usd.value / position.feesClaimed[1]?.quotes.usd.price
+ const token0TotalAmount = token0TotalProvide + token0EarnedAmount
+ const token1TotalAmount = token1TotalProvide + token1EarnedAmount
+ const earning7d = position.earning7d
+ const totalUnclaimedFee = position.feePending.reduce((a, b) => a + b.quotes.usd.value, 0)
+ const token0UnclaimedAmount =
+ position.feePending[0]?.quotes.usd.value / position.feePending[0]?.quotes.usd.price
+ const token1UnclaimedAmount =
+ position.feePending[1]?.quotes.usd.value / position.feePending[1]?.quotes.usd.price
+
+ return (
+
+ navigate({
+ pathname: APP_PATHS.EARN_POSITION_DETAIL.replace(':chainId', poolChainId.toString()).replace(
+ ':id',
+ id,
+ ),
+ })
+ }
+ >
+
+
+
+
+
+
+
+
+ {token0Symbol}/{token1Symbol}
+
+ {poolFee && {poolFee}%}
+
+ ● {status === PositionStatus.IN_RANGE ? t`In range` : t`Out of range`}
+
+
+
+
+
+
+ {dexVersion}
+
+
+
+ #{positionId}
+
+
+ {shortenAddress(poolChainId, poolAddress, 4)}
+
+
+
+
+ {upToLarge && !upToSmall && (
+
+ handleOpenIncreaseLiquidityWidget(e, position)}>
+
+
+ handleOpenZapOut(e, position)}>
+
+
+
+
+
+
+ )}
+
+ {t`Value`}
+
+
+ {formatDisplayNumber(token0TotalAmount, { significantDigits: 6 })} {token0Symbol}
+
+
+ {formatDisplayNumber(token1TotalAmount, { significantDigits: 6 })} {token1Symbol}
+
+ >
+ }
+ width="fit-content"
+ placement="bottom"
+ >
+
+ {formatDisplayNumber(totalValue, {
+ style: 'currency',
+ significantDigits: 4,
+ })}
+
+
+
+
+ {t`APR`}
+
+ {formatDisplayNumber(earning7d, {
+ style: 'currency',
+ significantDigits: 4,
+ })}
+
+
+
+ {t`Unclaimed Fee`}
+
+
+ {formatDisplayNumber(token0UnclaimedAmount, { significantDigits: 6 })} {token0Symbol}
+
+
+ {formatDisplayNumber(token1UnclaimedAmount, { significantDigits: 6 })} {token1Symbol}
+
+ >
+ }
+ width="fit-content"
+ placement="bottom"
+ >
+ {formatDisplayNumber(totalUnclaimedFee, { style: 'currency', significantDigits: 4 })}
+
+
+
+ {t`Bal`}
+
+
+ {formatDisplayNumber(token0TotalProvide, { significantDigits: 4 })} {token0Symbol}
+
+ {upToSmall && }
+
+ {formatDisplayNumber(token1TotalProvide, { significantDigits: 4 })} {token1Symbol}
+
+
+
+
+ {(upToSmall || !upToLarge) && (
+
+
+ handleOpenIncreaseLiquidityWidget(e, position)}>
+
+
+
+
+ handleOpenZapOut(e, position)}>
+
+
+
+
+
+
+
+ )}
+
+ )
+ })
+ ) : (
+
+
+
+ {t`You don’t have any liquidity positions yet`}.
+ {t`Explore Liquidity Pools to get started`}!
+
+ {!account && Connect Wallet}
+
+ )}
+
+ )
+}
diff --git a/src/pages/Earns/UserPositions/index.tsx b/src/pages/Earns/UserPositions/index.tsx
index b9a50df8ea..a93e3564b8 100644
--- a/src/pages/Earns/UserPositions/index.tsx
+++ b/src/pages/Earns/UserPositions/index.tsx
@@ -1,57 +1,32 @@
import { t } from '@lingui/macro'
import { useEffect, useMemo, useRef, useState } from 'react'
-import { Minus, Plus } from 'react-feather'
-import { Link, useNavigate } from 'react-router-dom'
+import { useNavigate } from 'react-router-dom'
import { useMedia } from 'react-use'
import { Flex, Text } from 'rebass'
-import { EarnPosition, PositionStatus, useUserPositionsQuery } from 'services/zapEarn'
+import { useUserPositionsQuery } from 'services/zapEarn'
-import { ReactComponent as IconEarnNotFound } from 'assets/svg/ic_earn_not_found.svg'
import { ReactComponent as RocketIcon } from 'assets/svg/rocket.svg'
-import CopyHelper from 'components/Copy'
import LocalLoader from 'components/LocalLoader'
import Pagination from 'components/Pagination'
-import { MouseoverTooltipDesktopOnly } from 'components/Tooltip'
import { APP_PATHS } from 'constants/index'
-import { useActiveWeb3React } from 'hooks'
-import useTheme from 'hooks/useTheme'
-import { useWalletModalToggle } from 'state/application/hooks'
+import SortIcon, { Direction } from 'pages/MarketOverview/SortIcon'
import { MEDIA_WIDTHS } from 'theme'
-import { shortenAddress } from 'utils'
-import { formatDisplayNumber } from 'utils/numbers'
-import { CurrencyRoundedImage, CurrencySecondImage, Disclaimer, NavigateButton } from '../PoolExplorer/styles'
-import { IconArrowLeft, PositionAction as PositionActionBtn } from '../PositionDetail/styles'
+import { ContentWrapper, Disclaimer, NavigateButton } from '../PoolExplorer/styles'
+import { IconArrowLeft } from '../PositionDetail/styles'
import useLiquidityWidget from '../useLiquidityWidget'
import useSupportedDexesAndChains from '../useSupportedDexesAndChains'
import Filter from './Filter'
import PositionBanner from './PositionBanner'
-import {
- Badge,
- BadgeType,
- ChainImage,
- DexImage,
- Divider,
- EmptyPositionText,
- ImageContainer,
- MyLiquidityWrapper,
- PositionAction,
- PositionOverview,
- PositionPageWrapper,
- PositionRow,
- PositionValueLabel,
- PositionValueWrapper,
-} from './styles'
-import useFilter from './useFilter'
+import TableContent from './TableContent'
+import { PositionPageWrapper, PositionTableHeader, PositionTableWrapper } from './styles'
+import useFilter, { SortBy } from './useFilter'
-const LIMIT = 20
+const POSITIONS_TABLE_LIMIT = 10
const MyPositions = () => {
- const theme = useTheme()
- const { account } = useActiveWeb3React()
- const toggleWalletModal = useWalletModalToggle()
const navigate = useNavigate()
- const upToLarge = useMedia(`(max-width: ${MEDIA_WIDTHS.upToLarge}px)`)
+ const upToMedium = useMedia(`(max-width: ${MEDIA_WIDTHS.upToMedium}px)`)
const upToSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToSmall}px)`)
const { filters, onFilterChange } = useFilter()
const { supportedDexes, supportedChains } = useSupportedDexesAndChains(filters)
@@ -61,28 +36,35 @@ const MyPositions = () => {
const [loading, setLoading] = useState(false)
const [page, setPage] = useState(1)
- const { data: userPosition, isFetching } = useUserPositionsQuery(filters, {
+ const {
+ data: userPosition,
+ isFetching,
+ isError,
+ } = useUserPositionsQuery(filters, {
skip: !filters.addresses,
pollingInterval: 15_000,
})
- const isShowPagination = (!isFetching || !loading) && userPosition && userPosition.length > LIMIT
-
const positionsToShow = useMemo(() => {
- if (!isShowPagination) return userPosition
- return userPosition.slice((page - 1) * LIMIT, page * LIMIT)
- }, [isShowPagination, page, userPosition])
-
- const onOpenIncreaseLiquidityWidget = (e: React.MouseEvent, position: EarnPosition) => {
- e.stopPropagation()
- handleOpenZapInWidget(
- {
- exchange: position.pool.project || '',
- chainId: position.chainId,
- address: position.pool.poolAddress,
- },
- position.tokenId,
- )
+ if ((!isFetching || !loading) && userPosition && userPosition.length > POSITIONS_TABLE_LIMIT)
+ return userPosition.slice((page - 1) * POSITIONS_TABLE_LIMIT, page * POSITIONS_TABLE_LIMIT)
+
+ return userPosition
+ }, [isFetching, loading, page, userPosition])
+
+ const onSortChange = (sortBy: string) => {
+ setPage(1)
+ if (!filters.sortBy || filters.sortBy !== sortBy) {
+ onFilterChange('sortBy', sortBy)
+ onFilterChange('orderBy', Direction.DESC)
+ return
+ }
+ if (filters.orderBy === Direction.DESC) {
+ onFilterChange('orderBy', Direction.ASC)
+ return
+ }
+ onFilterChange('sortBy', SortBy.VALUE)
+ onFilterChange('orderBy', Direction.DESC)
}
useEffect(() => {
@@ -132,210 +114,62 @@ const MyPositions = () => {
}}
/>
-
- {isFetching && loading ? (
-
- ) : account && positionsToShow && positionsToShow.length > 0 ? (
- positionsToShow.map(position => {
- const { id, status, chainId: poolChainId } = position
- const positionId = position.tokenId
- const chainImage = position.chainLogo
- const dexImage = position.pool.projectLogo
- const dexVersion = position.pool.project?.split(' ')?.[1] || ''
- const token0Logo = position.pool.tokenAmounts[0]?.token.logo
- const token1Logo = position.pool.tokenAmounts[1]?.token.logo
- const token0Symbol = position.pool.tokenAmounts[0]?.token.symbol
- const token1Symbol = position.pool.tokenAmounts[1]?.token.symbol
- const poolFee = position.pool.fees?.[0]
- const poolAddress = position.pool.poolAddress
- const totalValue = position.currentPositionValue
- const token0TotalProvide =
- position.currentAmounts[0]?.quotes.usd.value / position.currentAmounts[0]?.quotes.usd.price
- const token1TotalProvide =
- position.currentAmounts[1]?.quotes.usd.value / position.currentAmounts[1]?.quotes.usd.price
- const token0EarnedAmount =
- position.feePending[0]?.quotes.usd.value / position.feePending[0]?.quotes.usd.price +
- position.feesClaimed[0]?.quotes.usd.value / position.feesClaimed[0]?.quotes.usd.price
- const token1EarnedAmount =
- position.feePending[1]?.quotes.usd.value / position.feePending[1]?.quotes.usd.price +
- position.feesClaimed[1]?.quotes.usd.value / position.feesClaimed[1]?.quotes.usd.price
- const token0TotalAmount = token0TotalProvide + token0EarnedAmount
- const token1TotalAmount = token1TotalProvide + token1EarnedAmount
- const totalEarnedFee =
- position.feePending.reduce((a, b) => a + b.quotes.usd.value, 0) +
- position.feesClaimed.reduce((a, b) => a + b.quotes.usd.value, 0)
-
- return (
-
- navigate({
- pathname: APP_PATHS.EARN_POSITION_DETAIL.replace(':chainId', poolChainId.toString()).replace(
- ':id',
- id,
- ),
- })
- }
+
+
+ {!upToMedium && positionsToShow && positionsToShow.length > 0 && (
+
+ {t`Position`}
+ onSortChange(SortBy.VALUE)}
+ >
+ {t`Value`}
+
+
+ onSortChange(SortBy.APR_7D)}
>
-
-
-
-
-
-
-
-
- {token0Symbol}/{token1Symbol}
-
- {poolFee && {poolFee}%}
-
- ● {status === PositionStatus.IN_RANGE ? t`In range` : t`Out of range`}
-
-
-
-
-
-
- {dexVersion}
-
-
-
- #{positionId}
-
-
- {shortenAddress(poolChainId, poolAddress, 4)}
-
-
-
-
- {upToLarge && !upToSmall && (
-
- {
- e.stopPropagation()
- handleOpenZapOut({
- dex: position.pool.project || '',
- chainId: position.chainId,
- id: position.tokenId,
- poolAddress: position.pool.poolAddress,
- })
- }}
- >
-
-
- onOpenIncreaseLiquidityWidget(e, position)}>
-
-
-
- )}
-
- {t`Value`}
-
-
- {formatDisplayNumber(token0TotalAmount, { significantDigits: 6 })} {token0Symbol}
-
-
- {formatDisplayNumber(token1TotalAmount, { significantDigits: 6 })} {token1Symbol}
-
- >
- }
- width="fit-content"
- placement="bottom"
- >
-
- {formatDisplayNumber(totalValue, {
- style: 'currency',
- significantDigits: 4,
- })}
-
-
-
-
- {t`Earned Fee`}
-
-
- {formatDisplayNumber(token0EarnedAmount, { significantDigits: 6 })} {token0Symbol}
-
-
- {formatDisplayNumber(token1EarnedAmount, { significantDigits: 6 })} {token1Symbol}
-
- >
- }
- width="fit-content"
- placement="bottom"
- >
- {formatDisplayNumber(totalEarnedFee, { style: 'currency', significantDigits: 4 })}
-
-
-
- Balance
-
-
- {formatDisplayNumber(token0TotalProvide, { significantDigits: 4 })} {token0Symbol}
-
- {upToSmall && }
-
- {formatDisplayNumber(token1TotalProvide, { significantDigits: 4 })} {token1Symbol}
-
-
-
- {(upToSmall || !upToLarge) && (
-
-
- {
- e.stopPropagation()
- handleOpenZapOut({
- dex: position.pool.project || '',
- chainId: position.chainId,
- id: position.tokenId,
- poolAddress: position.pool.poolAddress,
- })
- }}
- >
-
-
-
-
- onOpenIncreaseLiquidityWidget(e, position)}>
-
-
-
-
- )}
-
- )
- })
- ) : (
-
-
-
- {t`You don’t have any liquidity positions yet`}.
- {t`Explore Liquidity Pools to get started`}!
-
- {!account && Connect Wallet}
-
+ {t`7D APR`}
+
+
+ onSortChange(SortBy.UNCLAIMED_FEE)}
+ >
+ {t`Unclaimed fee`}
+
+
+ {t`Balance`}
+ {t`Price Range`}
+ {t`Actions`}
+
+ )}
+ {isFetching && loading ? (
+
+ ) : (
+
+ )}
+
+ {!isError && (
+ setPage(newPage)}
+ totalCount={userPosition?.length || 0}
+ currentPage={page || 1}
+ pageSize={POSITIONS_TABLE_LIMIT}
+ />
)}
-
- {isShowPagination && (
- setPage(newPage)}
- totalCount={userPosition.length}
- currentPage={page}
- pageSize={LIMIT}
- />
- )}
+
{t`KyberSwap provides tools for tracking & adding liquidity to third-party Protocols. For any pool-related concerns, please contact the respective Liquidity Protocol directly.`}
diff --git a/src/pages/Earns/UserPositions/styles.tsx b/src/pages/Earns/UserPositions/styles.tsx
index dbc5abde72..e8ea9420ec 100644
--- a/src/pages/Earns/UserPositions/styles.tsx
+++ b/src/pages/Earns/UserPositions/styles.tsx
@@ -3,10 +3,10 @@ import styled from 'styled-components'
import earnLargeBg from 'assets/banners/earn_background_large.png'
-import { PoolPageWrapper } from '../PoolExplorer/styles'
+import { PoolPageWrapper, TableBody, TableHeader, TableWrapper } from '../PoolExplorer/styles'
export const PositionPageWrapper = styled(PoolPageWrapper)`
- padding: 24px 6rem 50px;
+ padding: 24px 6rem 62px;
${({ theme }) => theme.mediaWidth.upToLarge`
padding: 24px 6rem 60px;
@@ -17,28 +17,16 @@ export const PositionPageWrapper = styled(PoolPageWrapper)`
`}
`
-export const MyLiquidityWrapper = styled.div`
- display: flex;
- flex-direction: column;
- gap: 1rem;
-
- ${({ theme }) => theme.mediaWidth.upToSmall`
- max-height: unset;
- `}
-`
-
export const PositionRow = styled.div`
display: grid;
- grid-template-columns: 2fr 1fr 1fr 1fr 75px;
+ grid-template-columns: 3fr 1fr 1fr 1.2fr 1.2fr 1.5fr 1fr;
grid-template-rows: 1fr;
- background-color: ${({ theme }) => rgba(theme.background, 0.8)};
- border-radius: 20px;
padding: 16px 28px;
row-gap: 8px;
${({ theme }) => theme.mediaWidth.upToLarge`
justify-content: flex-start;
- grid-template-columns: repeat(3, 1fr);
+ grid-template-columns: repeat(4, 1fr);
grid-template-rows: 1fr 1fr;
`}
@@ -47,11 +35,18 @@ export const PositionRow = styled.div`
flex-direction: column;
row-gap: 16px;
padding: 16px;
+ border-radius: 20px;
+ background: ${rgba(theme.background, 0.8)};
+ margin-bottom: 16px;
`}
+ &:last-child {
+ margin-bottom: 0;
+ }
+
&:hover {
cursor: pointer;
- filter: brightness(1.1);
+ background: #31cb9e1a;
}
`
@@ -61,7 +56,7 @@ export const PositionOverview = styled.div`
gap: 8px;
${({ theme }) => theme.mediaWidth.upToLarge`
- grid-column: span 2;
+ grid-column: span 3;
`}
`
@@ -147,6 +142,11 @@ export const PositionValueLabel = styled.p`
color: ${({ theme }) => theme.subText};
position: relative;
top: 1px;
+ display: none;
+
+ ${({ theme }) => theme.mediaWidth.upToLarge`
+ display: block;
+ `}
${({ theme }) => theme.mediaWidth.upToSmall`
font-size: 16px;
@@ -284,3 +284,18 @@ export const BannerDataItem = styled.div`
justify-content: space-between;
`}
`
+
+export const PositionTableHeader = styled(TableHeader)`
+ grid-template-columns: 3fr 1fr 1fr 1.2fr 1.2fr 1.5fr 1fr;
+`
+
+export const PositionTableWrapper = styled(TableWrapper)`
+ ${({ theme }) => theme.mediaWidth.upToSmall`
+ background: transparent;
+ margin: 0;
+ `}
+`
+
+export const PositionTableBody = styled(TableBody)`
+ max-height: unset;
+`
diff --git a/src/pages/Earns/UserPositions/useFilter.ts b/src/pages/Earns/UserPositions/useFilter.ts
index 3763828ba4..24f34abc6e 100644
--- a/src/pages/Earns/UserPositions/useFilter.ts
+++ b/src/pages/Earns/UserPositions/useFilter.ts
@@ -1,6 +1,13 @@
import { useEffect, useState } from 'react'
import { useActiveWeb3React } from 'hooks'
+import { Direction } from 'pages/MarketOverview/SortIcon'
+
+export enum SortBy {
+ VALUE = 'value',
+ APR_7D = 'apr_7d',
+ UNCLAIMED_FEE = 'unclaimed_fee',
+}
export default function useFilter() {
const { account } = useActiveWeb3React()
@@ -10,6 +17,8 @@ export default function useFilter() {
protocols: '',
status: '',
q: '',
+ sortBy: SortBy.VALUE,
+ orderBy: Direction.DESC,
})
const onFilterChange = (key: string, value: string | number) => {
diff --git a/src/services/zapEarn.ts b/src/services/zapEarn.ts
index 42652ddb23..3acb755cfe 100644
--- a/src/services/zapEarn.ts
+++ b/src/services/zapEarn.ts
@@ -1,6 +1,9 @@
import { ChainId } from '@kyberswap/ks-sdk-core'
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
+import { SortBy } from 'pages/Earns/UserPositions/useFilter'
+import { Direction } from 'pages/MarketOverview/SortIcon'
+
interface ExplorerLandingResponse {
data: {
highlightedPools: Array
@@ -108,6 +111,8 @@ export interface PositionQueryParams {
protocols?: string
status?: string
q?: string
+ sortBy?: string
+ orderBy?: string
}
export interface EarnPosition {
@@ -271,8 +276,33 @@ const zapEarnServiceApi = createApi({
_meta,
arg,
) => {
- if (!arg.status) return response.data.positions
- return response.data.positions.filter((position: EarnPosition) => position.status === arg.status)
+ let positions
+ if (!arg.status) positions = response.data.positions
+ else positions = response.data.positions.filter((position: EarnPosition) => position.status === arg.status)
+
+ if (arg.sortBy && positions && positions.length) {
+ if (arg.sortBy === SortBy.VALUE) {
+ positions = positions.sort((a, b) => {
+ const aValue = a.currentPositionValue
+ const bValue = b.currentPositionValue
+ return arg.orderBy === Direction.ASC ? aValue - bValue : bValue - aValue
+ })
+ } else if (arg.sortBy === SortBy.APR_7D) {
+ positions = positions.sort((a, b) => {
+ const aValue = a.earning7d
+ const bValue = b.earning7d
+ return arg.orderBy === Direction.ASC ? aValue - bValue : bValue - aValue
+ })
+ } else if (arg.sortBy === SortBy.UNCLAIMED_FEE) {
+ positions = positions.sort((a, b) => {
+ const aValue = a.feePending.reduce((total, fee) => total + fee.quotes.usd.value, 0)
+ const bValue = b.feePending.reduce((total, fee) => total + fee.quotes.usd.value, 0)
+ return arg.orderBy === Direction.ASC ? aValue - bValue : bValue - aValue
+ })
+ }
+ }
+
+ return positions
},
}),
addFavorite: builder.mutation({