mango-v4-ui/components/modals/MangoAccountsListModal.tsx

256 lines
10 KiB
TypeScript
Raw Normal View History

2023-01-23 15:54:49 -08:00
import { useMemo, useState } from 'react'
2022-12-15 20:04:26 -08:00
import {
CheckIcon,
DocumentDuplicateIcon,
2022-12-15 20:04:26 -08:00
HeartIcon,
PlusCircleIcon,
2023-01-19 19:48:14 -08:00
UserPlusIcon,
2022-12-15 20:04:26 -08:00
} from '@heroicons/react/20/solid'
2022-10-07 04:47:15 -07:00
import {
HealthType,
MangoAccount,
toUiDecimalsForQuote,
} from '@blockworks-foundation/mango-v4'
import mangoStore from '@store/mangoStore'
import { IconButton, LinkButton } from '../shared/Button'
import useLocalStorageState from '../../hooks/useLocalStorageState'
2022-10-07 04:47:15 -07:00
import { LAST_ACCOUNT_KEY } from '../../utils/constants'
import { useTranslation } from 'next-i18next'
import { retryFn } from '../../utils'
import Loading from '../shared/Loading'
import Modal from '@components/shared/Modal'
import CreateAccountForm from '@components/account/CreateAccountForm'
import { EnterRightExitLeft } from '@components/shared/Transitions'
import { useRouter } from 'next/router'
2022-11-18 09:09:39 -08:00
import useMangoAccount from 'hooks/useMangoAccount'
2022-11-20 12:32:38 -08:00
import useMangoGroup from 'hooks/useMangoGroup'
import { notify } from 'utils/notifications'
2022-12-15 20:04:26 -08:00
import { DEFAULT_DELEGATE } from './DelegateModal'
import Tooltip from '@components/shared/Tooltip'
import { abbreviateAddress } from 'utils/formatting'
import { handleCopyAddress } from '@components/account/AccountActions'
import useUnownedAccount from 'hooks/useUnownedAccount'
2022-10-07 04:47:15 -07:00
const MangoAccountsListModal = ({
isOpen,
onClose,
}: {
isOpen: boolean
onClose: () => void
}) => {
const { t } = useTranslation('common')
const { isDelegatedAccount } = useUnownedAccount()
2022-11-20 12:32:38 -08:00
const { mangoAccount, initialLoad: loading } = useMangoAccount()
2022-10-07 04:47:15 -07:00
const mangoAccounts = mangoStore((s) => s.mangoAccounts)
2022-11-20 12:32:38 -08:00
const actions = mangoStore.getState().actions
const { group } = useMangoGroup()
2022-10-07 04:47:15 -07:00
const [showNewAccountForm, setShowNewAccountForm] = useState(false)
const [, setLastAccountViewed] = useLocalStorageState(LAST_ACCOUNT_KEY)
const router = useRouter()
const { asPath } = useRouter()
const [submitting, setSubmitting] = useState('')
2022-10-07 04:47:15 -07:00
2023-01-23 15:54:49 -08:00
const sortedMangoAccounts = useMemo(() => {
if (!group) return mangoAccounts
return [...mangoAccounts].sort((a, b) => {
// keeps the current selected mango account at the top of the list
// if (b.publicKey.toString() === mangoAccount?.publicKey.toString())
// return 1
// if (a.publicKey.toString() === mangoAccount?.publicKey.toString())
// return -1
2023-01-23 15:54:49 -08:00
return b.getEquity(group).toNumber() - a.getEquity(group).toNumber()
})
}, [group, mangoAccounts])
2022-10-07 04:47:15 -07:00
const handleSelectMangoAccount = async (acc: MangoAccount) => {
const set = mangoStore.getState().set
const client = mangoStore.getState().client
if (!group) return
set((s) => {
s.activityFeed.feed = []
s.activityFeed.loading = true
})
setSubmitting(acc.publicKey.toString())
2022-10-07 04:47:15 -07:00
try {
2022-10-25 02:42:51 -07:00
const reloadedMangoAccount = await retryFn(() => acc.reload(client))
2022-10-07 04:47:15 -07:00
set((s) => {
s.mangoAccount.current = reloadedMangoAccount
})
actions.fetchOpenOrders()
2022-10-07 04:47:15 -07:00
setLastAccountViewed(acc.publicKey.toString())
} catch (e) {
console.warn('Error selecting account', e)
notify({
type: 'info',
title: 'Unable to load account. Please try again.',
description: `${e}`,
})
2022-10-07 04:47:15 -07:00
} finally {
onClose()
setSubmitting('')
2022-10-07 04:47:15 -07:00
}
}
const handleClose = () => {
if (asPath !== '/') {
router.push('/')
}
onClose()
}
2022-10-07 04:47:15 -07:00
return (
<Modal isOpen={isOpen} onClose={onClose}>
<div className="inline-block w-full transform overflow-x-hidden">
<div className="flex min-h-[400px] flex-col justify-between">
2022-10-25 02:53:50 -07:00
<div>
<h2 className="text-center">{t('accounts')}</h2>
{loading ? (
<Loading />
) : mangoAccounts.length ? (
2023-01-23 15:54:49 -08:00
<div className="thin-scroll mt-4 max-h-[320px] space-y-2 overflow-y-auto">
{sortedMangoAccounts.map((acc) => {
if (
mangoAccount &&
acc.publicKey.equals(mangoAccount.publicKey)
) {
acc = mangoAccount
}
const accountValue = toUiDecimalsForQuote(
2023-07-21 11:47:53 -07:00
Number(acc.getEquity(group!)),
).toFixed(2)
2022-10-25 02:53:50 -07:00
const maintHealth = acc.getHealthRatioUi(
group!,
2023-07-21 11:47:53 -07:00
HealthType.maint,
2022-10-25 02:53:50 -07:00
)
return (
<div
className="flex h-16 w-full items-center text-th-fgd-1"
key={acc.publicKey.toString()}
>
2022-12-28 18:19:38 -08:00
<button
onClick={() => handleSelectMangoAccount(acc)}
2023-04-19 18:12:45 -07:00
className="flex h-full w-full items-center justify-between rounded-md rounded-r-none border border-th-bkg-4 px-4 text-th-fgd-1 focus-visible:border-th-fgd-4 md:hover:border-th-fgd-4"
2022-12-28 18:19:38 -08:00
>
<div className="flex w-full items-center justify-between">
<div className="flex items-center space-x-2.5">
{submitting === acc.publicKey.toString() ? (
<Loading className="h-4 w-4" />
) : acc.publicKey.toString() ===
mangoAccount?.publicKey.toString() ? (
2022-12-28 18:19:38 -08:00
<div className="flex h-5 w-5 items-center justify-center rounded-full bg-th-success">
<CheckIcon className="h-4 w-4 text-th-bkg-1" />
</div>
) : (
<div className="h-5 w-5 rounded-full bg-th-bkg-4" />
)}
2023-03-04 09:46:49 -08:00
<div className="div flex items-center text-left">
{acc.delegate.toString() !== DEFAULT_DELEGATE ? (
<div className="mr-2">
<Tooltip
content={t('delegate-account-info', {
delegate: isDelegatedAccount
? t('you')
: abbreviateAddress(acc.delegate),
2023-03-04 09:46:49 -08:00
})}
>
<UserPlusIcon className="ml-1.5 h-4 w-4 text-th-fgd-3" />
</Tooltip>
</div>
) : null}
2022-12-28 18:19:38 -08:00
<div className="mb-0.5">
<div className="flex items-center">
{acc.name ? (
<p className="mr-2 text-sm font-bold text-th-fgd-1">
{acc.name}
</p>
) : null}
</div>
<p className="text-xs text-th-fgd-3">
{abbreviateAddress(acc.publicKey)}
</p>
</div>
</div>
</div>
<div className="flex">
<span className="text-sm text-th-fgd-2">
${accountValue}
2022-12-28 18:19:38 -08:00
</span>
<span className="mx-2 text-th-fgd-4">|</span>
<div
className={`flex items-center ${
maintHealth
? maintHealth > 15 && maintHealth < 50
? 'text-th-warning'
: maintHealth >= 50
? 'text-th-success'
: 'text-th-error'
: 'text-th-fgd-4'
}`}
>
<HeartIcon className="mr-1 h-4 w-4 flex-shrink-0" />
<span className="text-sm">{maintHealth}%</span>
</div>
</div>
</div>
</button>
2023-04-05 20:24:29 -07:00
<div className="flex h-full items-center justify-center rounded-md rounded-l-none border border-l-0 border-th-bkg-4">
<Tooltip
className="hidden md:block"
content={t('copy-address')}
2023-03-10 10:01:47 -08:00
delay={100}
>
<IconButton
className="text-th-fgd-3"
onClick={() =>
handleCopyAddress(
2023-10-03 22:05:16 -07:00
acc.publicKey.toString(),
t('copy-address-success', {
pk: abbreviateAddress(acc.publicKey),
2023-07-21 11:47:53 -07:00
}),
)
}
hideBg
2023-01-11 15:17:41 -08:00
size="medium"
>
<DocumentDuplicateIcon className="h-5 w-5" />
</IconButton>
</Tooltip>
</div>
2022-10-25 02:53:50 -07:00
</div>
)
})}
</div>
) : (
<div className="flex h-48 flex-col items-center justify-center">
<span className="mb-1 text-2xl">😎</span>
<p className="text-center text-sm">Create your first account</p>
</div>
)}
</div>
<div className="pt-6">
2022-10-07 04:47:15 -07:00
<LinkButton
className="w-full justify-center"
onClick={() => setShowNewAccountForm(true)}
>
<PlusCircleIcon className="h-5 w-5" />
2022-12-18 17:03:04 -08:00
<span className="ml-2">{t('add-new-account')}</span>
2022-10-07 04:47:15 -07:00
</LinkButton>
</div>
2022-10-07 04:47:15 -07:00
<EnterRightExitLeft
className="absolute bottom-0 left-0 z-20 h-full w-full overflow-hidden bg-th-bkg-1"
show={showNewAccountForm}
>
<CreateAccountForm
customClose={handleClose}
2022-10-07 04:47:15 -07:00
handleBack={() => setShowNewAccountForm(false)}
/>
</EnterRightExitLeft>
</div>
</div>
</Modal>
)
}
export default MangoAccountsListModal