Merge pull request #66 from blockworks-foundation/mobile-fixes

fix: mobile styling to accomodate new markets
This commit is contained in:
saml33 2021-11-04 08:17:08 +11:00 committed by GitHub
commit 61a6a65830
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 480 additions and 683 deletions

View File

@ -127,7 +127,7 @@ const BalancesTable = ({ showZeroBalances = false }) => {
const unsettledBalances = balances.filter((bal) => bal.unsettled > 0)
return (
<div className={`flex flex-col pb-2 sm:pb-4 sm:pt-4`}>
<div className={`flex flex-col pb-2 sm:pb-4`}>
{unsettledBalances.length > 0 ? (
<div className="border border-th-bkg-4 rounded-lg mb-6 p-4 sm:p-6">
<div className="flex items-center justify-between pb-4">
@ -167,7 +167,7 @@ const BalancesTable = ({ showZeroBalances = false }) => {
})}
</div>
) : null}
<div className={`-my-2 overflow-x-auto`}>
<div className={`md:-my-2 md:overflow-x-auto`}>
<div className={`align-middle inline-block min-w-full`}>
{items.length > 0 ? (
!isMobile ? (
@ -421,19 +421,13 @@ const BalancesTable = ({ showZeroBalances = false }) => {
) : (
<>
<MobileTableHeader
headerTemplate={
<>
<div className="col-span-7">{t('asset')}</div>
<div className="col-span-4 text-right">
{t('net-balance')}
</div>
</>
}
colOneHeader={t('asset')}
colTwoHeader={t('net-balance')}
/>
{items.map((balance, index) => (
<ExpandableRow
buttonTemplate={
<div className="col-span-11 flex items-center justify-between text-fgd-1">
<div className="flex items-center justify-between text-fgd-1 w-full">
<div className="flex items-center text-fgd-1">
<img
alt=""
@ -445,7 +439,7 @@ const BalancesTable = ({ showZeroBalances = false }) => {
{balance.symbol}
</div>
<div className="mr-1.5 text-fgd-1 text-right">
<div className="text-fgd-1 text-right">
{balance.net.toFixed()}
</div>
</div>
@ -454,37 +448,38 @@ const BalancesTable = ({ showZeroBalances = false }) => {
index={index}
panelTemplate={
<>
<div className="col-span-1 text-left">
<div className="grid grid-cols-2 grid-flow-row gap-4 pb-4">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('deposits')}
</div>
{balance.deposits.toFixed()}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('borrows')}
</div>
{balance.borrows.toFixed()}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('in-orders')}
</div>
{balance.orders.toFixed()}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('unsettled')}
</div>
{balance.unsettled.toFixed()}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('value')}
</div>
{formatUsdValue(balance.value.toNumber())}
</div>
<div className="col-span-1 text-left text-th-fgd-4">
<div className="text-left text-th-fgd-4">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('rates')}
</div>
@ -496,20 +491,25 @@ const BalancesTable = ({ showZeroBalances = false }) => {
{balance.borrowRate.toFixed(2)}%
</span>
</div>
</div>
<div className="flex space-x-4">
<Button
className="col-span-1 text-xs pt-0 pb-0 h-8 pl-3 pr-3"
onClick={() => handleOpenDepositModal(balance.symbol)}
className="text-xs pt-0 pb-0 h-8 pl-3 pr-3 w-1/2"
onClick={() =>
handleOpenDepositModal(balance.symbol)
}
>
{t('deposit')}
</Button>
<Button
className="col-span-1 text-xs pt-0 pb-0 h-8 pl-3 pr-3"
className="text-xs pt-0 pb-0 h-8 pl-3 pr-3 w-1/2"
onClick={() =>
handleOpenWithdrawModal(balance.symbol)
}
>
{t('withdraw')}
</Button>
</div>
</>
}
/>

View File

@ -9,7 +9,6 @@ import { breakpoints } from './TradePageGrid'
import { Table, Td, Th, TrBody, TrHead } from './TableElements'
import { formatUsdValue } from '../utils'
import Loading from './Loading'
import usePerpPositions from '../hooks/usePerpPositions'
import MarketCloseModal from './MarketCloseModal'
import { ExpandableRow } from './TableElements'
@ -17,6 +16,7 @@ import PerpSideBadge from './PerpSideBadge'
import PnlText from './PnlText'
import { settlePnl } from './MarketPosition'
import { useTranslation } from 'next-i18next'
import MobileTableHeader from './mobile/MobileTableHeader'
const PositionsTable = () => {
const { t } = useTranslation('common')
@ -211,7 +211,12 @@ const PositionsTable = () => {
</tbody>
</Table>
) : (
openPositions.map(
<>
<MobileTableHeader
colOneHeader={t('market')}
colTwoHeader={t('unrealized-pnl')}
/>
{openPositions.map(
(
{
marketConfig,
@ -227,7 +232,7 @@ const PositionsTable = () => {
<ExpandableRow
buttonTemplate={
<>
<div className="col-span-11 flex items-center justify-between text-fgd-1">
<div className="flex items-center justify-between text-fgd-1 w-full">
<div className="flex items-center">
<img
alt=""
@ -256,14 +261,14 @@ const PositionsTable = () => {
</div>
</div>
</div>
<PnlText className="mr-1.5" pnl={unrealizedPnl} />
<PnlText pnl={unrealizedPnl} />
</div>
</>
}
key={`${index}`}
index={index}
panelTemplate={
<>
<div className="grid grid-cols-2 grid-flow-row gap-4">
<div className="col-span-1 text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('average-entry')}
@ -286,18 +291,13 @@ const PositionsTable = () => {
? formatUsdValue(breakEvenPrice)
: '--'}
</div>
<div className="col-span-1 text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('unrealized-pnl')}
</div>
<PnlText pnl={unrealizedPnl} />
</div>
</>
}
/>
)
}
)
)}
</>
)
) : (
<div

View File

@ -87,7 +87,7 @@ export default function RecentMarketTrades() {
) : (
<ExpandableRow
buttonTemplate={
<div className="col-span-11 text-left">
<div className="flex justify-between text-left w-full">
<div className="mb-0.5 text-fgd-1">{t('recent-trades')}</div>
</div>
}

View File

@ -55,7 +55,7 @@ export const ExpandableRow = ({
<Disclosure.Button
className={`${
index % 2 === 0 ? `bg-th-bkg-3` : `bg-th-bkg-4`
} default-transition font-normal p-4 text-th-fgd-1 w-full hover:filter hover:brightness-90 focus:outline-none ${
} default-transition flex items-center justify-between font-normal p-4 text-th-fgd-1 w-full hover:filter hover:brightness-90 focus:outline-none ${
rounded
? open
? 'rounded-b-none'
@ -63,16 +63,14 @@ export const ExpandableRow = ({
: 'rounded-none'
}`}
>
<div className="grid grid-cols-12 grid-rows-1">
{buttonTemplate}
<div className="flex items-center justify-end">
<div className="flex items-center justify-end pl-5">
<ChevronDownIcon
className={`${
open ? 'transform rotate-180' : 'transform rotate-360'
} default-transition h-5 flex-shrink-0 w-5 text-th-primary`}
/>
</div>
</div>
</Disclosure.Button>
<Disclosure.Panel
className={`${
@ -87,9 +85,7 @@ export const ExpandableRow = ({
: 'rounded-none'
}`}
>
<div className="grid grid-cols-2 grid-rows-1 gap-4 py-4">
{panelTemplate}
</div>
<div className="py-4">{panelTemplate}</div>
</Disclosure.Panel>
</>
)}
@ -106,12 +102,10 @@ export const Row = ({ children, index }: RowProps) => {
return (
<div
className={`${
index % 2 === 0
? `bg-[rgba(255,255,255,0.03)]`
: `bg-[rgba(255,255,255,0.07)]`
index % 2 === 0 ? `bg-th-bkg-3` : `bg-th-bkg-4`
} default-transition font-normal p-4 rounded-none text-th-fgd-1 w-full`}
>
<div className="grid grid-cols-12 grid-rows-1 gap-4">{children}</div>
{children}
</div>
)
}

View File

@ -17,7 +17,6 @@ import Settings from './Settings'
const TopBar = () => {
const { t } = useTranslation('common')
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
const connected = useMangoStore((s) => s.wallet.connected)
const [showAccountsModal, setShowAccountsModal] = useState(false)
const [defaultMarket] = useLocalStorageState(
DEFAULT_MARKET_KEY,
@ -31,7 +30,7 @@ const TopBar = () => {
return (
<>
<nav className={`bg-th-bkg-2 border-b border-th-bkg-2`}>
<div className={`pl-2 md:px-4 lg:px-10`}>
<div className={`px-4 lg:px-10`}>
<div className={`flex justify-between h-14`}>
<div className={`flex`}>
<Link href={defaultMarket.path}>
@ -46,7 +45,7 @@ const TopBar = () => {
</div>
</Link>
<div
className={`hidden md:flex md:items-center md:space-x-6 md:ml-4`}
className={`hidden md:flex md:items-center md:space-x-4 lg:space-x-6 md:ml-4`}
>
<MenuItem href={defaultMarket.path}>{t('trade')}</MenuItem>
<MenuItem href="/account">{t('account')}</MenuItem>
@ -112,7 +111,7 @@ const TopBar = () => {
</div>
) : null}
<div className="flex">
<div className={`${connected ? 'pr-2 md:pr-0' : ''} pl-2`}>
<div className="pl-2">
<ConnectWalletButton />
</div>
</div>

View File

@ -261,7 +261,7 @@ const TradeHistoryTable = ({ numTrades }: { numTrades?: number }) => {
<ExpandableRow
buttonTemplate={
<>
<div className="col-span-11 flex items-center text-fgd-1">
<div className="flex items-center justify-between text-fgd-1 w-full">
<div className="flex items-center">
<img
alt=""
@ -300,26 +300,26 @@ const TradeHistoryTable = ({ numTrades }: { numTrades?: number }) => {
key={`${index}`}
index={index}
panelTemplate={
<>
<div className="col-span-1 text-left">
<div className="grid grid-cols-2 grid-flow-row gap-4">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('value')}
</div>
{formatUsdValue(trade.value)}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('liquidity')}
</div>
{trade.liquidity}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('fee')}
</div>
{formatUsdValue(trade.feeCost)}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('approximate-time')}
</div>
@ -329,7 +329,7 @@ const TradeHistoryTable = ({ numTrades }: { numTrades?: number }) => {
)
: t('recent')}
</div>
</>
</div>
}
/>
))

View File

@ -1,283 +0,0 @@
import { useCallback, useState } from 'react'
import { Table, Thead, Tbody, Tr, Th, Td } from 'react-super-responsive-table'
import { InformationCircleIcon } from '@heroicons/react/outline'
import useMangoStore from '../../stores/useMangoStore'
import { useBalances } from '../../hooks/useBalances'
import { tokenPrecision } from '../../utils/index'
import DepositModal from '../DepositModal'
import WithdrawModal from '../WithdrawModal'
import Button from '../Button'
import Tooltip from '../Tooltip'
import { Market } from '@project-serum/serum'
import {
getTokenBySymbol,
I80F48,
PerpMarket,
} from '@blockworks-foundation/mango-client'
import { notify } from '../../utils/notifications'
import { useTranslation } from 'next-i18next'
export default function AccountAssets() {
const { t } = useTranslation('common')
const balances = useBalances()
const actions = useMangoStore((s) => s.actions)
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
const mangoCache = useMangoStore((s) => s.selectedMangoGroup.cache)
const groupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
const mangoClient = useMangoStore((s) => s.connection.client)
const loadingMangoAccount = useMangoStore(
(s) => s.selectedMangoAccount.initialLoad
)
const connected = useMangoStore((s) => s.wallet.connected)
const [showDepositModal, setShowDepositModal] = useState(false)
const [showWithdrawModal, setShowWithdrawModal] = useState(false)
const [withdrawSymbol, setWithdrawSymbol] = useState('')
const [depositSymbol, setDepositSymbol] = useState('')
const handleCloseDeposit = useCallback(() => {
setShowDepositModal(false)
}, [])
const handleCloseWithdraw = useCallback(() => {
setShowWithdrawModal(false)
}, [])
const handleShowWithdraw = (symbol) => {
setWithdrawSymbol(symbol)
setShowWithdrawModal(true)
}
const handleShowDeposit = (symbol) => {
setDepositSymbol(symbol)
setShowDepositModal(true)
}
async function handleSettleAllTrades() {
const markets: Array<Market | PerpMarket> = Object.values(
useMangoStore.getState().selectedMangoGroup.markets
)
const mangoAccount = useMangoStore.getState().selectedMangoAccount.current
const mangoGroup = useMangoStore.getState().selectedMangoGroup.current
const wallet = useMangoStore.getState().wallet.current
const spotMarkets = markets.filter(
(mkt) => mkt instanceof Market
) as Market[]
try {
await mangoClient.settleAll(mangoGroup, mangoAccount, spotMarkets, wallet)
actions.reloadMangoAccount()
} catch (e) {
if (e.message === 'No unsettled funds') {
notify({
title: t('no-unsettled'),
type: 'error',
})
} else {
notify({
title: t('settle-error'),
description: e.message,
txid: e.txid,
type: 'error',
})
}
}
}
return mangoAccount ? (
<>
<div className="sm:flex sm:items-center sm:justify-between pb-2">
<div className="pb-2 sm:pb-0 text-th-fgd-1 text-lg">
{t('your-assets')}
</div>
{balances.length > 0 ? (
<div className="border border-th-green flex items-center justify-between p-2 rounded">
<div className="pr-4 text-xs text-th-fgd-3">
{t('total-assets')}:
</div>
<span>
$ {mangoAccount.getAssetsVal(mangoGroup, mangoCache).toFixed(2)}
</span>
</div>
) : null}
</div>
{balances.length > 0 &&
balances.find(({ unsettled }) => unsettled > 0) ? (
<div
className={`flex items-center justify-between px-6 py-4 my-2 rounded-md bg-th-bkg-1`}
>
<div className="flex items-center text-fgd-1 font-semibold pr-4">
You have unsettled funds
<Tooltip content="Use the Settle All button to move unsettled funds to your deposits.">
<div>
<InformationCircleIcon
className={`h-5 w-5 ml-2 text-th-primary cursor-help`}
/>
</div>
</Tooltip>
</div>
<Button onClick={handleSettleAllTrades}>{t('settle-all')}</Button>
</div>
) : null}
{mangoGroup && balances.length > 0 ? (
<div className={`flex flex-col py-4`}>
<div className={`-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8`}>
<div
className={`align-middle inline-block min-w-full sm:px-6 lg:px-8`}
>
<Table className="min-w-full divide-y divide-th-bkg-2">
<Thead>
<Tr className="text-th-fgd-3 text-xs">
<Th
scope="col"
className={`px-6 py-3 text-left font-normal`}
>
{t('asset')}
</Th>
<Th
scope="col"
className={`px-6 py-3 text-left font-normal`}
>
Available
</Th>
<Th
scope="col"
className={`px-6 py-3 text-left font-normal`}
>
{t('in-orders')}
</Th>
<Th
scope="col"
className={`px-6 py-3 text-left font-normal`}
>
{t('unsettled')}
</Th>
<Th
scope="col"
className={`px-6 py-3 text-left font-normal`}
>
{t('value')}
</Th>
<Th scope="col" className="px-6 py-3 text-left font-normal">
{t('interest')} APY
</Th>
</Tr>
</Thead>
<Tbody>
{balances.map((bal, i) => {
const token = getTokenBySymbol(groupConfig, bal.symbol)
const tokenIndex = mangoGroup.getTokenIndex(token.mintKey)
return (
<Tr
key={tokenIndex}
className={`border-b border-th-bkg-3
${i % 2 === 0 ? `bg-th-bkg-3` : `bg-th-bkg-2`}
`}
>
<Td
className={`px-6 py-3 whitespace-nowrap text-sm text-th-fgd-1`}
>
<div className="flex items-center">
<img
alt=""
width="20"
height="20"
src={`/assets/icons/${bal.symbol.toLowerCase()}.svg`}
className={`mr-2.5`}
/>
<div>{bal.symbol}</div>
</div>
</Td>
<Td
className={`px-6 py-3 whitespace-nowrap text-sm text-th-fgd-1`}
>
{bal.deposits.toFixed(tokenPrecision[bal.symbol])}
</Td>
<Td
className={`px-6 py-3 whitespace-nowrap text-sm text-th-fgd-1`}
>
{bal.orders.toFixed(tokenPrecision[bal.symbol])}
</Td>
<Td
className={`px-6 py-3 whitespace-nowrap text-sm text-th-fgd-1`}
>
{bal.unsettled.toFixed(tokenPrecision[bal.symbol])}
</Td>
<Td
className={`px-6 py-3 whitespace-nowrap text-sm text-th-fgd-1`}
>
$
{(
(bal.deposits.toNumber() +
bal.orders +
bal.unsettled) *
mangoGroup
.getPrice(tokenIndex, mangoCache)
.toNumber()
).toFixed(2)}
</Td>
<Td
className={`px-6 py-3 whitespace-nowrap text-sm text-th-fgd-1`}
>
<span className={`text-th-green`}>
{mangoGroup
.getDepositRate(tokenIndex)
.mul(I80F48.fromNumber(100))
.toFixed(2)}
%
</span>
</Td>
<Td
className={`px-6 py-3 whitespace-nowrap text-sm text-th-fgd-1`}
>
<div className={`flex justify-end`}>
<Button
onClick={() => handleShowDeposit(bal.symbol)}
className="text-xs pt-0 pb-0 h-8 pl-3 pr-3"
disabled={!connected || loadingMangoAccount}
>
<span>{t('deposit')}</span>
</Button>
<Button
onClick={() => handleShowWithdraw(bal.symbol)}
className="ml-3 text-xs pt-0 pb-0 h-8 pl-3 pr-3"
disabled={!connected || loadingMangoAccount}
>
<span>{t('withdraw')}</span>
</Button>
</div>
</Td>
</Tr>
)
})}
</Tbody>
</Table>
</div>
</div>
</div>
) : (
<div
className={`w-full text-center py-6 bg-th-bkg-1 text-th-fgd-3 rounded-md`}
>
No assets found.
</div>
)}
{showDepositModal && (
<DepositModal
isOpen={showDepositModal}
onClose={handleCloseDeposit}
tokenSymbol={depositSymbol}
/>
)}
{showWithdrawModal && (
<WithdrawModal
isOpen={showWithdrawModal}
onClose={handleCloseWithdraw}
tokenSymbol={withdrawSymbol}
/>
)}
</>
) : null
}

View File

@ -167,14 +167,8 @@ export default function AccountBorrows() {
) : (
<>
<MobileTableHeader
headerTemplate={
<>
<div className="col-span-7">{t('asset')}</div>
<div className="col-span-4 text-right">
{t('balance')}
</div>
</>
}
colOneHeader={t('asset')}
colTwoHeader={t('balance')}
/>
{balances
.filter((assets) => assets.borrows.gt(ZERO_I80F48))
@ -189,8 +183,8 @@ export default function AccountBorrows() {
return (
<ExpandableRow
buttonTemplate={
<>
<div className="col-span-7 flex items-center text-fgd-1">
<div className="flex items-center justify-between text-fgd-1 w-full">
<div className="flex items-center text-fgd-1">
<img
alt=""
width="20"
@ -201,18 +195,19 @@ export default function AccountBorrows() {
{asset.symbol}
</div>
<div className="col-span-4 text-fgd-1 text-right">
<div className="text-fgd-1 text-right">
{asset.borrows.toFixed(
tokenPrecision[asset.symbol]
)}
</div>
</>
</div>
}
key={`${asset.symbol}${i}`}
index={i}
panelTemplate={
<>
<div className="col-span-1 text-left">
<div className="grid grid-cols-2 grid-flow-row gap-4 pb-4">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('value')}
</div>
@ -227,7 +222,7 @@ export default function AccountBorrows() {
.toNumber()
)}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('borrow-rate')} (APR)
</div>
@ -240,8 +235,9 @@ export default function AccountBorrows() {
%
</span>
</div>
</div>
<div className="col-span-1">
<div className="flex space-x-4">
<Button
onClick={() =>
handleShowDeposit(asset.symbol)
@ -251,8 +247,6 @@ export default function AccountBorrows() {
>
{t('deposit')}
</Button>
</div>
<div className="col-span-1">
<Button
onClick={() =>
handleShowBorrow(asset.symbol)
@ -382,22 +376,16 @@ export default function AccountBorrows() {
) : (
<>
<MobileTableHeader
headerTemplate={
<>
<div className="col-span-5">{t('asset')}</div>
<div className="col-span-6 text-right">
{t('borrow-rate')} (APR)
</div>
</>
}
colOneHeader={t('asset')}
colTwoHeader={`${t('borrow-rate')} (APR)`}
/>
{mangoConfig.tokens.map((token, i) => {
const tokenIndex = mangoGroup.getTokenIndex(token.mintKey)
return (
<ExpandableRow
buttonTemplate={
<>
<div className="col-span-7 flex items-center text-fgd-1">
<div className="flex items-center justify-between text-fgd-1 w-full">
<div className="flex items-center">
<img
alt=""
width="20"
@ -408,7 +396,7 @@ export default function AccountBorrows() {
{token.symbol}
</div>
<div className="col-span-4 text-fgd-1 text-right">
<div className="text-fgd-1 text-right">
<span className={`text-th-red`}>
{i80f48ToPercent(
mangoGroup.getBorrowRate(tokenIndex)
@ -416,13 +404,13 @@ export default function AccountBorrows() {
%
</span>
</div>
</>
</div>
}
key={`${token.symbol}${i}`}
index={i}
panelTemplate={
<>
<div className="col-span-1 text-left">
<div className="grid grid-cols-2 grid-flow-row gap-4">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('price')}
</div>
@ -432,7 +420,7 @@ export default function AccountBorrows() {
.toNumber()
)}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('max-borrow')}
</div>
@ -451,7 +439,7 @@ export default function AccountBorrows() {
tokenPrecision[token.symbol],
})}
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('liquidity')}
</div>
@ -466,8 +454,8 @@ export default function AccountBorrows() {
tokenPrecision[token.symbol],
})}
</div>
<div className="col-span-1" />
<div className="col-span-1">
<div className="" />
<div className="">
<Button
onClick={() => handleShowBorrow(token.symbol)}
className="text-xs pt-0 pb-0 h-8 w-full"
@ -476,7 +464,7 @@ export default function AccountBorrows() {
{t('borrow')}
</Button>
</div>
</>
</div>
}
/>
)

View File

@ -1,7 +1,6 @@
import { getTokenBySymbol } from '@blockworks-foundation/mango-client'
import { useEffect, useMemo, useState } from 'react'
import useMangoStore from '../../stores/useMangoStore'
import Loading from '../Loading'
import Select from '../Select'
import { Table, Td, Th, TrBody, TrHead } from '../TableElements'
import { useTranslation } from 'next-i18next'
@ -9,6 +8,10 @@ import { isEmpty } from 'lodash'
import usePagination from '../../hooks/usePagination'
import { roundToDecimal } from '../../utils/'
import Pagination from '../Pagination'
import { useViewport } from '../../hooks/useViewport'
import { breakpoints } from '../TradePageGrid'
import { ExpandableRow } from '../TableElements'
import MobileTableHeader from '../mobile/MobileTableHeader'
interface InterestStats {
[key: string]: {
@ -22,11 +25,9 @@ const AccountInterest = () => {
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
const groupConfig = useMangoStore((s) => s.selectedMangoGroup.config)
const [interestStats, setInterestStats] = useState<any>([])
const [hourlyInterestStats, setHourlyInterestStats] = useState<any>({
USDC: [],
})
const [hourlyInterestStats, setHourlyInterestStats] = useState<any>({})
const [loading, setLoading] = useState(false)
const [selectedAsset, setSelectedAsset] = useState<string>('USDC')
const [selectedAsset, setSelectedAsset] = useState<string>('')
const {
paginated,
setData,
@ -37,13 +38,17 @@ const AccountInterest = () => {
firstPage,
lastPage,
} = usePagination(hourlyInterestStats[selectedAsset])
const { width } = useViewport()
const isMobile = width ? width < breakpoints.md : false
const mangoAccountPk = useMemo(() => {
return mangoAccount.publicKey.toString()
}, [mangoAccount])
const token = useMemo(() => {
if (selectedAsset) {
return getTokenBySymbol(groupConfig, selectedAsset)
}
}, [selectedAsset])
useEffect(() => {
@ -52,6 +57,12 @@ const AccountInterest = () => {
}
}, [selectedAsset, hourlyInterestStats])
useEffect(() => {
if (!selectedAsset && Object.keys(hourlyInterestStats).length > 0) {
setSelectedAsset(Object.keys(hourlyInterestStats)[0])
}
}, [hourlyInterestStats])
useEffect(() => {
const fetchInterestStats = async () => {
const response = await fetch(
@ -104,11 +115,10 @@ const AccountInterest = () => {
return (
<>
<div className="pb-3.5 text-th-fgd-1 text-base">
{t('interest-earned')}
</div>
<div className="pb-4 text-th-fgd-1 text-lg">{t('interest-earned')}</div>
{mangoAccount ? (
<div>
{!isMobile ? (
<Table>
<thead>
<TrHead>
@ -122,7 +132,7 @@ const AccountInterest = () => {
{interestStats.length === 0 ? (
<TrBody index={0}>
<td colSpan={4}>
<div className="flex">
<div className="bg-th-bkg-3 flex rounded-md text-th-fgd-3">
<div className="mx-auto py-4">{t('no-interest')}</div>
</div>
</td>
@ -153,7 +163,8 @@ const AccountInterest = () => {
{symbol}
</Td>
<Td>
{stats.total_borrow_interest.toFixed(decimals)} {symbol}
{stats.total_borrow_interest.toFixed(decimals)}{' '}
{symbol}
</Td>
<Td>
{(
@ -168,14 +179,78 @@ const AccountInterest = () => {
)}
</tbody>
</Table>
) : interestStats.length === 0 ? (
<div className="bg-th-bkg-3 flex rounded-md text-th-fgd-3">
<div className="mx-auto py-4">{t('no-interest')}</div>
</div>
) : (
<>
<MobileTableHeader
colOneHeader={t('token')}
colTwoHeader={t('net')}
/>
{interestStats.map(([symbol, stats], index) => {
const decimals = getTokenBySymbol(groupConfig, symbol).decimals
return (
<ExpandableRow
buttonTemplate={
<div className="flex items-center justify-between text-fgd-1 w-full">
<div className="flex items-center text-fgd-1">
<img
alt=""
width="20"
height="20"
src={`/assets/icons/${symbol.toLowerCase()}.svg`}
className={`mr-2.5`}
/>
{symbol}
</div>
<div className="text-fgd-1 text-right">
{(
stats.total_deposit_interest -
stats.total_borrow_interest
).toFixed(decimals)}{' '}
{symbol}
</div>
</div>
}
key={`${symbol}${index}`}
index={index}
panelTemplate={
<>
<div className="grid grid-cols-2 grid-flow-row gap-4">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('total-deposit-interest')}
</div>
{stats.total_deposit_interest.toFixed(decimals)}{' '}
{symbol}
</div>
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('total-borrow-interest')}
</div>
{stats.total_borrow_interest.toFixed(decimals)}{' '}
{symbol}
</div>
</div>
</>
}
/>
)
})}
</>
)}
<>
{!isEmpty(hourlyInterestStats) && !loading ? (
<>
<div className="flex items-center justify-between my-4 w-full">
<div className="flex items-center justify-between pb-4 pt-6 w-full">
<div className="text-th-fgd-1 text-lg">{t('history')}</div>
<Select
value={selectedAsset}
onChange={(a) => setSelectedAsset(a)}
className="w-24 sm:hidden"
className="w-24 md:hidden"
>
<div className="space-y-2">
{Object.keys(hourlyInterestStats).map((token: string) => (
@ -191,7 +266,7 @@ const AccountInterest = () => {
))}
</div>
</Select>
<div className="hidden sm:flex pb-4 sm:pb-0">
<div className="hidden md:flex pb-4 sm:pb-0">
{Object.keys(hourlyInterestStats).map((token: string) => (
<div
className={`px-2 py-1 ml-2 rounded-md cursor-pointer default-transition bg-th-bkg-3
@ -226,8 +301,10 @@ const AccountInterest = () => {
return (
<TrBody index={index} key={stat.time}>
<Td>
{date.toLocaleDateString()}{' '}
<div>{date.toLocaleDateString()}</div>
<div className="text-xs text-th-fgd-3">
{date.toLocaleTimeString()}
</div>
</Td>
<Td>
{stat.borrow_interest > 0
@ -261,10 +338,10 @@ const AccountInterest = () => {
</div>
</>
) : loading ? (
<div className="flex justify-center my-8">
<div>
<Loading />
</div>
<div className="pt-8 space-y-2">
<div className="animate-pulse bg-th-bkg-3 h-12 rounded-md w-full" />
<div className="animate-pulse bg-th-bkg-3 h-12 rounded-md w-full" />
<div className="animate-pulse bg-th-bkg-3 h-12 rounded-md w-full" />
</div>
) : null}
</>

View File

@ -209,7 +209,7 @@ export default function AccountOverview() {
</div>
</div>
</div>
<div className="flex justify-between pb-4 sm:pb-0">
<div className="flex justify-between pb-4 md:pb-6">
<div className="text-th-fgd-1 text-lg">Balances</div>
<Switch
checked={showZeroBalances}

View File

@ -37,7 +37,7 @@ const BottomBar = () => {
return (
<>
<div className="bg-th-bkg-4 default-transition grid grid-cols-4 grid-rows-1 py-2.5">
<div className="bg-th-bkg-1 default-transition grid grid-cols-4 grid-rows-1 py-2.5">
<div
className="col-span-1 cursor-pointer default-transition flex flex-col items-center text-th-fgd-3 hover:text-th-primary"
onClick={() => setShowMarketsModal(true)}

View File

@ -1,11 +1,16 @@
type MobileTableHeaderProps = {
headerTemplate: React.ReactNode
colOneHeader: string
colTwoHeader: string
}
const MobileTableHeader = ({ headerTemplate }: MobileTableHeaderProps) => {
const MobileTableHeader = ({
colOneHeader,
colTwoHeader,
}: MobileTableHeaderProps) => {
return (
<div className="grid grid-cols-12 grid-rows-1 gap-4 pb-2 px-3 text-xs">
{headerTemplate}
<div className="flex justify-between pb-2 pl-4 pr-14 text-th-fgd-3 text-xs">
<div>{colOneHeader}</div>
<div>{colTwoHeader}</div>
</div>
)
}

View File

@ -104,7 +104,7 @@ const MobileTradePage = () => {
<Swipeable index={viewIndex} onChangeIndex={handleChangeViewIndex}>
<div>
<div className="bg-th-bkg-2 grid grid-cols-12 grid-rows-1 gap-4 mb-2 px-2 py-3 rounded-lg">
<div className="col-span-7">
<div className="col-span-7 pt-2">
<AdvancedTradeForm />
</div>
<div className="col-span-5">

View File

@ -26,7 +26,7 @@ export default function StatsAssets({ latestStats, stats }) {
<Select
value={selectedAsset}
onChange={(a) => setSelectedAsset(a)}
className="w-24 sm:hidden"
className="w-24 md:hidden"
>
<div className="space-y-2">
{latestStats.map((stat) => (
@ -42,7 +42,7 @@ export default function StatsAssets({ latestStats, stats }) {
))}
</div>
</Select>
<div className="hidden sm:flex pb-4 sm:pb-0">
<div className="hidden md:flex pb-4 sm:pb-0">
{latestStats.map((stat) => (
<div
className={`px-2 py-1 ml-2 rounded-md cursor-pointer default-transition bg-th-bkg-3

View File

@ -6,6 +6,7 @@ import Chart from '../Chart'
import BN from 'bn.js'
import { tokenPrecision } from '../../utils'
import { useTranslation } from 'next-i18next'
import Select from '../Select'
function calculateFundingRate(
oldestLongFunding,
@ -82,7 +83,7 @@ export default function StatsPerps({ perpStats }) {
return (
<>
<div className="flex flex-col-reverse sm:flex-row sm:items-center sm:justify-between mb-4 w-full">
<div className="flex items-center justify-between mb-4 w-full">
<div className="flex items-center text-xl text-th-fgd-1">
<img
width="24"
@ -94,7 +95,26 @@ export default function StatsPerps({ perpStats }) {
/>
{selectedAsset.split(/-|\//)[0]} {t('perpetual-futures')}
</div>
<div className="flex mb-4 sm:mb-0 space-x-2">
<Select
value={selectedAsset}
onChange={(a) => setSelectedAsset(a)}
className="flex-shrink-0 ml-4 w-36 md:hidden"
>
<div className="space-y-2">
{marketConfigs.map((market) => (
<Select.Option
key={market.name}
value={market.name}
className={`bg-th-bkg-1 relative rounded-md w-full px-3 py-3 cursor-pointer default-transition flex hover:bg-th-bkg-3 focus:outline-none`}
>
<div className="flex items-center justify-between w-full">
{market.name}
</div>
</Select.Option>
))}
</div>
</Select>
<div className="hidden md:flex space-x-2">
{marketConfigs.map((market) => (
<div
className={`bg-th-bkg-3 cursor-pointer default-transition px-2 py-1 rounded-md text-center w-full whitespace-nowrap
@ -107,7 +127,7 @@ export default function StatsPerps({ perpStats }) {
onClick={() => setSelectedAsset(market.name)}
key={market.name as string}
>
{market.name}
{market.name.slice(0, -5)}
</div>
))}
</div>

View File

@ -345,8 +345,8 @@ export default function StatsTotals({ latestStats, stats }) {
// latestStats.length > 0 ? (
<ExpandableRow
buttonTemplate={
<div className="col-span-11">
<div className="col-span-11 flex items-center pb-4 text-fgd-1">
<div className="grid grid-cols-12 grid-rows-2 sm:grid-rows-1 gap-2 text-left sm:text-right w-full">
<div className="col-span-12 sm:col-span-6 flex items-center text-fgd-1">
<div className="flex items-center">
<img
alt=""
@ -360,27 +360,25 @@ export default function StatsTotals({ latestStats, stats }) {
{stat.name}
</div>
</div>
<div className="grid grid-cols-11 grid-rows-1 gap-4">
<div className="col-span-6 text-left">
<div className="col-span-6 sm:col-span-3">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('total-deposits')}
</div>
{formatNumberString(stat.totalDeposits, 0)}
</div>
<div className="col-span-5 text-left">
<div className="col-span-6 sm:col-span-3">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('total-borrows')}
</div>
{formatNumberString(stat.totalBorrows, 0)}
</div>
</div>
</div>
}
key={stat.name}
index={index}
panelTemplate={
<>
<div className="col-span-1 text-left">
<div className="grid grid-cols-2 grid-flow-row gap-4">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('deposit-rate')}
</div>
@ -389,7 +387,7 @@ export default function StatsTotals({ latestStats, stats }) {
%
</span>
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('borrow-rate')}
</div>
@ -397,7 +395,7 @@ export default function StatsTotals({ latestStats, stats }) {
{formatNumberString(stat.borrowInterest.toNumber(), 2)}%
</span>
</div>
<div className="col-span-1 text-left">
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('utilization')}
</div>
@ -407,7 +405,7 @@ export default function StatsTotals({ latestStats, stats }) {
)}
%
</div>
</>
</div>
}
/>
))}
@ -419,8 +417,8 @@ export default function StatsTotals({ latestStats, stats }) {
{stats.length > 1
? latestStats.map((stat, index) => (
<Row key={stat.name} index={index}>
<div className="col-span-12">
<div className="col-span-12 flex items-center pb-4 text-fgd-1">
<div className="grid grid-cols-12 grid-rows-2 sm:grid-rows-1 gap-2 text-left sm:text-right">
<div className="col-span-12 sm:col-span-3 flex items-center text-fgd-1">
<div className="flex items-center">
<img
alt=""
@ -434,28 +432,17 @@ export default function StatsTotals({ latestStats, stats }) {
{stat.name}
</div>
</div>
<div className="grid grid-cols-12 grid-rows-1 gap-4">
<div className="col-span-4 text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
24h
</div>
<div className="col-span-4 sm:col-span-3">
<div className="pb-0.5 text-th-fgd-3 text-xs">24h</div>
{getAverageStats(stats, 1, stat.name, 'depositIndex')}
</div>
<div className="col-span-4 text-left">
<div className="col-span-4 sm:col-span-3">
<div className="pb-0.5 text-th-fgd-3 text-xs">7d</div>
{getAverageStats(stats, 7, stat.name, 'depositIndex')}
</div>
<div className="col-span-4 text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
30d
</div>
{getAverageStats(
stats,
30,
stat.name,
'depositIndex'
)}
</div>
<div className="col-span-4 sm:col-span-3">
<div className="pb-0.5 text-th-fgd-3 text-xs">30d</div>
{getAverageStats(stats, 30, stat.name, 'depositIndex')}
</div>
</div>
</Row>
@ -468,8 +455,8 @@ export default function StatsTotals({ latestStats, stats }) {
{stats.length > 1
? latestStats.map((stat, index) => (
<Row key={stat.name} index={index}>
<div className="col-span-12">
<div className="col-span-12 flex items-center pb-4 text-fgd-1">
<div className="grid grid-cols-12 grid-rows-2 sm:grid-rows-1 gap-2 text-left sm:text-right">
<div className="col-span-12 sm:col-span-3 flex items-center text-fgd-1">
<div className="flex items-center">
<img
alt=""
@ -483,21 +470,19 @@ export default function StatsTotals({ latestStats, stats }) {
{stat.name}
</div>
</div>
<div className="grid grid-cols-12 grid-rows-1 gap-4">
<div className="col-span-4 text-left">
<div className="col-span-4 sm:col-span-3">
<div className="pb-0.5 text-th-fgd-3 text-xs">24h</div>
{getAverageStats(stats, 1, stat.name, 'borrowIndex')}
</div>
<div className="col-span-4 text-left">
<div className="col-span-4 sm:col-span-3">
<div className="pb-0.5 text-th-fgd-3 text-xs">7d</div>
{getAverageStats(stats, 7, stat.name, 'borrowIndex')}
</div>
<div className="col-span-4 text-left">
<div className="col-span-4 sm:col-span-3">
<div className="pb-0.5 text-th-fgd-3 text-xs">30d</div>
{getAverageStats(stats, 30, stat.name, 'borrowIndex')}
</div>
</div>
</div>
</Row>
))
: null}

View File

@ -738,7 +738,7 @@ export default function AdvancedTradeForm({
unit="%"
values={
isMobile
? ['10', '25', '50', '75']
? ['10', '25', '50', '100']
: ['10', '25', '50', '75', '100']
}
/>
@ -871,9 +871,10 @@ export default function AdvancedTradeForm({
</Button>
)}
</div>
<div className="flex text-xs text-th-fgd-4 px-6 mt-2.5 justify-center">
Maker fee: {(makerFee * 100).toFixed(2)}% | Taker fee:{' '}
{takerFee * 100}%
<div className="flex flex-col md:flex-row text-xs text-th-fgd-4 px-6 mt-2.5 items-center justify-center">
<div>Maker fee: {(makerFee * 100).toFixed(2)}% </div>
<span className="hidden md:block md:px-1">|</span>
<div> Taker fee: {takerFee * 100}%</div>
</div>
</div>
</div>

View File

@ -18,22 +18,22 @@ const OrderSideTabs: FunctionComponent<OrderSideTabsProps> = ({
const { t } = useTranslation('common')
const market = useMangoStore((s) => s.selectedMarket.current)
return (
<div className={`border-b border-th-fgd-4 mb-3 relative -mt-2.5`}>
<div className={`md:border-b md:border-th-fgd-4 mb-3 relative -mt-2.5`}>
<div
className={`absolute ${
className={`absolute hidden md:block ${
side === 'buy'
? 'bg-th-green translate-x-0'
: 'bg-th-red translate-x-full'
} bottom-[-1px] default-transition left-0 h-0.5 transform w-1/2`}
/>
<nav className="-mb-px flex" aria-label="Tabs">
<nav className="-mb-px flex space-x-2" aria-label="Tabs">
<button
onClick={() => onChange('buy')}
className={`cursor-pointer default-transition flex font-semibold items-center justify-center pb-2 md:py-2 relative text-base w-1/2 whitespace-nowrap hover:opacity-100
className={`cursor-pointer default-transition flex font-semibold items-center justify-center py-1.5 md:py-2 relative text-sm md:text-base w-1/2 whitespace-nowrap hover:opacity-100
${
side === 'buy'
? `text-th-green`
: `text-th-fgd-4 hover:text-th-green`
? `border border-th-green md:border-0 text-th-green`
: `border border-th-fgd-4 md:border-0 text-th-fgd-4 hover:border-th-green hover:text-th-green`
}
`}
>
@ -41,11 +41,11 @@ const OrderSideTabs: FunctionComponent<OrderSideTabsProps> = ({
</button>
<button
onClick={() => onChange('sell')}
className={`cursor-pointer default-transition flex font-semibold items-center justify-center pb-2 md:py-2 relative text-base w-1/2 whitespace-nowrap hover:opacity-100
className={`cursor-pointer default-transition flex font-semibold items-center justify-center py-1.5 md:py-2 relative text-sm md:text-base w-1/2 whitespace-nowrap hover:opacity-100
${
side === 'sell'
? `text-th-red`
: `text-th-fgd-4 hover:text-th-red`
? `border border-th-red md:border-0 text-th-red`
: `border border-th-fgd-4 md:border-0 text-th-fgd-4 hover:border-th-red hover:text-th-red`
}
`}
>

View File

@ -20,13 +20,13 @@ import AccountNameModal from '../components/AccountNameModal'
import Button from '../components/Button'
import EmptyState from '../components/EmptyState'
import Loading from '../components/Loading'
import SwipeableTabs from '../components/mobile/SwipeableTabs'
import Swipeable from '../components/mobile/Swipeable'
import Tabs from '../components/Tabs'
import { useViewport } from '../hooks/useViewport'
import { breakpoints } from '../components/TradePageGrid'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { useTranslation } from 'next-i18next'
import Select from '../components/Select'
export async function getServerSideProps({ locale }) {
return {
@ -37,17 +37,7 @@ export async function getServerSideProps({ locale }) {
}
}
const TABS = [
'Portfolio',
// 'Assets',
// 'Borrows',
// 'Stats',
// 'Positions',
'Orders',
'Trade History',
'Interest',
'Funding',
]
const TABS = ['Portfolio', 'Orders', 'Trade History', 'Interest', 'Funding']
export default function Account() {
const { t } = useTranslation('common')
@ -155,11 +145,18 @@ export default function Account() {
tabs={TABS}
/>
) : (
<SwipeableTabs
onChange={handleChangeViewIndex}
tabs={TABS}
tabIndex={viewIndex}
/>
<div className="pb-2 pt-3">
<Select
value={TABS[viewIndex]}
onChange={(e) => handleChangeViewIndex(e)}
>
{TABS.map((tab, index) => (
<Select.Option key={index + tab} value={index}>
{tab}
</Select.Option>
))}
</Select>
</div>
)
) : null}
<div className="bg-th-bkg-2 p-4 sm:p-6 rounded-lg">
@ -180,6 +177,12 @@ export default function Account() {
<div>
<AccountHistory />
</div>
<div>
<AccountInterest />
</div>
<div>
<AccountFunding />
</div>
</Swipeable>
)
) : connected ? (

View File

@ -38,10 +38,14 @@ export default function Borrow() {
<TopBar />
<PageBodyContainer>
<div className="pt-8 pb-3 sm:pb-4 md:pt-10">
{connected ? (
<>
<h1 className={`mb-1 text-th-fgd-1 text-2xl font-semibold`}>
{t('borrow-funds')}
</h1>
<p>{t('borrow-notification')}</p>
</>
) : null}
</div>
<div className="bg-th-bkg-2 overflow-none p-4 sm:p-6 rounded-lg">
{selectedMangoAccount ? (

View File

@ -100,6 +100,7 @@
"health-ratio": "Health Ratio",
"hide-all": "Hide all from Nav",
"high": "High",
"history": "History",
"hourly-borrow-interest": "Hourly Borrow Interest",
"hourly-deposit-interest": "Hourly Deposit Interest",
"hourly-funding": "Hourly Funding",

View File

@ -99,6 +99,7 @@
"health-ratio": "Relación de salud",
"hide-all": "Ocultar todo de Nav",
"high": "Alta",
"history": "La Historia",
"hourly-borrow-interest": "Préstamo prestado por hora",
"hourly-deposit-interest": "Interés por depósito por hora",
"hourly-funding": "Financiamiento por hora",

View File

@ -100,6 +100,7 @@
"health-ratio": "健康比率",
"hide-all": "在导航栏中隐藏全部",
"high": "高",
"history": "历史",
"hourly-borrow-interest": "1小时借贷利息",
"hourly-deposit-interest": "1小时存款利息",
"hourly-funding": "1小时资金费",

View File

@ -100,6 +100,7 @@
"health-ratio": "健康比率",
"hide-all": "在導航欄中隱藏全部",
"high": "高",
"history": "歷史",
"hourly-borrow-interest": "1小時借貸利息",
"hourly-deposit-interest": "1小時存款利息",
"hourly-funding": "1小時資金費",