mango-ui-v3/components/account_page/AccountPerformance.tsx

219 lines
7.4 KiB
TypeScript

import { useEffect, useMemo, useState } from 'react'
import dayjs from 'dayjs'
import useMangoStore from '../../stores/useMangoStore'
import { Table, Td, Th, TrBody, TrHead } from '../TableElements'
import { useTranslation } from 'next-i18next'
import isEmpty from 'lodash/isEmpty'
import usePagination from '../../hooks/usePagination'
import { numberCompactFormatter } from '../../utils/'
import Pagination from '../Pagination'
import Chart from '../Chart'
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
import { exportDataToCSV } from '../../utils/export'
import { SaveIcon } from '@heroicons/react/solid'
import Button from '../Button'
export const handleDustTicks = (v) =>
v < 0.000001
? v === 0
? 0
: v.toExponential()
: numberCompactFormatter.format(v)
const AccountPerformance = () => {
const { t } = useTranslation('common')
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
const [hourlyPerformanceStats, setHourlyPerformanceStats] = useState<any>([])
const [loading, setLoading] = useState(false)
const [chartData, setChartData] = useState([])
const {
paginatedData,
setData,
totalPages,
nextPage,
previousPage,
page,
firstPage,
lastPage,
} = usePagination(hourlyPerformanceStats)
const mangoAccountPk = useMemo(() => {
if (mangoAccount) {
return mangoAccount.publicKey.toString()
}
}, [mangoAccount])
const exportPerformanceDataToCSV = () => {
const dataToExport = hourlyPerformanceStats.map((row) => {
const timestamp = new Date(row.time)
return {
timestamp: `${timestamp.toLocaleDateString()} ${timestamp.toLocaleTimeString()}`,
account_equity: row.account_equity,
pnl: row.pnl,
}
})
const title = `${
mangoAccount?.name || mangoAccount?.publicKey
}-Performance-${new Date().toLocaleDateString()}`
const headers = ['Timestamp', 'Account Equity', 'PNL']
exportDataToCSV(dataToExport, title, headers, t)
}
useEffect(() => {
if (!isEmpty(hourlyPerformanceStats)) {
setData(hourlyPerformanceStats)
}
}, [hourlyPerformanceStats])
useEffect(() => {
const fetchHourlyPerformanceStats = async () => {
setLoading(true)
const response = await fetch(
`https://mango-transaction-log.herokuapp.com/v3/stats/account-performance?mango-account=${mangoAccountPk}`
)
const parsedResponse = await response.json()
const entries: any = Object.entries(parsedResponse).sort((a, b) =>
b[0].localeCompare(a[0])
)
const stats = entries
.map(([key, value]) => {
return { ...value, time: key }
})
.filter((x) => x)
setLoading(false)
setHourlyPerformanceStats(stats)
}
fetchHourlyPerformanceStats()
}, [mangoAccountPk])
useEffect(() => {
if (hourlyPerformanceStats) {
setChartData(hourlyPerformanceStats.slice().reverse())
}
}, [hourlyPerformanceStats])
const increaseYAxisWidth = !!chartData.find((data: any) => data.value < 0.001)
return (
<>
<div className="flex items-center justify-between pb-4">
<h2>{t('account-performance')}</h2>
<div className="flex items-center">
<Button
className={`float-right h-8 pt-0 pb-0 pl-3 pr-3 text-xs`}
onClick={exportPerformanceDataToCSV}
>
<div className={`flex items-center whitespace-nowrap`}>
<SaveIcon className={`mr-1.5 h-4 w-4`} />
{t('export-data')}
</div>
</Button>
</div>
</div>
{mangoAccount ? (
<div>
<>
{!isEmpty(hourlyPerformanceStats) && !loading ? (
<>
{chartData.length > 0 ? (
<div className="flex w-full flex-col space-x-0 sm:flex-row sm:space-x-4">
<div
className="relative mb-6 w-full rounded-md border border-th-bkg-3 p-4 sm:w-1/2"
style={{ height: '330px' }}
>
<Chart
title={t('account-equity-chart-title')}
xAxis="time"
yAxis="account_equity"
data={chartData}
labelFormat={(x) => x && x.toFixed(6 + 1)}
tickFormat={handleDustTicks}
type="area"
yAxisWidth={increaseYAxisWidth ? 70 : 50}
showAll
/>
</div>
<div
className="relative mb-6 w-full rounded-md border border-th-bkg-3 p-4 sm:w-1/2"
style={{ height: '330px' }}
>
<Chart
title={t('account-pnl-chart-title')}
xAxis="time"
yAxis="pnl"
data={chartData}
labelFormat={(x) => x && x.toFixed(6 + 1)}
tickFormat={handleDustTicks}
type="area"
yAxisWidth={increaseYAxisWidth ? 70 : 50}
showAll
/>
</div>
</div>
) : null}
<div>
<div>
{paginatedData.length ? (
<Table>
<thead>
<TrHead>
<Th>{t('time')}</Th>
<Th>{t('account-equity')}</Th>
<Th>{t('account-pnl')}</Th>
</TrHead>
</thead>
<tbody>
{paginatedData.map((stat) => {
// @ts-ignore
const utc = dayjs.utc(stat.time).format()
return (
<TrBody key={stat.time}>
<Td>{dayjs(utc).format('DD/MM/YY, h:mma')}</Td>
<Td>{stat.account_equity.toFixed(6 + 1)}</Td>
<Td>{stat.pnl.toFixed(6 + 1)}</Td>
</TrBody>
)
})}
</tbody>
</Table>
) : (
<div className="flex w-full justify-center bg-th-bkg-3 py-4 text-th-fgd-3">
{t('no-performance-history')}
</div>
)}
</div>
<Pagination
page={page}
totalPages={totalPages}
nextPage={nextPage}
lastPage={lastPage}
firstPage={firstPage}
previousPage={previousPage}
/>
</div>
</>
) : loading ? (
<div className="space-y-2 pt-8">
<div className="h-12 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-12 w-full animate-pulse rounded-md bg-th-bkg-3" />
<div className="h-12 w-full animate-pulse rounded-md bg-th-bkg-3" />
</div>
) : null}
</>
</div>
) : (
<div>{t('connect-wallet')}</div>
)}
</>
)
}
export default AccountPerformance