mango-ui-v3/components/ShareModal.tsx

314 lines
9.7 KiB
TypeScript

import {
FunctionComponent,
useEffect,
useMemo,
createRef,
useState,
} from 'react'
import { MarketConfig } from '@blockworks-foundation/mango-client'
import useMangoStore from '../stores/useMangoStore'
import Modal from './Modal'
import { useScreenshot } from '../hooks/useScreenshot'
import * as MonoIcons from './icons'
import { TwitterIcon } from './icons'
import QRCode from 'react-qr-code'
import { useTranslation } from 'next-i18next'
import useMangoAccount from '../hooks/useMangoAccount'
import {
mangoCacheSelector,
mangoGroupConfigSelector,
mangoGroupSelector,
} from '../stores/selectors'
import {
getMarketIndexBySymbol,
ReferrerIdRecord,
} from '@blockworks-foundation/mango-client'
import Button from './Button'
import Switch from './Switch'
import { roundPerpSize } from 'utils'
const calculatePositionPercentage = (position) => {
if (position.basePosition > 0) {
const returnsPercentage =
(position.indexPrice / position.avgEntryPrice - 1) * 100
return returnsPercentage
} else {
const returnsPercentage =
(position.indexPrice / position.avgEntryPrice - 1) * -100
return returnsPercentage
}
}
async function copyToClipboard(image) {
try {
image.toBlob((blob) => {
navigator.clipboard.write([new ClipboardItem({ 'image/png': blob })])
}, 'image/png')
} catch (error) {
console.error(error)
}
}
interface ShareModalProps {
onClose: () => void
isOpen: boolean
position: {
indexPrice: number
avgEntryPrice: number
basePosition: number
marketConfig: MarketConfig
notionalSize: number
}
}
const ShareModal: FunctionComponent<ShareModalProps> = ({
isOpen,
onClose,
position,
}) => {
const { t } = useTranslation(['common', 'share-modal'])
const ref = createRef()
const [copied, setCopied] = useState(false)
const [showButton, setShowButton] = useState(true)
const [image, takeScreenshot] = useScreenshot()
const { mangoAccount } = useMangoAccount()
const mangoCache = useMangoStore(mangoCacheSelector)
const groupConfig = useMangoStore(mangoGroupConfigSelector)
const client = useMangoStore.getState().connection.client
const mangoGroup = useMangoStore(mangoGroupSelector)
const [customRefLinks, setCustomRefLinks] = useState<ReferrerIdRecord[]>([])
const [showSize, setShowSize] = useState(true)
const mngoIndex = getMarketIndexBySymbol(groupConfig, 'MNGO')
const hasRequiredMngo = useMemo(() => {
return mangoGroup && mangoAccount && mangoCache
? mangoAccount
.getUiDeposit(
mangoCache.rootBankCache[mngoIndex],
mangoGroup,
mngoIndex
)
.toNumber() >= 10000
: false
}, [mangoAccount, mangoGroup])
const [showReferral, setShowReferral] = useState(
hasRequiredMngo ? true : false
)
const marketConfig = position.marketConfig
// const maxLeverage = useMemo(() => {
// if (!mangoGroup) return 1
// const ws = getWeights(mangoGroup, marketConfig.marketIndex, 'Init')
// return Math.round((100 * -1) / (ws.perpAssetWeight.toNumber() - 1)) / 100
// }, [mangoGroup, marketConfig])
const positionPercentage = calculatePositionPercentage(position)
const side = position.basePosition > 0 ? 'long' : 'short'
useEffect(() => {
if (image) {
copyToClipboard(image)
setCopied(true)
setShowButton(true)
}
}, [image])
useEffect(() => {
// if the button is hidden we are taking a screenshot
if (!showButton) {
takeScreenshot(ref.current as HTMLElement)
}
}, [showButton])
const handleCopyToClipboard = () => {
setShowButton(false)
}
useEffect(() => {
const fetchCustomReferralLinks = async (mangoAccount) => {
const referrerIds = await client.getReferrerIdsForMangoAccount(
mangoAccount
)
setCustomRefLinks(referrerIds)
}
if (mangoAccount && customRefLinks?.length === 0) {
fetchCustomReferralLinks(mangoAccount)
}
}, [mangoAccount])
const isProfit = positionPercentage > 0
const iconName = `${marketConfig.baseSymbol.slice(
0,
1
)}${marketConfig.baseSymbol.slice(1, 4).toLowerCase()}MonoIcon`
const SymbolIcon = MonoIcons[iconName]
return (
<Modal
isOpen={isOpen}
onClose={onClose}
className={`-mt-40 ${
side === 'long'
? isProfit
? 'bg-long-profit'
: 'bg-long-loss'
: isProfit
? 'bg-short-profit'
: 'bg-short-loss'
} h-[337.5px] w-[600px] bg-contain leading-[0.5] sm:max-w-7xl`}
noPadding
hideClose
ref={ref}
>
<div
id="share-image"
className="relative z-20 flex h-full flex-col items-center justify-center space-y-4 drop-shadow-lg"
>
{hasRequiredMngo && showReferral ? (
<div className="absolute right-4 top-4">
<QRCode
size={64}
value={
customRefLinks.length > 0
? `https://trade.mango.markets?ref=${customRefLinks[0].referrerId}`
: `https://trade.mango.markets?ref=${mangoAccount?.publicKey.toString()}`
}
/>
</div>
) : null}
<div className="flex items-center text-lg text-th-fgd-3">
<SymbolIcon className="mr-2 h-6 w-auto" />
<span
className={`mr-2 ${
!showButton ? 'inline-block h-full align-top leading-none' : ''
}`}
>
{position.marketConfig.name}
</span>
<span
className={`h-full rounded border px-1 ${
position.basePosition > 0
? 'border-th-green text-th-green'
: 'border-th-red text-th-red'
}`}
>
<span
className={`${
!showButton ? 'inline-block h-full align-top leading-none' : ''
}`}
>
{t(side).toLocaleUpperCase()}
</span>
</span>
</div>
<div
className={`text-center text-6xl font-bold ${
isProfit ? 'text-th-green' : 'text-th-red'
}`}
>
{positionPercentage > 0 ? '+' : null}
{positionPercentage.toFixed(2)}%
</div>
<div className="w-1/2 space-y-1 pt-2 text-base text-th-fgd-1">
{showSize ? (
<div className="flex items-center justify-between">
<span className="text-th-fgd-2">{t('size')}</span>
<span className="font-bold">
{roundPerpSize(
position.basePosition,
position.marketConfig.baseSymbol
)}
</span>
</div>
) : null}
<div className="flex items-center justify-between">
<span className="text-th-fgd-2">{t('average-entry')}</span>
<span className="font-bold">
$
{position.avgEntryPrice.toLocaleString(undefined, {
maximumFractionDigits: 2,
minimumFractionDigits: 2,
})}
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-th-fgd-2">{t('share-modal:mark-price')}</span>
<span className="font-bold">
$
{position.indexPrice.toLocaleString(undefined, {
maximumFractionDigits: 2,
minimumFractionDigits: 2,
})}
</span>
</div>
{/* <div className="flex items-center justify-between">
<span className="text-th-fgd-2">
{t('share-modal:max-leverage')}
</span>
<span className="font-bold">{maxLeverage}x</span>
</div> */}
</div>
</div>
<div className="absolute left-1/2 mt-3 w-[600px] -translate-x-1/2 transform rounded-md bg-th-bkg-2 p-4">
<div className="flex flex-col items-center">
{!copied ? (
<div className="flex space-x-4 pb-4">
<div className="flex items-center">
<label className="mr-1.5 text-th-fgd-2">
{t('share-modal:show-size')}
</label>
<Switch
checked={showSize}
onChange={(checked) => setShowSize(checked)}
/>
</div>
{hasRequiredMngo ? (
<div className="flex items-center">
<label className="mr-1.5 text-th-fgd-2">
{t('share-modal:show-referral-qr')}
</label>
<Switch
checked={showReferral}
onChange={(checked) => setShowReferral(checked)}
/>
</div>
) : null}
</div>
) : null}
{copied ? (
<a
className="block flex items-center justify-center rounded-full bg-th-bkg-button px-6 py-2 text-center font-bold text-th-fgd-1 hover:cursor-pointer hover:text-th-fgd-1 hover:brightness-[1.1]"
href={`https://twitter.com/intent/tweet?text=I'm ${side.toUpperCase()} %24${
position.marketConfig.baseSymbol
} perp on %40mangomarkets%0A[PASTE IMAGE HERE]`}
target="_blank"
rel="noreferrer"
>
<TwitterIcon className="mr-1.5 h-4 w-4" />
<div>{t('share-modal:tweet-position')}</div>
</a>
) : (
<div>
<Button onClick={handleCopyToClipboard}>
<div className="flex items-center">
<TwitterIcon className="mr-1.5 h-4 w-4" />
{t('share-modal:copy-and-share')}
</div>
</Button>
</div>
)}
</div>
</div>
</Modal>
)
}
export default ShareModal