Add UiLock toggle and themed the stats page

This commit is contained in:
Tyler Shipe 2021-04-13 12:51:42 -04:00
parent e0370f4b0f
commit 59f1156703
13 changed files with 160 additions and 98 deletions

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v14.15.3

View File

@ -1,14 +1,14 @@
import { Listbox } from '@headlessui/react'
import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/solid'
const Select = ({ value, onChange, options, className = '' }) => {
const Select = ({ value, onChange, children, className = '' }) => {
return (
<div className={`relative`}>
<div className={`relative ${className}`}>
<Listbox value={value} onChange={onChange}>
{({ open }) => (
<>
<Listbox.Button
className={`h-full w-full bg-th-bkg-1 border border-th-fgd-4 rounded focus:outline-none focus:ring-1 focus:ring-th-primary ${className}`}
className={`h-full w-full bg-th-bkg-1 border border-th-fgd-4 rounded focus:outline-none focus:ring-1 focus:ring-th-primary`}
>
<div
className={`flex items-center justify-between space-x-4 pl-2 pr-1`}
@ -26,19 +26,7 @@ const Select = ({ value, onChange, options, className = '' }) => {
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`}
>
{options.map((option) => (
<Listbox.Option key={option} value={option}>
{({ selected }) => (
<div
className={`p-2 hover:bg-th-bkg-3 hover:cursor-pointer tracking-wider ${
selected && `text-th-primary`
}`}
>
{option}
</div>
)}
</Listbox.Option>
))}
{children}
</Listbox.Options>
) : null}
</>
@ -48,4 +36,22 @@ const Select = ({ value, onChange, options, className = '' }) => {
)
}
const Option = ({ key, value, children }) => {
return (
<Listbox.Option key={key} value={value}>
{({ selected }) => (
<div
className={`p-2 hover:bg-th-bkg-3 hover:cursor-pointer tracking-wider ${
selected && `text-th-primary`
}`}
>
{children}
</div>
)}
</Listbox.Option>
)
}
Select.Option = Option
export default Select

View File

@ -4,6 +4,8 @@ import { MenuIcon, XIcon } from '@heroicons/react/outline'
import MenuItem from './MenuItem'
import useWallet from '../hooks/useWallet'
import ThemeSwitch from './ThemeSwitch'
import UiLock from './UiLock'
import { useRouter } from 'next/router'
const Code = styled.code`
border: 1px solid hsla(0, 0%, 39.2%, 0.2);
@ -12,6 +14,9 @@ const Code = styled.code`
`
const TopBar = () => {
const { asPath } = useRouter()
console.log('asPath', asPath)
const { connected, wallet } = useWallet()
const [showMenu, setShowMenu] = useState(false)
@ -39,18 +44,8 @@ const TopBar = () => {
</div>
<div className={`flex`}>
<div className={`flex items-center pr-1`}>
{asPath === '/' ? <UiLock className="mr-4" /> : null}
<ThemeSwitch />
{/*<button
type="button"
className={`inline-flex items-center justify-center p-2 rounded-md text-black dark:text-white hover:text-gray-400 focus:outline-none`}
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
>
{theme === 'light' ? (
<MoonIcon className={`h-5 w-5`} />
) : (
<SunIcon className={`h-5 w-5`} />
)}
</button>*/}
<div className={`hidden sm:ml-4 sm:flex sm:items-center`}>
<button
onClick={handleConnectDisconnect}

View File

@ -12,6 +12,7 @@ import MarginBalances from './MarginBalances'
import TradeForm from './TradeForm'
import UserInfo from './UserInfo'
import RecentMarketTrades from './RecentMarketTrades'
import useMangoStore from '../stores/useMangoStore'
const ResponsiveGridLayout = WidthProvider(Responsive)
@ -37,6 +38,8 @@ const layouts = {
}
const TradePageGrid = () => {
const { uiLocked } = useMangoStore((s) => s.settings)
return (
<ResponsiveGridLayout
className="layout"
@ -44,7 +47,8 @@ const TradePageGrid = () => {
breakpoints={{ xl: 1600, lg: 1200, md: 996, sm: 768, xs: 0 }}
cols={{ xl: 5, lg: 3, md: 3, sm: 2, xs: 1 }}
rowHeight={15}
isDraggable={false}
isDraggable={!uiLocked}
isResizable={!uiLocked}
>
<div key="tvChart">
<FloatingElement>

26
components/UiLock.tsx Normal file
View File

@ -0,0 +1,26 @@
import { LockClosedIcon, LockOpenIcon } from '@heroicons/react/outline'
import useMangoStore from '../stores/useMangoStore'
const UiLock = ({ className = '' }) => {
const set = useMangoStore((s) => s.set)
const uiLocked = useMangoStore((s) => s.settings.uiLocked)
const handleClick = () => {
set((state) => {
state.settings.uiLocked = !uiLocked
})
}
return (
<div className={`flex relative ${className}`}>
<button
onClick={handleClick}
className="bg-transparent rounded w-5 h-5 hover:text-th-primary focus:outline-none"
>
{uiLocked ? <LockClosedIcon /> : <LockOpenIcon />}
</button>
</div>
)
}
export default UiLock

View File

@ -146,8 +146,11 @@ const useHydrateStore = () => {
state.fills = loadedFills
})
}
fetchFills()
try {
fetchFills()
} catch (err) {
console.error('Error fetching fills:', err)
}
}, _SLOW_REFRESH_INTERVAL)
}

View File

@ -85,7 +85,6 @@ export const useTradeHistory = () => {
}, [marginAccount])
useInterval(() => {
console.log('interval', allTrades, tradeHistory)
if (marginAccount && tradeHistory.length === 0) {
fetchTradeHistory()
}

View File

@ -29,7 +29,7 @@
"@blockworks-foundation/mango-client": "^0.1.10",
"@emotion/react": "^11.1.5",
"@emotion/styled": "^11.1.5",
"@headlessui/react": "^0.3.2",
"@headlessui/react": "^0.3.2-d950146",
"@heroicons/react": "^1.0.0",
"@project-serum/serum": "^0.13.31",
"@project-serum/sol-wallet-adapter": "^0.1.8",

View File

@ -1,9 +0,0 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { NextApiRequest, NextApiResponse } from 'next'
const handler = (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).json({ name: 'John Doe' })
}
export default handler

View File

@ -1,6 +1,5 @@
import { useEffect, useState } from 'react'
import styled from '@emotion/styled'
import { Select } from 'antd'
import { LineChart, Line, ReferenceLine, XAxis, YAxis, Tooltip } from 'recharts'
import useDimensions from 'react-cool-dimensions'
import { IDS, MangoClient } from '@blockworks-foundation/mango-client'
@ -9,6 +8,7 @@ import { DEFAULT_MANGO_GROUP } from '../utils/mango'
import FloatingElement from '../components/FloatingElement'
import useConnection from '../hooks/useConnection'
import TopBar from '../components/TopBar'
import Select from '../components/Select'
const DECIMALS = {
BTC: 4,
@ -26,13 +26,6 @@ const icons = {
WUSDT: '/assets/icons/usdt.svg',
}
const Wrapper = styled.div`
height: 100%;
display: flex;
flex-direction: column;
padding: 16px 16px;
`
const ChartLayover = styled.div`
position: absolute;
top: 0;
@ -195,50 +188,76 @@ export default function StatsPage() {
)
return (
<Wrapper>
<div className={`bg-th-bkg-1 text-th-fgd-1 transition-all `}>
<TopBar />
<div className="w-2/3 mx-auto">
<div className="min-h-screen w-full lg:w-2/3 mx-auto p-1 sm:px-2 sm:py-1 md:px-6 md:py-1">
<FloatingElement>
<>
<div className="text-center">
<h1 className={`text-white text-lg`}>Mango Stats</h1>
</div>
<div className="flex justify-between divide">
<div>Asset</div>
<div>Total Deposits</div>
<div>Total Borrows</div>
<div>Deposit Interest</div>
<div>Borrow Interest</div>
<div>Utilization</div>
</div>
<div className="divide-y divide-gray-600">
{latestStats.map((stat) => (
<div key={stat.symbol} className="flex justify-between py-4">
<div className="flex items-center">
<img src={icons[stat.symbol]} alt={icons[stat.symbol]} />
<button
onClick={() => setSelectedAsset(stat.symbol)}
className="text-th-primary cursor-pointer ml-2"
>
<div style={{ width: '100%' }}>{stat.symbol}</div>
</button>
</div>
<div>{stat.totalDeposits.toFixed(DECIMALS[stat.symbol])}</div>
<div>{stat.totalBorrows.toFixed(DECIMALS[stat.symbol])}</div>
<div>{stat.depositInterest.toFixed(2)}%</div>
<div>{stat.borrowInterest.toFixed(2)}%</div>
<div>{(parseFloat(stat.utilization) * 100).toFixed(2)}%</div>
</div>
))}
</div>
</>
<div className="text-center">
<h1 className={`text-white text-3xl`}>Mango Stats</h1>
</div>
<div className="hidden md:flex md:flex-col min-w-full">
<table className="min-w-full">
<thead className="">
<tr>
<th scope="col" className="text-left py-4">
Asset
</th>
<th scope="col" className="text-left py-4">
Total Deposits
</th>
<th scope="col" className="text-left py-4">
Total Borrows
</th>
<th scope="col" className="text-left py-4">
Deposit Interest
</th>
<th scope="col" className="text-left py-4">
Borrow Interest
</th>
<th scope="col" className="text-left py-4">
Utilization
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-600">
{latestStats.map((stat) => (
<tr key={stat.symbol}>
<td className="flex items-center text-left py-4">
<img src={icons[stat.symbol]} alt={icons[stat.symbol]} />
<button
onClick={() => setSelectedAsset(stat.symbol)}
className="text-th-primary cursor-pointer ml-2"
>
<div style={{ width: '100%' }}>{stat.symbol}</div>
</button>
</td>
<td className="text-left py-4">
{stat.totalDeposits.toFixed(DECIMALS[stat.symbol])}
</td>
<td className="text-left py-4">
{stat.totalBorrows.toFixed(DECIMALS[stat.symbol])}
</td>
<td className="text-left py-4">
{stat.depositInterest.toFixed(2)}%
</td>
<td className="text-left py-4">
{stat.borrowInterest.toFixed(2)}%
</td>
<td className="text-left py-4">
{(parseFloat(stat.utilization) * 100).toFixed(2)}%
</td>
</tr>
))}
</tbody>
</table>
</div>
</FloatingElement>
{selectedAsset ? (
<FloatingElement shrink>
<div className="flex justify-center text-lg">
<div className="flex justify-center text-2xl">
<span className={`text-white`}>Historical</span>
<Select
style={{ margin: '0px 8px', fontSize: 16 }}
className="mx-4 text-lg"
value={selectedAsset}
onChange={(val) => setSelectedAsset(val)}
>
@ -251,8 +270,11 @@ export default function StatsPage() {
<span className={`text-white`}>Stats</span>
</div>
<div className="flex flex-row mt-2">
<div className="relative w-1/2" style={{ height: '300px' }}>
<div className="flex flex-col md:flex-row mt-2">
<div
className="relative my-2 md:w-1/2"
style={{ height: '300px' }}
>
<StatsChart
title="Total Deposits"
xAxis="time"
@ -261,7 +283,10 @@ export default function StatsPage() {
labelFormat={(x) => x.toFixed(DECIMALS[selectedAsset])}
/>
</div>
<div className="relative w-1/2" style={{ height: '300px' }}>
<div
className="relative my-2 md:w-1/2"
style={{ height: '300px' }}
>
<StatsChart
title="Total Borrows"
xAxis="time"
@ -271,8 +296,11 @@ export default function StatsPage() {
/>
</div>
</div>
<div className="flex flex-row" style={{ margin: '50px 0' }}>
<div className="relative w-1/2" style={{ height: '300px' }}>
<div className="flex flex-col md:flex-row">
<div
className="relative my-2 md:w-1/2"
style={{ height: '300px' }}
>
<StatsChart
title="Deposit Interest"
xAxis="time"
@ -281,7 +309,10 @@ export default function StatsPage() {
labelFormat={(x) => `${(x * 100).toFixed(5)}%`}
/>
</div>
<div className="relative w-1/2" style={{ height: '300px' }}>
<div
className="relative my-2 md:w-1/2"
style={{ height: '300px' }}
>
<StatsChart
title="Borrow Interest"
xAxis="time"
@ -294,6 +325,6 @@ export default function StatsPage() {
</FloatingElement>
) : null}
</div>
</Wrapper>
</div>
)
}

View File

@ -91,6 +91,9 @@ interface MangoStore extends State {
current: Wallet
balances: Array<{ account: any; publicKey: PublicKey }>
}
settings: {
uiLocked: boolean
}
set: (x: any) => void
actions: any
}
@ -145,6 +148,9 @@ const useMangoStore = create<MangoStore>((set, get) => ({
current: null,
balances: [],
},
settings: {
uiLocked: true,
},
set: (fn) => set(produce(fn)),
actions: {
async fetchWalletBalances() {

View File

@ -12,8 +12,7 @@
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"jsxImportSource": "@emotion/react"
"jsx": "preserve"
},
"exclude": ["node_modules", ".next", "out", "public/datafeeds"],
"include": [

View File

@ -1024,9 +1024,10 @@
version "9.1.1"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.1.tgz#9daf5745156fd84b8e9889a2dc721f0c58e894aa"
"@headlessui/react@^0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-0.3.2.tgz#fa8600fa669fe704b84e9256855fb39092b6e233"
"@headlessui/react@^0.3.2-d950146":
version "0.3.2-d950146"
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-0.3.2-d950146.tgz#00cad543d2803654a9361be2add89f2b663b4c8d"
integrity sha512-MblPc6jWSTdWiIe7VLBXbpGwhMOoA3ubUdDTqavQ978WNCI70lOBs2k1oi4mU5znRvmEPc9YNAiHIibyxq+4nQ==
"@heroicons/react@^1.0.0":
version "1.0.0"