trigger set alerts modal from margininfo
This commit is contained in:
parent
9dc5b1479b
commit
23220e3555
|
@ -0,0 +1,329 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { RadioGroup } from '@headlessui/react'
|
||||
import { InformationCircleIcon, DuplicateIcon } from '@heroicons/react/outline'
|
||||
import PhoneInput from 'react-phone-input-2'
|
||||
import 'react-phone-input-2/lib/plain.css'
|
||||
import Button from './Button'
|
||||
import Input from './Input'
|
||||
import { ElementTitle } from './styles'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import { notify } from '../utils/notifications'
|
||||
import { copyToClipboard } from '../utils'
|
||||
import Modal from './Modal'
|
||||
import Loading from './Loading'
|
||||
import MarginAccountSelect from './MarginAccountSelect'
|
||||
import Tooltip from './Tooltip'
|
||||
|
||||
export default function AlertsModal({ isOpen, onClose }) {
|
||||
const connected = useMangoStore((s) => s.wallet.connected)
|
||||
const marginAccounts = useMangoStore((s) => s.marginAccounts)
|
||||
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
|
||||
const [selectedMarginAccount, setSelectedMarginAccount] = useState<any>(
|
||||
marginAccounts[0]
|
||||
)
|
||||
const [collateralRatioThresh, setCollateralRatioThresh] = useState(113)
|
||||
const [alertProvider, setAlertProvider] = useState('sms')
|
||||
const [phoneNumber, setPhoneNumber] = useState<any>({ phone: null })
|
||||
const [email, setEmail] = useState<string>('')
|
||||
const [tgCode, setTgCode] = useState<string>('')
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [isCopied, setIsCopied] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (isCopied) {
|
||||
const timer = setTimeout(() => {
|
||||
setIsCopied(false)
|
||||
}, 2000)
|
||||
return () => clearTimeout(timer)
|
||||
}
|
||||
}, [isCopied])
|
||||
|
||||
const handleCopyTgCode = (code) => {
|
||||
setIsCopied(true)
|
||||
copyToClipboard(code)
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
setAlertProvider('sms')
|
||||
setPhoneNumber({ phone: null })
|
||||
setEmail('')
|
||||
setTgCode('')
|
||||
setCollateralRatioThresh(113)
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
if (!connected) {
|
||||
notify({
|
||||
message: 'Please connect wallet',
|
||||
type: 'error',
|
||||
})
|
||||
return
|
||||
} else if (!selectedMarginAccount) {
|
||||
notify({
|
||||
message: 'Please select a margin account',
|
||||
type: 'error',
|
||||
})
|
||||
return
|
||||
} else if (alertProvider === 'sms' && !phoneNumber.phone) {
|
||||
notify({
|
||||
message: 'Please provide phone number',
|
||||
type: 'error',
|
||||
})
|
||||
return
|
||||
} else if (alertProvider === 'mail' && !email) {
|
||||
notify({
|
||||
message: 'Please provide e-mail',
|
||||
type: 'error',
|
||||
})
|
||||
return
|
||||
}
|
||||
setSubmitting(true)
|
||||
const fetchUrl = `https://mango-margin-call.herokuapp.com/alerts`
|
||||
const body = {
|
||||
mangoGroupPk: selectedMangoGroup.publicKey.toString(),
|
||||
marginAccountPk: selectedMarginAccount.publicKey.toString(),
|
||||
collateralRatioThresh,
|
||||
alertProvider,
|
||||
phoneNumber,
|
||||
email,
|
||||
}
|
||||
const headers = { 'Content-Type': 'application/json' }
|
||||
fetch(fetchUrl, {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
.then((response: any) => {
|
||||
if (!response.ok) {
|
||||
throw response
|
||||
}
|
||||
return response.json()
|
||||
})
|
||||
.then((json: any) => {
|
||||
if (alertProvider === 'tg') {
|
||||
setTgCode(json.code)
|
||||
} else {
|
||||
notify({
|
||||
message: 'You have succesfully saved your alert',
|
||||
type: 'success',
|
||||
})
|
||||
resetForm()
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (typeof err.text === 'function') {
|
||||
err.text().then((errorMessage: string) => {
|
||||
notify({
|
||||
message: errorMessage,
|
||||
type: 'error',
|
||||
})
|
||||
})
|
||||
} else {
|
||||
notify({
|
||||
message: 'Something went wrong',
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
setSubmitting(false)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose}>
|
||||
{tgCode !== '' ? (
|
||||
<TelegramModal
|
||||
tgCode={tgCode}
|
||||
setTgCode={setTgCode}
|
||||
handleCopyToClipboard={handleCopyTgCode}
|
||||
isCopied={isCopied}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<Modal.Header>
|
||||
<div className={`text-th-fgd-3 flex-shrink invisible w-5`}>X</div>
|
||||
<ElementTitle noMarignBottom>
|
||||
Set Liquidation Alert{' '}
|
||||
<Tooltip
|
||||
content="Your account can be liquidated if your collateral ratio is below 110%.
|
||||
Set an alert above 110% and we'll let you know if it falls
|
||||
below that value."
|
||||
>
|
||||
<div>
|
||||
<InformationCircleIcon
|
||||
className={`h-5 w-5 ml-2 text-th-primary cursor-help`}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</ElementTitle>
|
||||
</Modal.Header>
|
||||
<div className="pb-4">
|
||||
<div className={`text-th-fgd-1 pb-2`}>Margin Account</div>
|
||||
<MarginAccountSelect
|
||||
value={marginAccounts[0]}
|
||||
onChange={setSelectedMarginAccount}
|
||||
/>
|
||||
</div>
|
||||
<div className="pb-4">
|
||||
<div className={`text-th-fgd-1 pb-2`}>
|
||||
Alert me when my collateral ratio is below:
|
||||
</div>
|
||||
<Input
|
||||
type="number"
|
||||
value={collateralRatioThresh}
|
||||
onChange={(e) => setCollateralRatioThresh(e.target.value)}
|
||||
suffix="%"
|
||||
/>
|
||||
</div>
|
||||
<div className="pb-4">
|
||||
<div className={`text-th-fgd-1 pb-2`}>Alert me via:</div>
|
||||
<RadioGroup
|
||||
value={alertProvider}
|
||||
onChange={(val) => setAlertProvider(val)}
|
||||
className="flex border border-th-fgd-4 rounded"
|
||||
>
|
||||
<RadioGroup.Option
|
||||
value="sms"
|
||||
className="flex-1 focus:outline-none"
|
||||
>
|
||||
{({ checked }) => (
|
||||
<button
|
||||
className={`${
|
||||
checked ? 'bg-th-bkg-3 rounded-l' : ''
|
||||
} font-normal text-th-fgd-1 text-center py-1.5 w-full rounded-none border-r border-th-fgd-4 hover:bg-th-bkg-3 focus:outline-none`}
|
||||
>
|
||||
SMS
|
||||
</button>
|
||||
)}
|
||||
</RadioGroup.Option>
|
||||
<RadioGroup.Option
|
||||
value="mail"
|
||||
className="focus:outline-none flex-1"
|
||||
>
|
||||
{({ checked }) => (
|
||||
<button
|
||||
className={`${
|
||||
checked ? 'bg-th-bkg-3' : ''
|
||||
} font-normal text-th-fgd-1 text-center py-1.5 w-full rounded-none border-r border-th-fgd-4 hover:bg-th-bkg-3 focus:outline-none`}
|
||||
>
|
||||
E-mail
|
||||
</button>
|
||||
)}
|
||||
</RadioGroup.Option>
|
||||
<RadioGroup.Option
|
||||
value="tg"
|
||||
className="focus:outline-none flex-1"
|
||||
>
|
||||
{({ checked }) => (
|
||||
<button
|
||||
className={`${
|
||||
checked ? 'bg-th-bkg-3 rounded-r' : ''
|
||||
} font-normal text-th-fgd-1 text-center py-1.5 w-full rounded-none hover:bg-th-bkg-3 focus:outline-none`}
|
||||
>
|
||||
Telegram
|
||||
</button>
|
||||
)}
|
||||
</RadioGroup.Option>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
<div className="pb-4">
|
||||
{alertProvider === 'sms' ? (
|
||||
<>
|
||||
<div className={`text-th-fgd-1 pb-2`}>Mobile Number</div>
|
||||
<PhoneInput
|
||||
containerClass="w-full"
|
||||
inputClass="!w-full !bg-th-bkg-1 !rounded !h-10 !text-th-fgd-1
|
||||
!border !border-th-fgd-4 !border-l hover:!border-th-primary focus:!border-th-primary default-transition"
|
||||
buttonClass="!bg-th-bkg-2 !border !border-th-fgd-4 !pl-1 hover:!bg-th-bkg-3 focus:!bg-th-primary !rounded-l default-transition"
|
||||
dropdownClass="!bg-th-bkg-1 !border-0 !pl-1 !text-th-fgd-1 !rounded !mt-2 !max-h-40 thin-scroll"
|
||||
country="us"
|
||||
inputProps={{
|
||||
name: 'phone',
|
||||
required: true,
|
||||
// autoFocus: true,
|
||||
}}
|
||||
onChange={(val) => setPhoneNumber({ phone: val, code: '' })}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
{alertProvider === 'mail' ? (
|
||||
<>
|
||||
<div className={`text-th-fgd-1 pb-2`}>Email</div>
|
||||
<Input
|
||||
value={email}
|
||||
type="mail"
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<Button
|
||||
disabled={!connected}
|
||||
onClick={onSubmit}
|
||||
className="w-full mb-2"
|
||||
>
|
||||
{connected ? (
|
||||
<div className="flex justify-center">
|
||||
{submitting ? (
|
||||
<Loading />
|
||||
) : alertProvider === 'tg' ? (
|
||||
'Generate Telegram Bot Code'
|
||||
) : (
|
||||
'Save Alert'
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
'Connect Wallet To Save'
|
||||
)}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const TelegramModal = ({
|
||||
tgCode,
|
||||
setTgCode,
|
||||
handleCopyToClipboard,
|
||||
isCopied,
|
||||
}) => {
|
||||
return (
|
||||
<div className="text-th-fgd-1">
|
||||
<ElementTitle>Claim Your Alert in Telegram</ElementTitle>
|
||||
<p className="text-center">This code will expire in 15 minutes</p>
|
||||
|
||||
<div className="text-center relative bg-th-bkg-1 py-2 px-8 mt-4 rounded text-lg">
|
||||
{tgCode}{' '}
|
||||
<div
|
||||
className="absolute top-3.5 cursor-pointer right-4 flex items-center text-xs pl-2 text-th-fgd-1 hover:text-th-primary default-transition"
|
||||
onClick={() => handleCopyToClipboard(tgCode)}
|
||||
>
|
||||
<DuplicateIcon className="w-4 h-4 mr-1" />
|
||||
{isCopied ? 'Copied!' : 'Copy'}
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-th-bkg-3 p-4 rounded-lg mt-2 mb-4">
|
||||
<ol className="ml-6 list-decimal space-y-2">
|
||||
<li>Copy the code above</li>
|
||||
<li>
|
||||
Go to{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://t.me/mango_alerts_bot"
|
||||
>
|
||||
https://t.me/mango_alerts_bot
|
||||
</a>
|
||||
</li>
|
||||
<li>Paste the code and send message</li>
|
||||
</ol>
|
||||
</div>
|
||||
<Button onClick={() => setTgCode('')} className="w-full">
|
||||
Okay, Got It
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -25,7 +25,7 @@ const AlphaModal = ({
|
|||
<ElementTitle noMarignBottom>Mango Markets UI V2</ElementTitle>
|
||||
</div>
|
||||
</Modal.Header>
|
||||
<div className={`pb-4 px-6 text-th-fgd-2 text-center`}>
|
||||
<div className={`text-th-fgd-2 text-center`}>
|
||||
This is an unaudited alpha release of Mango Markets. The software is
|
||||
provided 'AS IS' without warranty of any kind.
|
||||
<div className={`mt-4 flex justify-center`}>
|
||||
|
|
|
@ -124,7 +124,7 @@ const DepositModal = ({ isOpen, onClose }) => {
|
|||
<div className={`text-th-fgd-3 flex-shrink invisible w-5`}>X</div>
|
||||
<ElementTitle noMarignBottom>Deposit Funds</ElementTitle>
|
||||
</Modal.Header>
|
||||
<div className={`pb-6 px-8`}>
|
||||
<>
|
||||
<AccountSelect
|
||||
symbols={symbols}
|
||||
accounts={depositAccounts}
|
||||
|
@ -166,7 +166,7 @@ const DepositModal = ({ isOpen, onClose }) => {
|
|||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ const DepositSrmModal = ({ isOpen, onClose }) => {
|
|||
<div className={`text-th-fgd-3 flex-shrink invisible w-5`}>X</div>
|
||||
<ElementTitle noMarignBottom>Contribute SRM</ElementTitle>
|
||||
</Modal.Header>
|
||||
<div className={`pb-6 px-8`}>
|
||||
<>
|
||||
<AccountSelect
|
||||
accounts={depositAccounts}
|
||||
selectedAccount={selectedAccount}
|
||||
|
@ -124,7 +124,7 @@ const DepositSrmModal = ({ isOpen, onClose }) => {
|
|||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
import { MarginAccount } from '@blockworks-foundation/mango-client'
|
||||
import styled from '@emotion/styled'
|
||||
import { useState } from 'react'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import Select from './Select'
|
||||
import { abbreviateAddress } from '../utils'
|
||||
import useMarketList from '../hooks/useMarketList'
|
||||
|
||||
const StyledMarginAccountSymbols = styled.div`
|
||||
:last-child {
|
||||
border-right-width: 0px;
|
||||
}
|
||||
`
|
||||
|
||||
type MarginAccountSelectProps = {
|
||||
className?: string
|
||||
|
@ -20,6 +29,7 @@ const MarginAccountSelect = ({
|
|||
const [selectedMarginAccount, setSelectedMarginAccount] = useState(
|
||||
value || null
|
||||
)
|
||||
const { symbols } = useMarketList()
|
||||
|
||||
const handleSelectMarginAccount = (value) => {
|
||||
const marginAccount = marginAccounts.find(
|
||||
|
@ -34,7 +44,16 @@ const MarginAccountSelect = ({
|
|||
return (
|
||||
<Select
|
||||
disabled={disabled}
|
||||
value={selectedMarginAccount?.publicKey.toString()}
|
||||
value={
|
||||
<div className="text-left">
|
||||
{Object.keys(symbols).map((symbol, index) =>
|
||||
index !== 0 ? `/${symbol}` : symbol
|
||||
)}
|
||||
<div className="text-xs text-th-fgd-4">
|
||||
{abbreviateAddress(selectedMarginAccount?.publicKey)}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
onChange={handleSelectMarginAccount}
|
||||
placeholder="Select Margin Account"
|
||||
className={className}
|
||||
|
@ -42,7 +61,10 @@ const MarginAccountSelect = ({
|
|||
{marginAccounts.length ? (
|
||||
marginAccounts.map((ma, index) => (
|
||||
<Select.Option key={index} value={ma.publicKey.toString()}>
|
||||
{ma.publicKey.toString()}
|
||||
BTC/ETH/USDT
|
||||
<div className="text-xs text-th-fgd-4">
|
||||
{abbreviateAddress(ma.publicKey)}
|
||||
</div>
|
||||
</Select.Option>
|
||||
))
|
||||
) : (
|
||||
|
|
|
@ -5,6 +5,8 @@ import useTradeHistory from '../hooks/useTradeHistory'
|
|||
import useMangoStore from '../stores/useMangoStore'
|
||||
import FloatingElement from './FloatingElement'
|
||||
import Tooltip from './Tooltip'
|
||||
import Button from './Button'
|
||||
import AlertsModal from './AlertsModal'
|
||||
|
||||
const calculatePNL = (tradeHistory, prices, mangoGroup) => {
|
||||
if (!tradeHistory.length) return '0.00'
|
||||
|
@ -53,6 +55,7 @@ const calculatePNL = (tradeHistory, prices, mangoGroup) => {
|
|||
|
||||
export default function MarginInfo() {
|
||||
const connection = useMangoStore((s) => s.connection.current)
|
||||
const connected = useMangoStore((s) => s.wallet.connected)
|
||||
const selectedMarginAccount = useMangoStore(
|
||||
(s) => s.selectedMarginAccount.current
|
||||
)
|
||||
|
@ -67,6 +70,7 @@ export default function MarginInfo() {
|
|||
}[]
|
||||
| null
|
||||
>(null)
|
||||
const [openAlertModal, setOpenAlertModal] = useState(false)
|
||||
const tradeHistory = useTradeHistory()
|
||||
const tradeHistoryLength = useMemo(() => tradeHistory.length, [tradeHistory])
|
||||
|
||||
|
@ -153,21 +157,36 @@ export default function MarginInfo() {
|
|||
<>
|
||||
{mAccountInfo
|
||||
? mAccountInfo.map((entry, i) => (
|
||||
<div className={`flex justify-between pt-2 pb-2`} key={i}>
|
||||
<Tooltip content={entry.desc}>
|
||||
<div
|
||||
className={`cursor-help font-normal text-th-fgd-4 border-b border-th-fgd-4 border-dashed border-opacity-20 leading-4 default-transition hover:border-th-bkg-2 hover:text-th-fgd-3`}
|
||||
>
|
||||
{entry.label}
|
||||
<>
|
||||
<div className={`flex justify-between pt-2 pb-2`} key={i}>
|
||||
<Tooltip content={entry.desc}>
|
||||
<div
|
||||
className={`cursor-help font-normal text-th-fgd-4 border-b border-th-fgd-4 border-dashed border-opacity-20 leading-4 default-transition hover:border-th-bkg-2 hover:text-th-fgd-3`}
|
||||
>
|
||||
{entry.label}
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className={`text-th-fgd-1`}>
|
||||
{entry.currency + entry.value}
|
||||
{entry.unit}
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className={`text-th-fgd-1`}>
|
||||
{entry.currency + entry.value}
|
||||
{entry.unit}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
))
|
||||
: null}
|
||||
<Button
|
||||
className="mt-4 w-full"
|
||||
disabled={!connected}
|
||||
onClick={() => setOpenAlertModal(true)}
|
||||
>
|
||||
Set Liquidation Alert
|
||||
</Button>
|
||||
{openAlertModal ? (
|
||||
<AlertsModal
|
||||
isOpen={openAlertModal}
|
||||
onClose={() => setOpenAlertModal(false)}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
</FloatingElement>
|
||||
)
|
||||
|
|
|
@ -29,14 +29,14 @@ const Modal = ({ isOpen, onClose, children, hideClose = false }) => {
|
|||
{isOpen ? (
|
||||
<div
|
||||
className="inline-block bg-th-bkg-2
|
||||
rounded-lg text-left shadow-lg transform transition-all
|
||||
rounded-lg text-left px-8 pt-6 pb-8 shadow-lg transform transition-all
|
||||
sm:my-8 align-middle sm:max-w-md w-full"
|
||||
>
|
||||
{!hideClose ? (
|
||||
<div className="w-full flex justify-end p-2 pb-0">
|
||||
<div className="">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className={`text-th-fgd-1 hover:text-th-primary focus:outline-none`}
|
||||
className={`absolute right-2 top-2 text-th-fgd-1 hover:text-th-primary focus:outline-none`}
|
||||
>
|
||||
<XIcon className={`h-5 w-5`} />
|
||||
</button>
|
||||
|
@ -55,7 +55,7 @@ const Modal = ({ isOpen, onClose, children, hideClose = false }) => {
|
|||
|
||||
const Header = ({ children }) => {
|
||||
return (
|
||||
<div className={`flex justify-center bg-th-bkg-2 p-2 pt-0`}>{children}</div>
|
||||
<div className={`flex justify-center bg-th-bkg-2 pb-4`}>{children}</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ const NotificationList = () => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className={`fixed inset-0 flex items-end px-4 py-6 pointer-events-none sm:p-6 text-th-fgd-1`}
|
||||
className={`fixed inset-0 flex items-end px-4 py-6 pointer-events-none sm:p-6 text-th-fgd-1 z-50`}
|
||||
>
|
||||
<div className={`flex flex-col w-full`}>
|
||||
{reversedNotifications.map((n, idx) => (
|
||||
|
|
|
@ -15,12 +15,14 @@ const Select = ({
|
|||
{({ open }) => (
|
||||
<>
|
||||
<Listbox.Button
|
||||
className={`h-full w-full font-normal bg-th-bkg-1 border border-th-fgd-4 rounded focus:outline-none focus:border-th-primary`}
|
||||
className={`h-full w-full font-normal bg-th-bkg-1 border border-th-fgd-4 rounded hover:border-th-primary focus:outline-none focus:border-th-primary`}
|
||||
>
|
||||
<div
|
||||
className={`flex items-center justify-between space-x-4 p-3`}
|
||||
>
|
||||
<span className="">{value ? value : placeholder}</span>
|
||||
<span className="text-th-fgd-1">
|
||||
{value ? value : placeholder}
|
||||
</span>
|
||||
{open ? (
|
||||
<ChevronUpIcon className={`h-5 w-5 mr-1 text-th-primary`} />
|
||||
) : (
|
||||
|
@ -31,7 +33,7 @@ const Select = ({
|
|||
{open ? (
|
||||
<Listbox.Options
|
||||
static
|
||||
className={`z-20 w-full p-1 absolute left-0 mt-1 bg-th-bkg-1 origin-top-left divide-y divide-th-bkg-3 shadow-lg outline-none rounded-md`}
|
||||
className={`text-th-fgd-1 z-20 w-full p-1 absolute left-0 mt-1 bg-th-bkg-1 origin-top-left divide-y divide-th-bkg-3 shadow-lg outline-none rounded-md`}
|
||||
>
|
||||
{children}
|
||||
</Listbox.Options>
|
||||
|
|
|
@ -16,11 +16,11 @@ const Tooltip: FunctionComponent<TooltipProps> = ({
|
|||
<Tippy
|
||||
animation="scale"
|
||||
appendTo={() => document.body}
|
||||
maxWidth="30rem"
|
||||
maxWidth="20rem"
|
||||
interactive
|
||||
content={
|
||||
<div
|
||||
className={`rounded p-3 text-sm bg-th-bkg-3 shadow-md text-th-fgd-2 outline-none focus:outline-none ${className}`}
|
||||
className={`rounded p-3 text-xs bg-th-bkg-3 leading-5 shadow-md text-th-fgd-3 outline-none focus:outline-none ${className}`}
|
||||
>
|
||||
{content}
|
||||
</div>
|
||||
|
|
|
@ -16,6 +16,7 @@ import ThemeSwitch from './ThemeSwitch'
|
|||
import { WalletIcon } from './icons'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import ConnectWalletButton from './ConnectWalletButton'
|
||||
import { copyToClipboard } from '../utils'
|
||||
|
||||
const Code = styled.code`
|
||||
border: 1px solid hsla(0, 0%, 39.2%, 0.2);
|
||||
|
@ -47,12 +48,7 @@ const TopBar = () => {
|
|||
|
||||
const handleWalletMenu = (option) => {
|
||||
if (option === 'Copy address') {
|
||||
const el = document.createElement('textarea')
|
||||
el.value = wallet.publicKey.toString()
|
||||
document.body.appendChild(el)
|
||||
el.select()
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(el)
|
||||
copyToClipboard(wallet.publicKey)
|
||||
setIsCopied(true)
|
||||
} else {
|
||||
wallet.disconnect()
|
||||
|
|
|
@ -29,9 +29,9 @@ export const defaultLayouts = {
|
|||
{ i: 'marginInfo', x: 6, y: 2, w: 2, h: 12 },
|
||||
],
|
||||
lg: [
|
||||
{ i: 'tvChart', x: 0, y: 0, w: 2, h: 24 },
|
||||
{ i: 'balanceInfo', x: 2, y: 0, w: 1, h: 13 },
|
||||
{ i: 'marginInfo', x: 2, y: 1, w: 1, h: 11 },
|
||||
{ i: 'tvChart', x: 0, y: 0, w: 2, h: 25 },
|
||||
{ i: 'balanceInfo', x: 2, y: 0, w: 1, h: 12 },
|
||||
{ i: 'marginInfo', x: 2, y: 1, w: 1, h: 13 },
|
||||
{ i: 'orderbook', x: 0, y: 2, w: 1, h: 17 },
|
||||
{ i: 'tradeForm', x: 1, y: 2, w: 1, h: 17 },
|
||||
{ i: 'marketTrades', x: 2, y: 2, w: 1, h: 17 },
|
||||
|
|
|
@ -183,7 +183,7 @@ const WithdrawModal = ({ isOpen, onClose }) => {
|
|||
<Modal.Header>
|
||||
<ElementTitle noMarignBottom>Withdraw Funds</ElementTitle>
|
||||
</Modal.Header>
|
||||
<div className="pb-6 px-8">
|
||||
<>
|
||||
<AccountSelect
|
||||
hideAddress
|
||||
accounts={withdrawAccounts}
|
||||
|
@ -281,7 +281,7 @@ const WithdrawModal = ({ isOpen, onClose }) => {
|
|||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ const WithdrawModal = ({ isOpen, onClose }) => {
|
|||
<div className={`text-th-fgd-3 flex-shrink invisible w-5`}>X</div>
|
||||
<ElementTitle noMarignBottom>Withdraw SRM</ElementTitle>
|
||||
</Modal.Header>
|
||||
<div className={`pb-6 px-8`}>
|
||||
<>
|
||||
<div className={`text-th-fgd-1 pb-2`}>Token Account</div>
|
||||
<MangoSrmAccountSelector
|
||||
accounts={mangoSrmAccountsForOwner}
|
||||
|
@ -124,7 +124,7 @@ const WithdrawModal = ({ isOpen, onClose }) => {
|
|||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -55,6 +55,14 @@ body {
|
|||
@apply text-sm font-body tracking-wide;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-th-fgd-3 mb-2.5;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-th-primary transition-all duration-300 hover:opacity-70;
|
||||
}
|
||||
|
||||
button {
|
||||
transition: all 0.3s ease;
|
||||
@apply font-semibold rounded-md;
|
||||
|
@ -212,6 +220,14 @@ input[type='number'] {
|
|||
|
||||
/* phone input */
|
||||
|
||||
.react-tel-input .form-control:hover + div {
|
||||
border-right: 1px solid var(--primary) !important;
|
||||
}
|
||||
|
||||
.react-tel-input .form-control:focus + div {
|
||||
border-right: 1px solid var(--primary) !important;
|
||||
}
|
||||
|
||||
.react-tel-input .selected-flag:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
@ -225,11 +241,21 @@ input[type='number'] {
|
|||
}
|
||||
|
||||
.react-tel-input .country-list .country:hover {
|
||||
background-color: var(--bkg-1) !important;
|
||||
background-color: var(--bkg-3) !important;
|
||||
}
|
||||
|
||||
.react-tel-input .country-list .highlight {
|
||||
background-color: var(--bkg-1) !important;
|
||||
background-color: var(--bkg-3) !important;
|
||||
}
|
||||
|
||||
.react-tel-input .country-list {
|
||||
margin: 8px 0 10px -6px !important;
|
||||
}
|
||||
|
||||
.react-tel-input .selected-flag:hover,
|
||||
.react-tel-input .selected-flag:focus,
|
||||
.react-tel-input .selected-flag.open {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
/* orderbook flash */
|
||||
|
|
|
@ -186,3 +186,12 @@ export const capitalize = (s) => {
|
|||
if (typeof s !== 'string') return ''
|
||||
return s.charAt(0).toUpperCase() + s.slice(1)
|
||||
}
|
||||
|
||||
export const copyToClipboard = (copyThis) => {
|
||||
const el = document.createElement('textarea')
|
||||
el.value = copyThis.toString()
|
||||
document.body.appendChild(el)
|
||||
el.select()
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(el)
|
||||
}
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -847,9 +847,9 @@
|
|||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
|
||||
"@blockworks-foundation/mango-client@^0.1.14":
|
||||
version "0.1.15"
|
||||
resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-client/-/mango-client-0.1.15.tgz#9da71650c80012304a61f66ddbdac3b7c7fed390"
|
||||
"@blockworks-foundation/mango-client@^0.1.16":
|
||||
version "0.1.16"
|
||||
resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-client/-/mango-client-0.1.16.tgz#3bf96836bd5d6310e561ed09de8a8f9c0c72c574"
|
||||
dependencies:
|
||||
"@project-serum/serum" "^0.13.20"
|
||||
"@project-serum/sol-wallet-adapter" "^0.1.4"
|
||||
|
@ -2124,9 +2124,9 @@ boolbase@^1.0.0, boolbase@~1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
|
||||
"borsh@https://github.com/defactojob/borsh-js#field-mapper":
|
||||
"borsh@git+https://github.com/defactojob/borsh-js.git#field-mapper":
|
||||
version "0.3.1"
|
||||
resolved "https://github.com/defactojob/borsh-js#33a0d24af281112c0a48efb3fa503f3212443de9"
|
||||
resolved "git+https://github.com/defactojob/borsh-js.git#33a0d24af281112c0a48efb3fa503f3212443de9"
|
||||
dependencies:
|
||||
"@types/bn.js" "^4.11.5"
|
||||
bn.js "^5.0.0"
|
||||
|
|
Loading…
Reference in New Issue