WIP adds RedeemDropdown
This commit is contained in:
parent
c79e0869b5
commit
8f40cce851
|
@ -25,6 +25,7 @@ yarn-debug.log*
|
|||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
|
|
|
@ -360,101 +360,107 @@ const BalancesTable = ({
|
|||
</TrHead>
|
||||
</thead>
|
||||
<tbody>
|
||||
{items.map((balance, index) => (
|
||||
<TrBody key={`${balance.symbol}${index}`}>
|
||||
<Td>
|
||||
<div className="flex items-center">
|
||||
<img
|
||||
alt=""
|
||||
width="20"
|
||||
height="20"
|
||||
src={`/assets/icons/${balance.symbol.toLowerCase()}.svg`}
|
||||
className={`mr-2.5`}
|
||||
/>
|
||||
|
||||
{balance.symbol === 'USDC' ||
|
||||
decodeURIComponent(asPath).includes(
|
||||
`${balance.symbol}/USDC`
|
||||
) ? (
|
||||
<span>{balance.symbol}</span>
|
||||
) : (
|
||||
<Link
|
||||
href={{
|
||||
pathname: '/',
|
||||
query: { name: `${balance.symbol}/USDC` },
|
||||
}}
|
||||
shallow={true}
|
||||
>
|
||||
<a className="text-th-fgd-1 underline hover:text-th-fgd-1 hover:no-underline">
|
||||
{balance.symbol}
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</Td>
|
||||
<Td>{balance.deposits.toFormat(balance.decimals)}</Td>
|
||||
<Td>{balance.borrows.toFormat(balance.decimals)}</Td>
|
||||
<Td>{balance.orders}</Td>
|
||||
<Td>{balance.unsettled}</Td>
|
||||
<Td>
|
||||
{marketConfig.kind === 'spot' &&
|
||||
marketConfig.name.includes(balance.symbol) &&
|
||||
selectedMarket &&
|
||||
clickToPopulateTradeForm ? (
|
||||
<span
|
||||
className={
|
||||
balance.net.toNumber() != 0
|
||||
? 'cursor-pointer underline hover:no-underline'
|
||||
: ''
|
||||
}
|
||||
onClick={() =>
|
||||
handleSizeClick(balance.net, balance.symbol)
|
||||
}
|
||||
>
|
||||
{balance.net.toFormat(balance.decimals)}
|
||||
</span>
|
||||
) : (
|
||||
balance.net.toFormat(balance.decimals)
|
||||
)}
|
||||
</Td>
|
||||
<Td>{formatUsdValue(balance.value.toNumber())}</Td>
|
||||
<Td>
|
||||
<span className="text-th-green">
|
||||
{balance.depositRate.toFixed(2)}%
|
||||
</span>
|
||||
</Td>
|
||||
<Td>
|
||||
<span className="text-th-red">
|
||||
{balance.borrowRate.toFixed(2)}%
|
||||
</span>
|
||||
</Td>
|
||||
{showDepositWithdraw ? (
|
||||
{items.map((balance, index) => {
|
||||
console.log('balance', balance)
|
||||
if (!balance) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<TrBody key={`${balance.symbol}${index}`}>
|
||||
<Td>
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
className="h-7 pt-0 pb-0 pl-3 pr-3 text-xs"
|
||||
onClick={() =>
|
||||
handleOpenDepositModal(balance.symbol)
|
||||
}
|
||||
>
|
||||
{balance.borrows.toNumber() > 0
|
||||
? t('repay')
|
||||
: t('deposit')}
|
||||
</Button>
|
||||
<Button
|
||||
className="ml-4 h-7 pt-0 pb-0 pl-3 pr-3 text-xs"
|
||||
onClick={() =>
|
||||
handleOpenWithdrawModal(balance.symbol)
|
||||
}
|
||||
disabled={!canWithdraw}
|
||||
>
|
||||
{t('withdraw')}
|
||||
</Button>
|
||||
<div className="flex items-center">
|
||||
<img
|
||||
alt=""
|
||||
width="20"
|
||||
height="20"
|
||||
src={`/assets/icons/${balance.symbol.toLowerCase()}.svg`}
|
||||
className={`mr-2.5`}
|
||||
/>
|
||||
|
||||
{balance.symbol === 'USDC' ||
|
||||
decodeURIComponent(asPath).includes(
|
||||
`${balance.symbol}/USDC`
|
||||
) ? (
|
||||
<span>{balance.symbol}</span>
|
||||
) : (
|
||||
<Link
|
||||
href={{
|
||||
pathname: '/',
|
||||
query: { name: `${balance.symbol}/USDC` },
|
||||
}}
|
||||
shallow={true}
|
||||
>
|
||||
<a className="text-th-fgd-1 underline hover:text-th-fgd-1 hover:no-underline">
|
||||
{balance.symbol}
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</Td>
|
||||
) : null}
|
||||
</TrBody>
|
||||
))}
|
||||
<Td>{balance.deposits.toFormat(balance.decimals)}</Td>
|
||||
<Td>{balance.borrows.toFormat(balance.decimals)}</Td>
|
||||
<Td>{balance.orders}</Td>
|
||||
<Td>{balance.unsettled}</Td>
|
||||
<Td>
|
||||
{marketConfig.kind === 'spot' &&
|
||||
marketConfig.name.includes(balance.symbol) &&
|
||||
selectedMarket &&
|
||||
clickToPopulateTradeForm ? (
|
||||
<span
|
||||
className={
|
||||
balance.net.toNumber() != 0
|
||||
? 'cursor-pointer underline hover:no-underline'
|
||||
: ''
|
||||
}
|
||||
onClick={() =>
|
||||
handleSizeClick(balance.net, balance.symbol)
|
||||
}
|
||||
>
|
||||
{balance.net.toFormat(balance.decimals)}
|
||||
</span>
|
||||
) : (
|
||||
balance.net.toFormat(balance.decimals)
|
||||
)}
|
||||
</Td>
|
||||
<Td>{formatUsdValue(balance.value.toNumber())}</Td>
|
||||
<Td>
|
||||
<span className="text-th-green">
|
||||
{balance.depositRate.toFixed(2)}%
|
||||
</span>
|
||||
</Td>
|
||||
<Td>
|
||||
<span className="text-th-red">
|
||||
{balance.borrowRate.toFixed(2)}%
|
||||
</span>
|
||||
</Td>
|
||||
{showDepositWithdraw ? (
|
||||
<Td>
|
||||
<div className="flex justify-end">
|
||||
<Button
|
||||
className="h-7 pt-0 pb-0 pl-3 pr-3 text-xs"
|
||||
onClick={() =>
|
||||
handleOpenDepositModal(balance.symbol)
|
||||
}
|
||||
>
|
||||
{balance.borrows.toNumber() > 0
|
||||
? t('repay')
|
||||
: t('deposit')}
|
||||
</Button>
|
||||
<Button
|
||||
className="ml-4 h-7 pt-0 pb-0 pl-3 pr-3 text-xs"
|
||||
onClick={() =>
|
||||
handleOpenWithdrawModal(balance.symbol)
|
||||
}
|
||||
disabled={!canWithdraw}
|
||||
>
|
||||
{t('withdraw')}
|
||||
</Button>
|
||||
</div>
|
||||
</Td>
|
||||
) : null}
|
||||
</TrBody>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
{showDepositModal && (
|
||||
<DepositModal
|
||||
|
|
|
@ -38,6 +38,12 @@ const MarketNavItem: FunctionComponent<MarketNavItemProps> = ({
|
|||
mangoGroupConfig,
|
||||
market.baseSymbol
|
||||
)
|
||||
|
||||
// The following if statement is for markets not on devnet
|
||||
if (!mangoGroup.spotMarkets[marketIndex]) {
|
||||
return 1
|
||||
}
|
||||
|
||||
const ws = getWeights(mangoGroup, marketIndex, 'Init')
|
||||
const w = market.name.includes('PERP')
|
||||
? ws.perpAssetWeight
|
||||
|
|
|
@ -21,6 +21,45 @@ import { breakpoints } from './TradePageGrid'
|
|||
import { useTranslation } from 'next-i18next'
|
||||
import useMangoAccount from '../hooks/useMangoAccount'
|
||||
|
||||
export const settlePosPnl = async (
|
||||
perpMarkets: PerpMarket[],
|
||||
perpAccount: PerpAccount,
|
||||
t,
|
||||
mangoAccounts: MangoAccount[] | undefined
|
||||
) => {
|
||||
const mangoAccount = useMangoStore.getState().selectedMangoAccount.current
|
||||
const mangoGroup = useMangoStore.getState().selectedMangoGroup.current
|
||||
const mangoCache = useMangoStore.getState().selectedMangoGroup.cache
|
||||
const wallet = useMangoStore.getState().wallet.current
|
||||
const actions = useMangoStore.getState().actions
|
||||
const mangoClient = useMangoStore.getState().connection.client
|
||||
|
||||
try {
|
||||
await mangoClient.settlePosPnl(
|
||||
mangoGroup,
|
||||
mangoCache,
|
||||
mangoAccount,
|
||||
perpMarkets,
|
||||
mangoGroup.rootBankAccounts[QUOTE_INDEX],
|
||||
wallet,
|
||||
mangoAccounts
|
||||
)
|
||||
actions.reloadMangoAccount()
|
||||
notify({
|
||||
title: t('pnl-success'),
|
||||
description: '',
|
||||
})
|
||||
} catch (e) {
|
||||
console.log('Error settling PNL: ', `${e}`, `${perpAccount}`)
|
||||
notify({
|
||||
title: t('pnl-error'),
|
||||
description: e.message,
|
||||
txid: e.txid,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const settlePnl = async (
|
||||
perpMarket: PerpMarket,
|
||||
perpAccount: PerpAccount,
|
||||
|
|
|
@ -5,7 +5,7 @@ import { useTranslation } from 'next-i18next'
|
|||
import { ExclamationIcon } from '@heroicons/react/outline'
|
||||
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import Button, { LinkButton } from '../components/Button'
|
||||
import { LinkButton } from '../components/Button'
|
||||
import { useViewport } from '../hooks/useViewport'
|
||||
import { breakpoints } from './TradePageGrid'
|
||||
import { ExpandableRow, Table, Td, Th, TrBody, TrHead } from './TableElements'
|
||||
|
@ -16,11 +16,10 @@ import PerpSideBadge from './PerpSideBadge'
|
|||
import PnlText from './PnlText'
|
||||
import { settlePnl } from './MarketPosition'
|
||||
import MobileTableHeader from './mobile/MobileTableHeader'
|
||||
import { RedeemDropdown } from 'components/perp_positions'
|
||||
|
||||
const PositionsTable = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const { reloadMangoAccount } = useMangoStore((s) => s.actions)
|
||||
const [settling, setSettling] = useState(false)
|
||||
const [settleSinglePos, setSettleSinglePos] = useState(null)
|
||||
|
||||
const selectedMarket = useMangoStore((s) => s.selectedMarket.current)
|
||||
|
@ -53,16 +52,6 @@ const PositionsTable = () => {
|
|||
})
|
||||
}
|
||||
|
||||
const handleSettleAll = async () => {
|
||||
setSettling(true)
|
||||
for (const p of unsettledPositions) {
|
||||
await settlePnl(p.perpMarket, p.perpAccount, t, undefined)
|
||||
}
|
||||
|
||||
reloadMangoAccount()
|
||||
setSettling(false)
|
||||
}
|
||||
|
||||
const handleSettlePnl = async (perpMarket, perpAccount, index) => {
|
||||
setSettleSinglePos(index)
|
||||
await settlePnl(perpMarket, perpAccount, t, undefined)
|
||||
|
@ -79,12 +68,7 @@ const PositionsTable = () => {
|
|||
<h3>{t('unsettled-positions')}</h3>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
className="h-8 whitespace-nowrap pt-0 pb-0 pl-3 pr-3 text-xs"
|
||||
onClick={handleSettleAll}
|
||||
>
|
||||
{settling ? <Loading /> : t('redeem-all')}
|
||||
</Button>
|
||||
<RedeemDropdown />
|
||||
</div>
|
||||
<div className="grid grid-flow-row grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
{unsettledPositions.map((p, index) => {
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
import { ChevronDownIcon } from '@heroicons/react/solid'
|
||||
import React, { Fragment, useState } from 'react'
|
||||
import { settlePnl, settlePosPnl } from 'components/MarketPosition'
|
||||
import Button from 'components/Button'
|
||||
import { Transition } from '@headlessui/react'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Loading from 'components/Loading'
|
||||
import useMangoStore from 'stores/useMangoStore'
|
||||
|
||||
const MenuButton = ({ onClick, text }) => {
|
||||
return (
|
||||
<div
|
||||
className="default-transition flex items-center justify-end whitespace-nowrap pb-2.5 text-xs tracking-wider text-th-fgd-1 hover:cursor-pointer hover:text-th-primary"
|
||||
onClick={onClick}
|
||||
>
|
||||
{text}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const RedeemDropdown: React.FC = () => {
|
||||
const { t } = useTranslation('common')
|
||||
const { reloadMangoAccount } = useMangoStore((s) => s.actions)
|
||||
const [settling, setSettling] = useState(false)
|
||||
const [settlingPosPnl, setSettlingPosPnl] = useState(false)
|
||||
const [open, setOpen] = useState(false)
|
||||
const unsettledPositions =
|
||||
useMangoStore.getState().selectedMangoAccount.unsettledPerpPositions
|
||||
const openPositions = useMangoStore(
|
||||
(s) => s.selectedMangoAccount.openPerpPositions
|
||||
)
|
||||
|
||||
const loading = settling || settlingPosPnl
|
||||
|
||||
const handleSettleAll = async () => {
|
||||
setOpen(false)
|
||||
setSettling(true)
|
||||
for (const p of unsettledPositions) {
|
||||
await settlePnl(p.perpMarket, p.perpAccount, t, undefined)
|
||||
}
|
||||
|
||||
reloadMangoAccount()
|
||||
setSettling(false)
|
||||
}
|
||||
|
||||
const handleSettlePosPnl = async () => {
|
||||
setOpen(false)
|
||||
setSettlingPosPnl(true)
|
||||
for (const p of openPositions) {
|
||||
if (p.unsettledPnl > 0) {
|
||||
console.log('settlePosPnl', settlePosPnl)
|
||||
// await settlePosPnl([p.perpMarket], p.perpAccount, t, undefined)
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
setSettlingPosPnl(false)
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative"
|
||||
onMouseOver={() => setOpen(true)}
|
||||
onMouseOut={() => setOpen(false)}
|
||||
>
|
||||
<Button className="flex h-8 w-full items-center justify-center rounded-full bg-th-bkg-button pt-0 pb-0 pl-3 pr-2 text-xs font-bold hover:brightness-[1.1] hover:filter sm:w-auto">
|
||||
{loading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<>
|
||||
{t('redeem-pnl')}
|
||||
<ChevronDownIcon
|
||||
className={`default-transition h-5 w-5 ${
|
||||
open ? 'rotate-180 transform' : 'rotate-360 transform'
|
||||
}`}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
<Transition
|
||||
appear={true}
|
||||
show={open}
|
||||
as={Fragment}
|
||||
enter="transition-all ease-in duration-200"
|
||||
enterFrom="opacity-0 transform scale-75"
|
||||
enterTo="opacity-100 transform scale-100"
|
||||
leave="transition ease-out duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="absolute right-0 rounded-md bg-th-bkg-3 px-4 pt-2.5">
|
||||
<MenuButton onClick={handleSettleAll} text={t('redeem-all')} />
|
||||
<MenuButton
|
||||
onClick={handleSettlePosPnl}
|
||||
text={t('redeem-positive')}
|
||||
/>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './RedeemDropdown'
|
|
@ -299,6 +299,7 @@
|
|||
"redeem-all": "Redeem All",
|
||||
"redeem-failure": "Error redeeming MNGO",
|
||||
"redeem-pnl": "Redeem",
|
||||
"redeem-positive": "Redeem positive",
|
||||
"redeem-success": "Successfully redeemed MNGO",
|
||||
"referrals": "Referrals",
|
||||
"refresh": "Refresh",
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
"resolveJsonModule": true,
|
||||
"jsx": "preserve",
|
||||
"isolatedModules": true,
|
||||
"incremental": true
|
||||
"incremental": true,
|
||||
"baseUrl": "."
|
||||
},
|
||||
"exclude": ["node_modules", ".next", "out", "public/datafeeds"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"]
|
||||
|
|
Loading…
Reference in New Issue