mango-ui-v3/components/AccountsModal.tsx

223 lines
7.8 KiB
TypeScript

import React, { FunctionComponent, useEffect, useState } from 'react'
import { RadioGroup } from '@headlessui/react'
import { CheckCircleIcon } from '@heroicons/react/solid'
import { PlusCircleIcon, UsersIcon } from '@heroicons/react/outline'
import useMangoStore from '../stores/useMangoStore'
import { MangoAccount, MangoGroup } from '@blockworks-foundation/mango-client'
import { abbreviateAddress, formatUsdValue } from '../utils'
import useLocalStorageState from '../hooks/useLocalStorageState'
import Modal from './Modal'
import { ElementTitle } from './styles'
import Button, { LinkButton } from './Button'
import NewAccount from './NewAccount'
import { useTranslation } from 'next-i18next'
import Tooltip from './Tooltip'
import { useWallet } from '@solana/wallet-adapter-react'
export const LAST_ACCOUNT_KEY = 'lastAccountViewed-3.0'
interface AccountsModalProps {
onClose: () => void
isOpen: boolean
}
const AccountsModal: FunctionComponent<AccountsModalProps> = ({
isOpen,
onClose,
}) => {
const { t } = useTranslation('common')
const { publicKey } = useWallet()
const [showNewAccountForm, setShowNewAccountForm] = useState(false)
const [newAccPublicKey, setNewAccPublicKey] = useState(null)
const mangoAccounts = useMangoStore((s) => s.mangoAccounts)
const selectedMangoAccount = useMangoStore(
(s) => s.selectedMangoAccount.current
)
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
const setMangoStore = useMangoStore((s) => s.set)
const actions = useMangoStore((s) => s.actions)
const [, setLastAccountViewed] = useLocalStorageState(LAST_ACCOUNT_KEY)
const handleMangoAccountChange = (mangoAccount: MangoAccount) => {
setLastAccountViewed(mangoAccount.publicKey.toString())
setMangoStore((state) => {
state.selectedMangoAccount.current = mangoAccount
})
actions.fetchTradeHistory()
onClose()
}
useEffect(() => {
if (newAccPublicKey) {
setMangoStore((state) => {
state.selectedMangoAccount.current =
mangoAccounts.find(
(ma) => ma.publicKey.toString() === newAccPublicKey
) ?? null
})
}
}, [mangoAccounts, newAccPublicKey])
const handleNewAccountCreation = (newAccPublicKey) => {
if (newAccPublicKey) {
setNewAccPublicKey(newAccPublicKey)
}
setShowNewAccountForm(false)
}
const handleShowNewAccountForm = () => {
setNewAccPublicKey(null)
setShowNewAccountForm(true)
}
return (
<Modal isOpen={isOpen} onClose={onClose}>
{mangoAccounts.length > 0 ? (
!showNewAccountForm ? (
<>
<Modal.Header>
<ElementTitle noMarginBottom>{t('mango-accounts')}</ElementTitle>
</Modal.Header>
<div className="flex items-center justify-between pb-3 text-th-fgd-1">
<div className="font-semibold">
{mangoAccounts.length > 1
? t('select-account')
: t('your-account')}
</div>
<Button
className="flex h-8 items-center justify-center pt-0 pb-0 pl-3 pr-3 text-xs"
onClick={() => handleShowNewAccountForm()}
>
<div className="flex items-center">
<PlusCircleIcon className="mr-1.5 h-5 w-5" />
{t('new-account')}
</div>
</Button>
</div>
<RadioGroup
value={selectedMangoAccount}
onChange={(acc) => {
if (acc) {
handleMangoAccountChange(acc)
}
}}
>
<RadioGroup.Label className="sr-only">
{t('select-account')}
</RadioGroup.Label>
<div className="space-y-2">
{mangoAccounts.map((account) => (
<RadioGroup.Option
key={account.publicKey.toString()}
value={account}
className={({ checked }) =>
`${
checked
? 'bg-th-bkg-3 ring-1 ring-inset ring-th-green'
: 'bg-th-bkg-1'
}
default-transition relative flex w-full cursor-pointer rounded-md px-3 py-3 hover:bg-th-bkg-3 focus:outline-none`
}
>
{({ checked }) => (
<>
<div className="flex w-full items-center justify-between">
<div className="flex items-center">
<div className="text-sm">
<RadioGroup.Label className="flex cursor-pointer items-center text-th-fgd-1">
<div>
<div className="flex items-center pb-0.5">
{account?.name ||
abbreviateAddress(account.publicKey)}
{publicKey &&
!account?.owner.equals(publicKey) ? (
<Tooltip
content={t(
'delegate:delegated-account'
)}
>
<UsersIcon className="ml-1.5 h-3 w-3" />
</Tooltip>
) : (
''
)}
</div>
{mangoGroup && (
<div className="text-xs text-th-fgd-3">
<AccountInfo
mangoGroup={mangoGroup}
mangoAccount={account}
/>
</div>
)}
</div>
</RadioGroup.Label>
</div>
</div>
{checked && (
<div className="flex-shrink-0 text-th-green">
<CheckCircleIcon className="h-5 w-5" />
</div>
)}
</div>
</>
)}
</RadioGroup.Option>
))}
</div>
</RadioGroup>
</>
) : (
<>
<NewAccount onAccountCreation={handleNewAccountCreation} />
<LinkButton
className="mt-4 flex w-full justify-center"
onClick={() => setShowNewAccountForm(false)}
>
{t('cancel')}
</LinkButton>
</>
)
) : (
<NewAccount onAccountCreation={handleNewAccountCreation} />
)}
</Modal>
)
}
const AccountInfo = ({
mangoGroup,
mangoAccount,
}: {
mangoGroup: MangoGroup
mangoAccount: MangoAccount
}) => {
const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache)
if (!mangoCache) {
return null
}
const accountEquity = mangoAccount.computeValue(mangoGroup, mangoCache)
const leverage = mangoAccount.getLeverage(mangoGroup, mangoCache).toFixed(2)
return (
<div className="text-xs text-th-fgd-3">
{formatUsdValue(accountEquity.toNumber())}
<span className="px-1.5 text-th-fgd-4">|</span>
<span
className={
parseFloat(leverage) > 4
? 'text-th-red'
: parseFloat(leverage) > 2
? 'text-th-orange'
: 'text-th-green'
}
>
{leverage}x
</span>
</div>
)
}
export default React.memo(AccountsModal)