Merge pull request #301 from blockworks-foundation/redeem-buttons
redeem positive button logic
This commit is contained in:
commit
67804e7bb0
|
@ -1,124 +0,0 @@
|
||||||
import { ChevronDownIcon } from '@heroicons/react/solid'
|
|
||||||
import React, { Fragment, useState } from 'react'
|
|
||||||
import {settleAllPnl, 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'
|
|
||||||
import { useWallet } from '@solana/wallet-adapter-react'
|
|
||||||
|
|
||||||
const MenuButton: React.FC<{
|
|
||||||
onClick: () => void
|
|
||||||
text: string
|
|
||||||
disabled?: boolean
|
|
||||||
}> = ({ onClick, text, disabled }) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={`default-transition flex items-center justify-end whitespace-nowrap pb-2.5 text-xs tracking-wider hover:cursor-pointer hover:text-th-primary ${
|
|
||||||
disabled ? 'pointer-events-none text-th-fgd-4' : 'text-th-fgd-1'
|
|
||||||
}`}
|
|
||||||
onClick={disabled ? () => null : onClick}
|
|
||||||
>
|
|
||||||
{text}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const RedeemDropdown: React.FC = () => {
|
|
||||||
const { t } = useTranslation('common')
|
|
||||||
const [settling, setSettling] = useState(false)
|
|
||||||
const { wallet } = useWallet()
|
|
||||||
const [settlingPosPnl, setSettlingPosPnl] = useState(false)
|
|
||||||
const [open, setOpen] = useState(false)
|
|
||||||
const unsettledPositions =
|
|
||||||
useMangoStore.getState().selectedMangoAccount.unsettledPerpPositions
|
|
||||||
const unsettledPositivePositions = useMangoStore
|
|
||||||
.getState()
|
|
||||||
.selectedMangoAccount.unsettledPerpPositions?.filter(
|
|
||||||
(p) => p.unsettledPnl > 0
|
|
||||||
)
|
|
||||||
|
|
||||||
const loading = settling || settlingPosPnl
|
|
||||||
|
|
||||||
const handleSettleAll = async () => {
|
|
||||||
if (!wallet) return
|
|
||||||
setOpen(false)
|
|
||||||
setSettling(true)
|
|
||||||
try {
|
|
||||||
await settleAllPnl(unsettledPositions.map((p) => p.perpMarket), t, undefined, wallet)
|
|
||||||
} finally {
|
|
||||||
setSettling(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSettlePosPnl = async () => {
|
|
||||||
if (!wallet) return
|
|
||||||
setOpen(false)
|
|
||||||
setSettlingPosPnl(true)
|
|
||||||
try {
|
|
||||||
await settlePosPnl(unsettledPositivePositions.map((p) => p.perpMarket), t, undefined, wallet)
|
|
||||||
} finally {
|
|
||||||
setSettlingPosPnl(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const buttons = [
|
|
||||||
{ onClick: handleSettleAll, disabled: false, text: t('redeem-all') },
|
|
||||||
{
|
|
||||||
onClick: handleSettlePosPnl,
|
|
||||||
disabled: !unsettledPositivePositions?.length,
|
|
||||||
text: t('redeem-positive'),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
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"
|
|
||||||
disabled={!unsettledPositions?.length}
|
|
||||||
>
|
|
||||||
{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">
|
|
||||||
{buttons.map((b) => {
|
|
||||||
return (
|
|
||||||
<MenuButton
|
|
||||||
key={b.text}
|
|
||||||
onClick={b.onClick}
|
|
||||||
text={b.text}
|
|
||||||
disabled={b.disabled}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</Transition>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './RedeemDropdown'
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useCallback, useEffect, useState } from 'react'
|
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useTranslation } from 'next-i18next'
|
import { useTranslation } from 'next-i18next'
|
||||||
|
@ -20,7 +20,7 @@ import ShareModal from './ShareModal'
|
||||||
import { TwitterIcon } from './icons'
|
import { TwitterIcon } from './icons'
|
||||||
import { marketSelector } from '../stores/selectors'
|
import { marketSelector } from '../stores/selectors'
|
||||||
import { useWallet } from '@solana/wallet-adapter-react'
|
import { useWallet } from '@solana/wallet-adapter-react'
|
||||||
import { RedeemDropdown } from 'components/PerpPositions'
|
import RedeemButtons from './RedeemButtons'
|
||||||
|
|
||||||
const PositionsTable: React.FC = () => {
|
const PositionsTable: React.FC = () => {
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
|
@ -85,17 +85,35 @@ const PositionsTable: React.FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unsettledSum = useMemo(() => {
|
||||||
|
if (unsettledPositions.length > 1) {
|
||||||
|
return unsettledPositions.reduce((a, c) => a + c.unsettledPnl, 0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}, [unsettledPositions])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col md:pb-2">
|
<div className="flex flex-col md:pb-2">
|
||||||
{unsettledPositions.length > 0 ? (
|
{unsettledPositions.length > 0 ? (
|
||||||
<div className="mb-6 rounded-lg border border-th-bkg-4 p-4 sm:p-6">
|
<div className="mb-6 rounded-lg border border-th-bkg-4 p-4 sm:p-6">
|
||||||
<div className="flex items-center justify-between pb-4">
|
<div className="flex items-start justify-between pb-4">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<ExclamationIcon className="mr-1.5 mt-0.5 h-5 w-5 flex-shrink-0 text-th-primary" />
|
<ExclamationIcon className="mr-2 h-6 w-6 flex-shrink-0 text-th-primary" />
|
||||||
<h3>{t('unsettled-positions')}</h3>
|
<h3>
|
||||||
|
{t('unsettled-positions')}{' '}
|
||||||
|
{unsettledSum ? (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
unsettledSum >= 0 ? 'text-th-green' : 'text-th-red'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{formatUsdValue(unsettledSum)}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<RedeemDropdown />
|
<RedeemButtons />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-flow-row grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
|
<div className="grid grid-flow-row grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||||
{unsettledPositions.map((p, index) => {
|
{unsettledPositions.map((p, index) => {
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import React, { useMemo, useState } from 'react'
|
||||||
|
import { settleAllPnl, settlePosPnl } from 'components/MarketPosition'
|
||||||
|
import Button from 'components/Button'
|
||||||
|
import { useTranslation } from 'next-i18next'
|
||||||
|
import Loading from 'components/Loading'
|
||||||
|
import useMangoStore from 'stores/useMangoStore'
|
||||||
|
import { useWallet } from '@solana/wallet-adapter-react'
|
||||||
|
|
||||||
|
const RedeemButtons: React.FC = () => {
|
||||||
|
const { t } = useTranslation('common')
|
||||||
|
const [settling, setSettling] = useState(false)
|
||||||
|
const { wallet } = useWallet()
|
||||||
|
const [settlingPosPnl, setSettlingPosPnl] = useState(false)
|
||||||
|
const unsettledPositions =
|
||||||
|
useMangoStore.getState().selectedMangoAccount.unsettledPerpPositions
|
||||||
|
const unsettledPositivePositions = useMangoStore
|
||||||
|
.getState()
|
||||||
|
.selectedMangoAccount.unsettledPerpPositions?.filter(
|
||||||
|
(p) => p.unsettledPnl > 0
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleSettleAll = async () => {
|
||||||
|
if (!wallet) return
|
||||||
|
setSettling(true)
|
||||||
|
try {
|
||||||
|
await settleAllPnl(
|
||||||
|
unsettledPositions.map((p) => p.perpMarket),
|
||||||
|
t,
|
||||||
|
undefined,
|
||||||
|
wallet
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
setSettling(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSettlePosPnl = async () => {
|
||||||
|
if (!wallet) return
|
||||||
|
setSettlingPosPnl(true)
|
||||||
|
try {
|
||||||
|
await settlePosPnl(
|
||||||
|
unsettledPositivePositions.map((p) => p.perpMarket),
|
||||||
|
t,
|
||||||
|
undefined,
|
||||||
|
wallet
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
setSettlingPosPnl(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const showPosOnlyButton = useMemo(() => {
|
||||||
|
return (
|
||||||
|
unsettledPositions.find((pos) => pos.unsettledPnl > 0) &&
|
||||||
|
unsettledPositions.find((pos) => pos.unsettledPnl < 0)
|
||||||
|
)
|
||||||
|
}, [unsettledPositions])
|
||||||
|
|
||||||
|
return unsettledPositions?.length ? (
|
||||||
|
<div className="flex space-x-3">
|
||||||
|
{showPosOnlyButton ? (
|
||||||
|
<Button
|
||||||
|
className="flex h-7 items-center justify-center pt-0 pb-0 pl-3 pr-3 text-xs"
|
||||||
|
onClick={handleSettlePosPnl}
|
||||||
|
>
|
||||||
|
{settlingPosPnl ? <Loading /> : t('redeem-positive')}
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
<Button
|
||||||
|
className="flex h-7 items-center justify-center pt-0 pb-0 pl-3 pr-3 text-xs"
|
||||||
|
onClick={handleSettleAll}
|
||||||
|
>
|
||||||
|
{settling ? <Loading /> : t('redeem-all')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RedeemButtons
|
|
@ -328,7 +328,7 @@
|
||||||
"redeem-all": "Redeem All",
|
"redeem-all": "Redeem All",
|
||||||
"redeem-failure": "Error redeeming MNGO",
|
"redeem-failure": "Error redeeming MNGO",
|
||||||
"redeem-pnl": "Redeem",
|
"redeem-pnl": "Redeem",
|
||||||
"redeem-positive": "Redeem positive",
|
"redeem-positive": "Redeem Positive",
|
||||||
"redeem-success": "Successfully redeemed MNGO",
|
"redeem-success": "Successfully redeemed MNGO",
|
||||||
"referrals": "Referrals",
|
"referrals": "Referrals",
|
||||||
"refresh": "Refresh",
|
"refresh": "Refresh",
|
||||||
|
|
|
@ -328,7 +328,7 @@
|
||||||
"redeem-all": "Redeem All",
|
"redeem-all": "Redeem All",
|
||||||
"redeem-failure": "Error al canjear MNGO",
|
"redeem-failure": "Error al canjear MNGO",
|
||||||
"redeem-pnl": "Resolver",
|
"redeem-pnl": "Resolver",
|
||||||
"redeem-positive": "Redeem positive",
|
"redeem-positive": "Redeem Positive",
|
||||||
"redeem-success": "MNGO canjeado con éxito",
|
"redeem-success": "MNGO canjeado con éxito",
|
||||||
"referrals": "Referencias",
|
"referrals": "Referencias",
|
||||||
"refresh": "Actualizar",
|
"refresh": "Actualizar",
|
||||||
|
|
Loading…
Reference in New Issue