|
|
@@ -1,8 +1,9 @@
|
|
|
'use client'
|
|
|
|
|
|
import { useEffect, useState } from 'react'
|
|
|
-import { Button, Modal, Input, Table, message, Spin, Image } from 'antd'
|
|
|
+import { Button, Modal, Input, Table, Spin, Image, App, Typography } from 'antd'
|
|
|
import type { ColumnsType } from 'antd/es/table'
|
|
|
+import dayjs from 'dayjs'
|
|
|
|
|
|
interface MintInfo {
|
|
|
symbol: string
|
|
|
@@ -17,15 +18,25 @@ interface LPInfo {
|
|
|
}
|
|
|
|
|
|
interface RecordInfo {
|
|
|
+ walletAddress: string
|
|
|
poolAddress: string
|
|
|
nftMintAddress: string
|
|
|
+ positionAddress: string
|
|
|
+ pnlUsd: string
|
|
|
+ pnlUsdPercent: string
|
|
|
PriceRange: string
|
|
|
- Token: string
|
|
|
- TokenA: number
|
|
|
- TokenB: number
|
|
|
+ totalDeposit: string
|
|
|
+ earnedUsd: string
|
|
|
+ earnedUsdPercent: string
|
|
|
+ openTime: number
|
|
|
+ bonusInfo?: {
|
|
|
+ fromCreatorPositionStatus: number
|
|
|
+ fromCreatorPosition: string
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-export default function MyLPPage() {
|
|
|
+function MyLPPageContent() {
|
|
|
+ const { message } = App.useApp()
|
|
|
const [userAddress, setUserAddress] = useState<string>('')
|
|
|
const [isModalOpen, setIsModalOpen] = useState(false)
|
|
|
const [inputValue, setInputValue] = useState<string>('')
|
|
|
@@ -33,23 +44,37 @@ export default function MyLPPage() {
|
|
|
const [loading, setLoading] = useState(false)
|
|
|
const [total, setTotal] = useState(0)
|
|
|
const [page, setPage] = useState(1)
|
|
|
- const [pageSize, setPageSize] = useState(10)
|
|
|
+ const [pageSize, setPageSize] = useState(50)
|
|
|
const [poolMap, setPoolMap] = useState<Record<string, LPInfo>>({})
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- const userAddress = localStorage.getItem('userAddress')
|
|
|
- if (userAddress) {
|
|
|
- setUserAddress(userAddress)
|
|
|
+ const fetchLPDetail = async (positions: RecordInfo[]) => {
|
|
|
+ // const newLpList = [...lpList]
|
|
|
+ message.loading(`正在查询当前页面仓位详细信息,请稍等...`)
|
|
|
+ for (let index = 0; index < positions.length; index++) {
|
|
|
+ const position = positions[index]
|
|
|
+ const response = await fetch(
|
|
|
+ `/api/my-lp/detail?address=${position.positionAddress}`
|
|
|
+ )
|
|
|
+ const data = await response.json()
|
|
|
+ console.log(data, 'data')
|
|
|
+ const newLpList = positions.map((item) => {
|
|
|
+ if (item.positionAddress === position.positionAddress) {
|
|
|
+ return Object.assign(item, data.result.data)
|
|
|
+ }
|
|
|
+ return item
|
|
|
+ })
|
|
|
+ setLpList(newLpList)
|
|
|
}
|
|
|
- }, [])
|
|
|
+ message.destroy()
|
|
|
+ }
|
|
|
|
|
|
- const fetchLPList = async () => {
|
|
|
- if (!userAddress) return
|
|
|
+ const fetchLPList = async (adddr: string) => {
|
|
|
+ if (!adddr) return
|
|
|
|
|
|
setLoading(true)
|
|
|
try {
|
|
|
const response = await fetch(
|
|
|
- `/api/my-lp?userAddress=${encodeURIComponent(userAddress)}&page=${page}&pageSize=${pageSize}`
|
|
|
+ `/api/my-lp?userAddress=${encodeURIComponent(adddr)}&page=${page}&pageSize=${pageSize}`
|
|
|
)
|
|
|
const data = await response.json()
|
|
|
console.log(data, 'data')
|
|
|
@@ -59,6 +84,7 @@ export default function MyLPPage() {
|
|
|
setTotal(total)
|
|
|
setPoolMap(poolMap)
|
|
|
message.success(`查询成功,找到 ${data.result.data.total} 个 LP token`)
|
|
|
+ fetchLPDetail(positions)
|
|
|
} else {
|
|
|
message.error(data.retMsg || '查询失败')
|
|
|
setLpList([])
|
|
|
@@ -100,17 +126,25 @@ export default function MyLPPage() {
|
|
|
lpToken: '',
|
|
|
logoURI: [],
|
|
|
price: [],
|
|
|
+ tokenAAddress: '',
|
|
|
+ tokenBAddress: '',
|
|
|
}
|
|
|
}
|
|
|
const tokenA = poolInfo.mintA.symbol
|
|
|
const tokenB = poolInfo.mintB.symbol
|
|
|
return {
|
|
|
+ tokenAAddress: poolInfo.mintA.address,
|
|
|
+ tokenBAddress: poolInfo.mintB.address,
|
|
|
lpToken: `${tokenA}/${tokenB}`,
|
|
|
logoURI: [poolInfo.mintA.logoURI, poolInfo.mintB.logoURI],
|
|
|
price: [poolInfo.mintA.price, poolInfo.mintB.price],
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ const handleClosePosition = (record: RecordInfo) => {
|
|
|
+ console.log(record, 'record')
|
|
|
+ }
|
|
|
+
|
|
|
const columns: ColumnsType<RecordInfo> = [
|
|
|
{
|
|
|
title: 'LP Token',
|
|
|
@@ -140,6 +174,16 @@ export default function MyLPPage() {
|
|
|
</div>
|
|
|
),
|
|
|
},
|
|
|
+ {
|
|
|
+ title: '当前价格',
|
|
|
+ dataIndex: 'price',
|
|
|
+ key: 'price',
|
|
|
+ render: (text: string, record: RecordInfo) => (
|
|
|
+ <span className="font-mono text-sm">
|
|
|
+ ${Number(getPoolInfo(record.poolAddress).price[0]).toFixed(8)}
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
{
|
|
|
title: 'NFT Token Address',
|
|
|
dataIndex: 'nftMintAddress',
|
|
|
@@ -151,27 +195,123 @@ export default function MyLPPage() {
|
|
|
),
|
|
|
},
|
|
|
{
|
|
|
- title: '价格范围',
|
|
|
- dataIndex: 'PriceRange',
|
|
|
- key: 'PriceRange',
|
|
|
+ title: 'Total Deposit',
|
|
|
+ dataIndex: 'totalDeposit',
|
|
|
+ key: 'totalDeposit',
|
|
|
+ render: (text: string) => (
|
|
|
+ <span className="font-mono text-sm">${Number(text).toFixed(2)}</span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'PNL',
|
|
|
+ dataIndex: 'pnlUsd',
|
|
|
+ key: 'pnlUsd',
|
|
|
+ render: (text: string) => (
|
|
|
+ <span className="font-mono text-sm">${Number(text).toFixed(2)}</span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'PNL Percent',
|
|
|
+ dataIndex: 'pnlUsd',
|
|
|
+ key: 'pnlUsdPercent',
|
|
|
+ render: (text: string) => (
|
|
|
+ <span className="font-mono text-sm">{Number(text).toFixed(2)}%</span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Earned',
|
|
|
+ dataIndex: 'earnedUsd',
|
|
|
+ key: 'pnlUsd',
|
|
|
+ render: (text: string) => (
|
|
|
+ <span className="font-mono text-sm">${Number(text).toFixed(2)}</span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: 'Earned Percent',
|
|
|
+ dataIndex: 'earnedUsdPercent',
|
|
|
+ key: 'earnedUsdPercent',
|
|
|
+ render: (text: string) => (
|
|
|
+ <span className="font-mono text-sm">{Number(text).toFixed(2)}%</span>
|
|
|
+ ),
|
|
|
},
|
|
|
{
|
|
|
- title: 'Token',
|
|
|
- dataIndex: 'Token',
|
|
|
- key: 'Token',
|
|
|
+ title: 'Earned Percent',
|
|
|
+ dataIndex: 'earnedUsdPercent',
|
|
|
+ key: 'earnedUsdPercent',
|
|
|
+ render: (text: string) => (
|
|
|
+ <span className="font-mono text-sm">{Number(text).toFixed(2)}%</span>
|
|
|
+ ),
|
|
|
},
|
|
|
{
|
|
|
- title: 'TokenA',
|
|
|
- dataIndex: 'TokenA',
|
|
|
- key: 'TokenA',
|
|
|
+ title: 'Bonus',
|
|
|
+ dataIndex: 'bonusUsd',
|
|
|
+ key: 'bonusUsd',
|
|
|
+ render: (text: string) => (
|
|
|
+ <span className="font-mono text-sm">${Number(text).toFixed(2)}</span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '开仓时间',
|
|
|
+ dataIndex: 'openTime',
|
|
|
+ key: 'openTime',
|
|
|
+ render: (text: string) => (
|
|
|
+ <span className="font-mono text-sm">
|
|
|
+ {dayjs(text).format('YYYY-MM-DD HH:mm:ss')}
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '仓位来源',
|
|
|
+ dataIndex: 'bonusInfo',
|
|
|
+ key: 'bonusInfo',
|
|
|
+ render: (text: string, record: RecordInfo) => (
|
|
|
+ <span className="font-mono text-sm">
|
|
|
+ {record?.bonusInfo?.fromCreatorPosition ? (
|
|
|
+ <span className="text-blue-500 mr-2">复制</span>
|
|
|
+ ) : (
|
|
|
+ <span className="text-green-500 mr-2">新开</span>
|
|
|
+ )}
|
|
|
+ {record?.bonusInfo?.fromCreatorPosition ? (
|
|
|
+ record?.bonusInfo?.fromCreatorPositionStatus === 0 ? (
|
|
|
+ <span className="text-green-500">上级未关仓</span>
|
|
|
+ ) : (
|
|
|
+ <span className="text-red-500">上级已关仓</span>
|
|
|
+ )
|
|
|
+ ) : (
|
|
|
+ ''
|
|
|
+ )}
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
},
|
|
|
{
|
|
|
- title: 'TokenB',
|
|
|
- dataIndex: 'TokenB',
|
|
|
- key: 'TokenB',
|
|
|
+ title: '操作',
|
|
|
+ dataIndex: 'bonusInfo',
|
|
|
+ key: 'bonusInfo',
|
|
|
+ render: (text: string, record: RecordInfo) => (
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
+ <Typography.Link
|
|
|
+ href={`https://www.byreal.io/en/portfolio?userAddress=${record.walletAddress}&tab=current&positionAddress=${record.positionAddress}&tokenAddress=${getPoolInfo(record.poolAddress).tokenAAddress}&tokenAddress=${getPoolInfo(record.poolAddress).tokenBAddress}`}
|
|
|
+ target="_blank"
|
|
|
+ >
|
|
|
+ 去关仓
|
|
|
+ </Typography.Link>
|
|
|
+ <Typography.Link onClick={() => handleClosePosition(record)}>
|
|
|
+ 快速关仓
|
|
|
+ </Typography.Link>
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
},
|
|
|
]
|
|
|
|
|
|
+ useEffect(() => {
|
|
|
+ const userAddress = localStorage.getItem('userAddress')
|
|
|
+ if (userAddress) {
|
|
|
+ setUserAddress(userAddress)
|
|
|
+ fetchLPList(userAddress)
|
|
|
+ }
|
|
|
+ // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
+ }, [])
|
|
|
+
|
|
|
return (
|
|
|
<main style={{ padding: '24px' }}>
|
|
|
<div className="mb-4">
|
|
|
@@ -181,7 +321,7 @@ export default function MyLPPage() {
|
|
|
<Button type="primary" onClick={handleAddressChange}>
|
|
|
更换地址
|
|
|
</Button>
|
|
|
- <Button onClick={fetchLPList} loading={loading}>
|
|
|
+ <Button onClick={() => fetchLPList(userAddress)} loading={loading}>
|
|
|
刷新
|
|
|
</Button>
|
|
|
</div>
|
|
|
@@ -206,8 +346,8 @@ export default function MyLPPage() {
|
|
|
}}
|
|
|
onChange={(pagination) => {
|
|
|
setPage(pagination.current || 1)
|
|
|
- setPageSize(pagination.pageSize || 10)
|
|
|
- fetchLPList()
|
|
|
+ setPageSize(pagination.pageSize || 50)
|
|
|
+ fetchLPList(userAddress)
|
|
|
}}
|
|
|
/>
|
|
|
</Spin>
|
|
|
@@ -231,3 +371,7 @@ export default function MyLPPage() {
|
|
|
</main>
|
|
|
)
|
|
|
}
|
|
|
+
|
|
|
+export default function MyLPPage() {
|
|
|
+ return <MyLPPageContent />
|
|
|
+}
|