Mp 1691 credit account details (#67)

This commit is contained in:
Linkie Link 2022-12-13 14:21:30 +01:00 committed by GitHub
parent 4527423a50
commit 83fa513bf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
219 changed files with 1323 additions and 1114 deletions

View File

@ -1,220 +0,0 @@
import BigNumber from 'bignumber.js'
import classNames from 'classnames'
import { useState } from 'react'
import Button from 'components/Button'
import FormattedNumber from 'components/FormattedNumber'
import ArrowRightLine from 'components/Icons/arrow-right-line.svg'
import ChevronDown from 'components/Icons/chevron-down.svg'
import ChevronLeft from 'components/Icons/chevron-left.svg'
import Text from 'components/Text'
import useAccountStats from 'hooks/useAccountStats'
import useCreditAccountPositions from 'hooks/useCreditAccountPositions'
import useMarkets from 'hooks/useMarkets'
import useTokenPrices from 'hooks/useTokenPrices'
import { useAccountDetailsStore } from 'stores'
import { chain } from 'utils/chains'
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
import AccountManageOverlay from './AccountManageOverlay'
const AccountDetails = () => {
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
const isOpen = useAccountDetailsStore((s) => s.isOpen)
const { data: positionsData, isLoading: isLoadingPositions } = useCreditAccountPositions(
selectedAccount ?? '',
)
const { data: tokenPrices } = useTokenPrices()
const { data: marketsData } = useMarkets()
const accountStats = useAccountStats()
const [showManageMenu, setShowManageMenu] = useState(false)
const getTokenTotalUSDValue = (amount: string, denom: string) => {
// early return if prices are not fetched yet
if (!tokenPrices) return 0
return (
BigNumber(amount)
.div(10 ** getTokenDecimals(denom))
.toNumber() * tokenPrices[denom]
)
}
return (
<div
className={classNames(
'relative flex w-[400px] basis-[400px] flex-wrap content-start border-white/20 bg-header placeholder:border-l',
'transition-[margin] duration-1000 ease-in-out',
isOpen ? 'mr-0' : '-mr-[400px]',
)}
>
<Button
onClick={() => {
useAccountDetailsStore.setState({ isOpen: true })
}}
variant='text'
className={classNames(
'absolute top-1/2 -left-[20px] w-[21px] -translate-y-1/2 bg-header p-0',
'rounded-none rounded-tl-sm rounded-bl-sm',
'border border-white/20',
'transition-[opacity] delay-1000 duration-500 ease-in-out',
isOpen ? 'pointer-events-none opacity-0' : 'opacity-100',
)}
>
<span className='flex h-20 px-1 py-6 text-white/40 transition-[color] hover:text-white'>
<ChevronLeft />
</span>
</Button>
<div className='relative flex w-full flex-wrap items-center border-b border-white/20'>
<Button
variant='text'
className='flex flex-grow flex-nowrap items-center justify-center p-4 text-center text-white text-xl-caps'
onClick={() => setShowManageMenu(!showManageMenu)}
>
Account {selectedAccount}
<span className='ml-2 flex w-4'>
<ChevronDown />
</span>
</Button>
<div className='flex border-l border-white/20' onClick={() => {}}>
<Button
variant='text'
className='w-14 p-4 text-white/40 transition-[color] hover:cursor-pointer hover:text-white'
onClick={() => {
useAccountDetailsStore.setState({ isOpen: false })
}}
>
<ArrowRightLine />
</Button>
</div>
<AccountManageOverlay
className='top-[60px] left-[36px]'
show={showManageMenu}
setShow={setShowManageMenu}
/>
</div>
<div className='flex w-full flex-wrap p-2'>
<div className='mb-2 flex w-full'>
<Text size='xs' className='flex-grow text-white/60'>
Total Position:
</Text>
<Text size='xs' className='text-white/60'>
<FormattedNumber
amount={BigNumber(accountStats?.totalPosition ?? 0)
.dividedBy(10 ** chain.stakeCurrency.coinDecimals)
.toNumber()}
animate
prefix='$'
/>
</Text>
</div>
<div className='flex w-full justify-between'>
<Text size='xs' className='flex-grow text-white/60'>
Total Liabilities:
</Text>
<Text size='xs' className=' text-white/60'>
<FormattedNumber
amount={BigNumber(accountStats?.totalDebt ?? 0)
.dividedBy(10 ** chain.stakeCurrency.coinDecimals)
.toNumber()}
animate
prefix='$'
/>
</Text>
</div>
</div>
<div className='flex w-full flex-wrap'>
<Text uppercase className='w-full bg-black/20 px-4 py-2 text-white/40'>
Balances
</Text>
{isLoadingPositions ? (
<div>Loading...</div>
) : (
<div className='flex w-full flex-wrap'>
<div className='mb-2 flex w-full border-b border-white/20 bg-black/20 px-4 py-2'>
<Text size='xs' uppercase className='flex-1 text-white'>
Asset
</Text>
<Text size='xs' uppercase className='flex-1 text-white'>
Value
</Text>
<Text size='xs' uppercase className='flex-1 text-white'>
Size
</Text>
<Text size='xs' uppercase className='flex-1 text-white'>
APY
</Text>
</div>
{positionsData?.coins.map((coin) => (
<div key={coin.denom} className='flex w-full px-4 py-2'>
<Text size='xs' className='flex-1 border-l-4 border-profit pl-2 text-white/60'>
{getTokenSymbol(coin.denom)}
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={getTokenTotalUSDValue(coin.amount, coin.denom)}
animate
prefix='$'
/>
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={BigNumber(coin.amount)
.div(10 ** getTokenDecimals(coin.denom))
.toNumber()}
animate
minDecimals={0}
maxDecimals={4}
/>
</Text>
<Text size='xs' className='flex-1 text-white/60'>
-
</Text>
</div>
))}
{positionsData?.debts.map((coin) => (
<div key={coin.denom} className='flex w-full px-4 py-2'>
<Text size='xs' className='flex-1 border-l-4 border-loss pl-2 text-white/60'>
{getTokenSymbol(coin.denom)}
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={getTokenTotalUSDValue(coin.amount, coin.denom)}
prefix='-$'
animate
/>
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={BigNumber(coin.amount)
.div(10 ** getTokenDecimals(coin.denom))
.toNumber()}
minDecimals={0}
maxDecimals={4}
animate
/>
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={Number(marketsData?.[coin.denom].borrow_rate) * 100}
minDecimals={0}
maxDecimals={2}
prefix='-'
suffix='%'
animate
/>
</Text>
</div>
))}
</div>
)}
</div>
</div>
)
}
export default AccountDetails

View File

@ -1,24 +0,0 @@
import CircularProgress from 'components/CircularProgress'
import Modal from 'components/Modal'
import Text from 'components/Text'
import { useModalStore } from 'stores'
const ConfirmModal = () => {
const createOpen = useModalStore((s) => s.createAccountModal)
const deleteOpen = useModalStore((s) => s.deleteAccountModal)
return (
<Modal open={createOpen || deleteOpen}>
<div className='w-full p-6'>
<Text size='2xl' uppercase={true} className='mb-6 w-full text-center'>
Confirm Transaction
</Text>
<div className='flex w-full justify-center pb-6'>
<CircularProgress size={40} />
</div>
</div>
</Modal>
)
}
export default ConfirmModal

View File

@ -1,7 +0,0 @@
export { default as AccountDetails } from './AccountDetails'
export { default as AccountManageOverlay } from './AccountManageOverlay'
export { default as AccountNavigation } from './AccountNavigation'
export { default as AccountStatus } from './AccountStatus'
export { default as ConfirmModal } from './ConfirmModal'
export { default as FundAccountModal } from './FundAccountModal'
export { default as WithdrawModal } from './WithdrawModal'

View File

@ -1,2 +0,0 @@
export { default as AssetRow } from './AssetRow'
export { default as BorrowTable } from './BorrowTable'

View File

@ -1,75 +0,0 @@
import classNames from 'classnames'
import React, { useEffect, useRef } from 'react'
import { animated, useSpring } from 'react-spring'
import { formatValue } from 'utils/formatters'
interface Props {
amount: number
animate?: boolean
className?: string
minDecimals?: number
maxDecimals?: number
thousandSeparator?: boolean
prefix?: boolean | string
suffix?: boolean | string
rounded?: boolean
abbreviated?: boolean
}
const FormattedNumber = ({
amount,
animate = false,
className,
minDecimals = 2,
maxDecimals = 2,
thousandSeparator = true,
prefix = false,
suffix = false,
rounded = false,
abbreviated = false,
}: Props) => {
const prevAmountRef = useRef<number>(0)
useEffect(() => {
if (prevAmountRef.current !== amount) prevAmountRef.current = amount
}, [amount])
const springAmount = useSpring({
number: amount,
from: { number: prevAmountRef.current },
config: { duration: 1000 },
})
return (prevAmountRef.current === amount && amount === 0) || !animate ? (
<span className={classNames('number', className)}>
{formatValue(
amount,
minDecimals,
maxDecimals,
thousandSeparator,
prefix,
suffix,
rounded,
abbreviated,
)}
</span>
) : (
<animated.span className={classNames('number', className)}>
{springAmount.number.to((num) =>
formatValue(
num,
minDecimals,
maxDecimals,
thousandSeparator,
prefix,
suffix,
rounded,
abbreviated,
),
)}
</animated.span>
)
}
export default React.memo(FormattedNumber)

View File

@ -1,3 +0,0 @@
export { default as DesktopNavigation } from './DesktopNavigation'
export { default as menuTree } from './menuTree'
export { default as NavLink } from './NavLink'

View File

@ -1,2 +0,0 @@
export { default as Overlay } from './Overlay'
export { default as OverlayLink } from './OverlayLink'

View File

@ -1,3 +0,0 @@
export { default as ConnectButton } from './ConnectButton'
export { default as ConnectedButton } from './ConnectedButton'
export { default as Wallet } from './Wallet'

View File

@ -1,16 +1,9 @@
const { withSentryConfig } = require('@sentry/nextjs')
// This file sets a custom webpack configuration to use your Next.js app
// with Sentry.
// https://nextjs.org/docs/api-reference/next.config.js/introduction
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
// swcMinify: true,
sentry: {
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#use-hidden-source-map
hideSourceMaps: true,
},
async redirects() {

View File

@ -5,9 +5,11 @@
"scripts": {
"build": "next build",
"dev": "next dev",
"format": "eslint . --ext=ts,tsx --fix && prettier --write ./**/*.ts ./**/*.tsx",
"lint": "next lint",
"start": "next start"
"lint": "eslint ./src/ && yarn prettier-check",
"format": "yarn index && eslint ./src/ --fix && prettier --write ./src/",
"prettier-check": "prettier --ignore-path .gitignore --check ./src/",
"start": "next start",
"index": "vscode-generate-index-standalone src/"
},
"dependencies": {
"@cosmjs/cosmwasm-stargate": "^0.29.4",
@ -27,6 +29,7 @@
"ethereumjs-util": "^7.1.5",
"graphql": "^16.6.0",
"graphql-request": "^5.0.0",
"moment": "^2.29.4",
"next": "12.3.1",
"react": "18.2.0",
"react-dom": "18.2.0",
@ -34,13 +37,14 @@
"react-spring": "^9.5.5",
"react-toastify": "^9.0.8",
"react-use-clipboard": "^1.0.9",
"recharts": "^2.2.0",
"tailwindcss-border-gradient-radius": "^3.0.1",
"use-local-storage-state": "^18.1.1",
"zustand": "^4.1.4"
},
"devDependencies": {
"@svgr/webpack": "^6.4.0",
"@types/node": "18.11.11",
"@types/node": "^18.11.13",
"@types/react": "18.0.26",
"@types/react-dom": "18.0.9",
"autoprefixer": "^10.4.13",
@ -51,6 +55,7 @@
"prettier": "^2.7.1",
"prettier-plugin-tailwindcss": "^0.1.13",
"tailwindcss": "^3.2.1",
"typescript": "4.8.2"
"typescript": "4.8.2",
"vscode-generate-index-standalone": "^1.6.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
public/images/fund-bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
public/images/fund-bg.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

View File

@ -0,0 +1,111 @@
import classNames from 'classnames'
import { useEffect, useState } from 'react'
import { Button, LabelValuePair, PositionsList } from 'components'
import { AccountManageOverlay, RiskChart } from 'components/Account'
import { ArrowRightLine, ChevronDown, ChevronLeft } from 'components/Icons'
import { useAccountStats, useBalances } from 'hooks/data'
import { useAccountDetailsStore, useSettings } from 'stores'
import { chain } from 'utils/chains'
import { lookup } from 'utils/formatters'
import { createRiskData } from 'utils/risk'
export const AccountDetails = () => {
const enableAnimations = useSettings((s) => s.enableAnimations)
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
const isOpen = useAccountDetailsStore((s) => s.isOpen)
const balances = useBalances()
const accountStats = useAccountStats()
const [showManageMenu, setShowManageMenu] = useState(false)
const [riskData, setRiskData] = useState<RiskTimePair[]>()
useEffect(() => {
setRiskData(createRiskData(accountStats?.risk ?? 0))
}, [accountStats?.risk, selectedAccount])
return (
<div
className={classNames(
'relative flex w-[400px] basis-[400px] flex-wrap content-start border-white/20 bg-header',
enableAnimations && 'transition-[margin] duration-1000 ease-in-out',
isOpen ? 'mr-0' : '-mr-[400px]',
)}
>
<Button
onClick={() => {
useAccountDetailsStore.setState({ isOpen: true })
}}
variant='text'
className={classNames(
'absolute top-1/2 -left-[20px] w-[21px] -translate-y-1/2 bg-header p-0',
'rounded-none rounded-tl-sm rounded-bl-sm',
'border border-white/20',
enableAnimations && 'transition-[opacity] delay-1000 duration-500 ease-in-out',
isOpen ? 'pointer-events-none opacity-0' : 'opacity-100',
)}
>
<span
className={classNames(
'flex h-20 px-1 py-6 text-white/40 hover:text-white',
enableAnimations && 'transition-[color]',
)}
>
<ChevronLeft />
</span>
</Button>
<div className='relative flex w-full flex-wrap items-center border-b border-white/20'>
<Button
variant='text'
className='flex flex-grow flex-nowrap items-center justify-center p-4 text-center text-white text-xl-caps'
onClick={() => setShowManageMenu(!showManageMenu)}
>
Account {selectedAccount}
<span className='ml-2 flex w-4'>
<ChevronDown />
</span>
</Button>
<div className='flex border-l border-white/20' onClick={() => {}}>
<Button
variant='text'
className={classNames(
'w-14 p-4 text-white/40 hover:cursor-pointer hover:text-white',
enableAnimations && 'transition-[color]',
)}
onClick={() => {
useAccountDetailsStore.setState({ isOpen: false })
}}
>
<ArrowRightLine />
</Button>
</div>
<AccountManageOverlay
className='top-[60px] left-[36px]'
show={showManageMenu}
setShow={setShowManageMenu}
/>
</div>
<div className='flex w-full flex-wrap p-3'>
<LabelValuePair
className='mb-2'
label='Total Position:'
value={{
format: 'number',
amount: lookup(accountStats?.totalPosition ?? 0, chain.stakeCurrency.coinDenom),
prefix: '$',
}}
/>
<LabelValuePair
label='Total Liabilities:'
value={{
format: 'number',
amount: lookup(accountStats?.totalDebt ?? 0, chain.stakeCurrency.coinDenom),
prefix: '$',
}}
/>
</div>
{riskData && <RiskChart data={riskData} />}
<PositionsList title='Balances' data={balances} />
</div>
)
}

View File

@ -1,16 +1,9 @@
import { useEffect } from 'react'
import Button from 'components/Button'
import PlusIcon from 'components/Icons/add.svg'
import ArrowDown from 'components/Icons/arrow-down.svg'
import ArrowUp from 'components/Icons/arrow-up.svg'
import ArrowsLeftRight from 'components/Icons/arrows-left-right.svg'
import DeleteIcon from 'components/Icons/rubbish.svg'
import Overlay from 'components/Overlay/Overlay'
import OverlayAction from 'components/Overlay/OverlayLink'
import Text from 'components/Text'
import useCreateCreditAccount from 'hooks/mutations/useCreateCreditAccount'
import useDeleteCreditAccount from 'hooks/mutations/useDeleteCreditAccount'
import { Button, Text } from 'components'
import { Add, ArrowDown, ArrowsLeftRight, ArrowUp, Rubbish } from 'components/Icons'
import { Overlay, OverlayAction } from 'components/Overlay'
import { useCreateCreditAccount, useDeleteCreditAccount } from 'hooks/mutations'
import { useAccountDetailsStore, useModalStore } from 'stores'
interface Props {
@ -19,7 +12,7 @@ interface Props {
show: boolean
}
const AccountManageOverlay = ({ className, setShow, show }: Props) => {
export const AccountManageOverlay = ({ className, setShow, show }: Props) => {
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
const { mutate: createCreditAccount, isLoading: isLoadingCreate } = useCreateCreditAccount()
@ -73,13 +66,13 @@ const AccountManageOverlay = ({ className, setShow, show }: Props) => {
setShow={setShow}
text='Create New Account'
onClick={createCreditAccount}
icon={<PlusIcon />}
icon={<Add />}
/>
<OverlayAction
setShow={setShow}
text='Close Account'
onClick={deleteCreditAccount}
icon={<DeleteIcon />}
icon={<Rubbish />}
/>
<OverlayAction
setShow={setShow}
@ -92,5 +85,3 @@ const AccountManageOverlay = ({ className, setShow, show }: Props) => {
</Overlay>
)
}
export default AccountManageOverlay

View File

@ -1,12 +1,11 @@
import classNames from 'classnames'
import { useMemo, useState } from 'react'
import Button from 'components/Button'
import ChevronDownIcon from 'components/Icons/chevron-down.svg'
import Overlay from 'components/Overlay/Overlay'
import { Button } from 'components'
import { ChevronDown } from 'components/Icons'
import { Overlay } from 'components/Overlay'
import { useAccountDetailsStore } from 'stores'
import AccountManageOverlay from './AccountManageOverlay'
import { AccountManageOverlay } from 'components/Account'
interface Props {
creditAccountsList: string[]
@ -15,7 +14,7 @@ interface Props {
const MAX_VISIBLE_CREDIT_ACCOUNTS = 5
const AccountNavigation = ({ creditAccountsList, selectedAccount }: Props) => {
export const AccountNavigation = ({ creditAccountsList, selectedAccount }: Props) => {
const { firstCreditAccounts, restCreditAccounts } = useMemo(() => {
return {
firstCreditAccounts: creditAccountsList?.slice(0, MAX_VISIBLE_CREDIT_ACCOUNTS) ?? [],
@ -53,7 +52,7 @@ const AccountNavigation = ({ creditAccountsList, selectedAccount }: Props) => {
>
More
<span className='ml-1 inline-block w-3'>
<ChevronDownIcon />
<ChevronDown />
</span>
</Button>
<Overlay show={showMoreMenu} setShow={setShowMoreMenu}>
@ -92,7 +91,7 @@ const AccountNavigation = ({ creditAccountsList, selectedAccount }: Props) => {
>
Manage
<span className='ml-1 inline-block w-3'>
<ChevronDownIcon />
<ChevronDown />
</span>
</Button>
@ -105,5 +104,3 @@ const AccountNavigation = ({ creditAccountsList, selectedAccount }: Props) => {
</>
)
}
export default AccountNavigation

View File

@ -1,19 +1,16 @@
import BigNumber from 'bignumber.js'
import { useEffect } from 'react'
import { Button, FormattedNumber, Gauge, Text } from 'components'
import { BorrowCapacity } from 'components/BorrowCapacity'
import Button from 'components/Button'
import FormattedNumber from 'components/FormattedNumber'
import Gauge from 'components/Gauge'
import Text from 'components/Text'
import useCreateCreditAccount from 'hooks/mutations/useCreateCreditAccount'
import useAccountStats from 'hooks/useAccountStats'
import useCreditAccounts from 'hooks/useCreditAccounts'
import { useAccountStats } from 'hooks/data'
import { useCreateCreditAccount } from 'hooks/mutations'
import { useCreditAccounts } from 'hooks/queries'
import { useModalStore } from 'stores'
import { chain } from 'utils/chains'
import { formatValue } from 'utils/formatters'
const AccountStatus = () => {
export const AccountStatus = () => {
const accountStats = useAccountStats()
const { data: creditAccountsList } = useCreditAccounts()
const { mutate: createCreditAccount, isLoading: isLoadingCreate } = useCreateCreditAccount()
@ -81,4 +78,3 @@ const AccountStatus = () => {
</div>
)
}
export default AccountStatus

View File

@ -0,0 +1,36 @@
import classNames from 'classnames'
import { CircularProgress, Modal, Text } from 'components'
import { MarsProtocol } from 'components/Icons'
import { useModalStore } from 'stores'
export const ConfirmModal = () => {
const createOpen = useModalStore((s) => s.createAccountModal)
const deleteOpen = useModalStore((s) => s.deleteAccountModal)
return (
<Modal open={createOpen || deleteOpen}>
<div
className={classNames(
'relative flex h-[630px] w-full flex-wrap items-center justify-center p-6',
createOpen && 'bg-create-modal',
deleteOpen && 'bg-delete-modal',
)}
>
<div className='w-full flex-wrap'>
<div className='flex w-full justify-center pb-6'>
<CircularProgress size={40} />
</div>
<Text size='2xl' uppercase={true} className='w-full text-center'>
{createOpen &&
'A small step for a Smart Contracts but a big leap for your financial freedom.'}
{deleteOpen && 'Some rovers have to be recycled once in a while...'}
</Text>
</div>
<div className='absolute bottom-8 left-8 flex w-[150px]'>
<MarsProtocol />
</div>
</div>
</Modal>
)
}

View File

@ -4,19 +4,14 @@ import { useEffect, useMemo, useState } from 'react'
import { toast } from 'react-toastify'
import useLocalStorageState from 'use-local-storage-state'
import Button from 'components/Button'
import CircularProgress from 'components/CircularProgress'
import MarsProtocolLogo from 'components/Icons/mars-protocol.svg'
import Modal from 'components/Modal'
import Slider from 'components/Slider'
import Text from 'components/Text'
import useDepositCreditAccount from 'hooks/mutations/useDepositCreditAccount'
import useAllBalances from 'hooks/useAllBalances'
import useAllowedCoins from 'hooks/useAllowedCoins'
import { Button, CircularProgress, Modal, Slider, Text } from 'components'
import { MarsProtocol } from 'components/Icons'
import { useDepositCreditAccount } from 'hooks/mutations'
import { useAllBalances, useAllowedCoins } from 'hooks/queries'
import { useAccountDetailsStore, useModalStore } from 'stores'
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
const FundAccountModal = () => {
export const FundAccountModal = () => {
// ---------------
// STORE
// ---------------
@ -105,7 +100,7 @@ const FundAccountModal = () => {
</Text>
</div>
<div className='w-[153px] text-white'>
<MarsProtocolLogo />
<MarsProtocol />
</div>
</div>
@ -202,7 +197,7 @@ const FundAccountModal = () => {
<span
className={`${
lendAssets ? 'translate-x-6' : 'translate-x-1'
} inline-block h-4 w-4 transform rounded-full bg-white transition`}
} inline-block h-4 w-4 transform rounded-full bg-white`}
/>
</Switch>
</div>
@ -218,5 +213,3 @@ const FundAccountModal = () => {
</Modal>
)
}
export default FundAccountModal

View File

@ -0,0 +1,97 @@
import moment from 'moment'
import {
Area,
AreaChart,
CartesianGrid,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts'
import { FormattedNumber, Text } from 'components'
import { useAccountStats } from 'hooks/data'
import { useSettings } from 'stores'
import { formatValue } from 'utils/formatters'
export const RiskChart = ({ data }: RiskChartProps) => {
const enableAnimations = useSettings((s) => s.enableAnimations)
const accountStats = useAccountStats()
const currentRisk = accountStats?.risk ?? 0
return (
<div className='flex w-full flex-wrap overflow-hidden py-2'>
<FormattedNumber
className='px-3 pb-2 text-lg'
amount={currentRisk * 100}
maxDecimals={0}
minDecimals={0}
animate
prefix='Risk Score: '
suffix='/100'
/>
<div className='-ml-6 h-[100px] w-[412px]'>
<ResponsiveContainer width='100%' height='100%'>
<AreaChart
data={data}
margin={{
top: 0,
right: 0,
left: 0,
bottom: 0,
}}
>
<defs>
<linearGradient id='chartGradient' x1='0' y1='0' x2='0' y2='1'>
<stop offset='0%' stopColor={'#FFFFFF'} stopOpacity={0.2} />
<stop offset='100%' stopColor={'#FFFFFF'} stopOpacity={0.02} />
</linearGradient>
</defs>
<CartesianGrid
strokeDasharray='0'
horizontalPoints={[0, 20, 40, 60, 80, 100]}
vertical={false}
stroke='rgba(255,255,255,0.1)'
/>
<XAxis
stroke='rgba(255, 255, 255, 0.6)'
tickLine={false}
tickFormatter={(value) => {
return moment(value).format('DD')
}}
fontSize={10.53}
dataKey='date'
/>
<YAxis
ticks={[0, 20, 40, 60, 80, 100]}
tickLine={false}
fontSize={10.53}
stroke='rgba(255, 255, 255, 0.6)'
/>
<Tooltip
wrapperStyle={{ outline: 'none' }}
content={({ payload, label }) => {
if (payload && payload.length) {
const risk = Number(payload[0].value) ?? 0
return (
<div className='max-w-[320px] rounded-lg px-4 py-2 shadow-tooltip gradient-tooltip '>
<Text size='sm'>{moment(label).format('MM-DD-YYYY')}</Text>
<Text size='sm'>Risk: {formatValue(risk, 0, 0, true, false, '%')}</Text>
</div>
)
}
}}
/>
<Area
type='monotone'
dataKey='risk'
stroke='#FFFFFF'
fill='url(#chartGradient)'
isAnimationActive={enableAnimations}
/>
</AreaChart>
</ResponsiveContainer>
</div>
</div>
)
}

View File

@ -4,27 +4,27 @@ import classNames from 'classnames'
import React, { useEffect, useMemo, useState } from 'react'
import { toast } from 'react-toastify'
import {
Button,
CircularProgress,
FormattedNumber,
Gauge,
LabelValuePair,
Modal,
PositionsList,
Slider,
Text,
} from 'components'
import { BorrowCapacity } from 'components/BorrowCapacity'
import Button from 'components/Button'
import CircularProgress from 'components/CircularProgress'
import FormattedNumber from 'components/FormattedNumber'
import Gauge from 'components/Gauge'
import Modal from 'components/Modal'
import Slider from 'components/Slider'
import Text from 'components/Text'
import useWithdrawFunds from 'hooks/mutations/useWithdrawFunds'
import useAccountStats, { AccountStatsAction } from 'hooks/useAccountStats'
import useAllBalances from 'hooks/useAllBalances'
import useCalculateMaxWithdrawAmount from 'hooks/useCalculateMaxWithdrawAmount'
import useCreditAccountPositions from 'hooks/useCreditAccountPositions'
import useMarkets from 'hooks/useMarkets'
import useTokenPrices from 'hooks/useTokenPrices'
import { useAccountStats, useBalances, useCalculateMaxWithdrawAmount } from 'hooks/data'
import { useWithdrawFunds } from 'hooks/mutations'
import { useCreditAccountPositions, useTokenPrices } from 'hooks/queries'
import { useAccountDetailsStore, useModalStore } from 'stores'
import { chain } from 'utils/chains'
import { formatValue } from 'utils/formatters'
import { formatValue, lookup } from 'utils/formatters'
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
const WithdrawModal = () => {
export const WithdrawModal = () => {
// ---------------
// STORE
// ---------------
@ -45,9 +45,8 @@ const WithdrawModal = () => {
// ---------------
// EXTERNAL HOOKS
// ---------------
const { data: balancesData } = useAllBalances()
const { data: tokenPrices } = useTokenPrices()
const { data: marketsData } = useMarkets()
const balances = useBalances()
const selectedTokenSymbol = getTokenSymbol(selectedToken)
const selectedTokenDecimals = getTokenDecimals(selectedToken)
@ -100,14 +99,6 @@ const WithdrawModal = () => {
const maxWithdrawAmount = useCalculateMaxWithdrawAmount(selectedToken, isBorrowEnabled)
const walletAmount = useMemo(() => {
if (!selectedToken) return 0
return BigNumber(balancesData?.find((balance) => balance.denom === selectedToken)?.amount ?? 0)
.div(10 ** selectedTokenDecimals)
.toNumber()
}, [balancesData, selectedToken, selectedTokenDecimals])
useEffect(() => {
if (positionsData && positionsData.coins.length > 0) {
// initialize selected token when allowedCoins fetch data is available
@ -248,7 +239,7 @@ const WithdrawModal = () => {
<span
className={`${
isBorrowEnabled ? 'translate-x-6' : 'translate-x-1'
} inline-block h-4 w-4 transform rounded-full bg-white transition`}
} inline-block h-4 w-4 transform rounded-full bg-white`}
/>
</Switch>
</div>
@ -310,130 +301,28 @@ const WithdrawModal = () => {
)}
</div>
<div className='flex w-full flex-wrap border-b border-white/20 p-6'>
<div className='mb-2 flex w-full'>
<Text size='xs' className='flex-grow text-white/60'>
Total Position:
</Text>
<Text size='xs' className='text-white/60'>
<FormattedNumber
amount={BigNumber(accountStats?.totalPosition ?? 0)
.dividedBy(10 ** chain.stakeCurrency.coinDecimals)
.toNumber()}
prefix='$'
animate
/>
</Text>
</div>
<div className='flex w-full justify-between'>
<Text size='xs' className='flex-grow text-white/60'>
Total Liabilities:
</Text>
<Text size='xs' className=' text-white/60'>
<FormattedNumber
amount={BigNumber(accountStats?.totalDebt ?? 0)
.dividedBy(10 ** chain.stakeCurrency.coinDecimals)
.toNumber()}
prefix='$'
animate
/>
</Text>
</div>
</div>
<div className='flex w-full flex-wrap'>
<Text uppercase className='w-full bg-black/20 px-6 py-2 text-white/40'>
Balances
</Text>
{isLoadingPositions ? (
<div>Loading...</div>
) : (
<div className='flex w-full flex-wrap'>
<div className='mb-2 flex w-full border-b border-white/20 bg-black/20 px-6 py-2 '>
<Text size='xs' uppercase className='flex-1 text-white'>
Asset
</Text>
<Text size='xs' uppercase className='flex-1 text-white'>
Value
</Text>
<Text size='xs' uppercase className='flex-1 text-white'>
Size
</Text>
<Text size='xs' uppercase className='flex-1 text-white'>
APY
</Text>
</div>
{positionsData?.coins.map((coin) => (
<div key={coin.denom} className='flex w-full px-4 py-2'>
<Text
size='xs'
className='flex-1 border-l-4 border-profit pl-2 text-white/60'
>
{getTokenSymbol(coin.denom)}
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={getTokenTotalUSDValue(coin.amount, coin.denom)}
prefix='$'
animate
/>
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={BigNumber(coin.amount)
.div(10 ** getTokenDecimals(coin.denom))
.toNumber()}
minDecimals={0}
maxDecimals={4}
animate
/>
</Text>
<Text size='xs' className='flex-1 text-white/60'>
-
</Text>
</div>
))}
{positionsData?.debts.map((coin) => (
<div key={coin.denom} className='flex w-full px-4 py-2'>
<Text size='xs' className='flex-1 border-l-4 border-loss pl-2 text-white/60'>
{getTokenSymbol(coin.denom)}
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={getTokenTotalUSDValue(coin.amount, coin.denom)}
prefix='-$'
animate
/>
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={BigNumber(coin.amount)
.div(10 ** getTokenDecimals(coin.denom))
.toNumber()}
minDecimals={0}
maxDecimals={4}
animate
/>
</Text>
<Text size='xs' className='flex-1 text-white/60'>
<FormattedNumber
amount={Number(marketsData?.[coin.denom].borrow_rate) * 100}
minDecimals={0}
maxDecimals={2}
prefix='-'
suffix='%'
animate
/>
</Text>
</div>
))}
</div>
)}
<LabelValuePair
className='mb-2'
label='Total Position:'
value={{
format: 'number',
amount: lookup(accountStats?.totalPosition ?? 0, chain.stakeCurrency.coinDenom),
prefix: '$',
}}
/>
<LabelValuePair
label='Total Liabilities:'
value={{
format: 'number',
amount: lookup(accountStats?.totalDebt ?? 0, chain.stakeCurrency.coinDenom),
prefix: '$',
}}
/>
</div>
<PositionsList title='Balances' data={balances} />
</div>
</div>
</div>
</Modal>
)
}
export default WithdrawModal

View File

@ -0,0 +1,10 @@
// @index(['./*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
export { AccountDetails } from './AccountDetails'
export { AccountManageOverlay } from './AccountManageOverlay'
export { AccountNavigation } from './AccountNavigation'
export { AccountStatus } from './AccountStatus'
export { ConfirmModal } from './ConfirmModal'
export { FundAccountModal } from './FundAccountModal'
export { RiskChart } from './RiskChart'
export { WithdrawModal } from './WithdrawModal'
// @endindex

View File

@ -1,9 +1,8 @@
import Image from 'next/image'
import React, { useState } from 'react'
import ChevronUpIcon from 'components/Icons/chevron-up.svg'
import ChevronDownIcon from 'components/Icons/chevron-down.svg'
import Button from 'components/Button'
import { Button } from 'components'
import { ChevronDown, ChevronUp } from 'components/Icons'
import { formatCurrency } from 'utils/formatters'
type AssetRowProps = {
@ -23,7 +22,7 @@ type AssetRowProps = {
onRepayClick: () => void
}
const AssetRow = ({ data, onBorrowClick, onRepayClick }: AssetRowProps) => {
export const AssetRow = ({ data, onBorrowClick, onRepayClick }: AssetRowProps) => {
const [isExpanded, setIsExpanded] = useState(false)
return (
@ -54,7 +53,7 @@ const AssetRow = ({ data, onBorrowClick, onRepayClick }: AssetRowProps) => {
</div>
<div className='flex flex-1 items-center text-xs'>{data.marketLiquidity}</div>
<div className='flex w-[50px] items-center justify-end'>
<div className='w-5'>{isExpanded ? <ChevronUpIcon /> : <ChevronDownIcon />}</div>
<div className='w-5'>{isExpanded ? <ChevronUp /> : <ChevronDown />}</div>
</div>
</div>
{isExpanded && (
@ -84,5 +83,3 @@ const AssetRow = ({ data, onBorrowClick, onRepayClick }: AssetRowProps) => {
</div>
)
}
export default AssetRow

View File

@ -9,11 +9,9 @@ import {
import Image from 'next/image'
import React from 'react'
import ChevronUpIcon from 'components/Icons/chevron-up.svg'
import ChevronDownIcon from 'components/Icons/chevron-down.svg'
import { ChevronDown, ChevronUp } from 'components/Icons'
import { formatCurrency } from 'utils/formatters'
import AssetRow from './AssetRow'
import { AssetRow } from 'components/Borrow'
interface Market {
denom: string
@ -34,7 +32,7 @@ type Props = {
onRepayClick: (denom: string) => void
}
const BorrowTable = ({ data, onBorrowClick, onRepayClick }: Props) => {
export const BorrowTable = ({ data, onBorrowClick, onRepayClick }: Props) => {
const [sorting, setSorting] = React.useState<SortingState>([])
const columns = React.useMemo<ColumnDef<Market>[]>(
@ -91,9 +89,7 @@ const BorrowTable = ({ data, onBorrowClick, onRepayClick }: Props) => {
width: 150,
cell: ({ row }) => (
<div className='flex items-center justify-end'>
<div className='w-5'>
{row.getIsExpanded() ? <ChevronUpIcon /> : <ChevronDownIcon />}
</div>
<div className='w-5'>{row.getIsExpanded() ? <ChevronUp /> : <ChevronDown />}</div>
</div>
),
},
@ -158,5 +154,3 @@ const BorrowTable = ({ data, onBorrowClick, onRepayClick }: Props) => {
</div>
)
}
export default BorrowTable

View File

@ -0,0 +1,4 @@
// @index(['./**/*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
export { AssetRow } from './AssetRow'
export { BorrowTable } from './BorrowTable'
// @endindex

View File

@ -1,9 +1,8 @@
import classNames from 'classnames'
import { useEffect, useState } from 'react'
import FormattedNumber from 'components/FormattedNumber'
import Text from 'components/Text'
import Tooltip from 'components/Tooltip'
import { FormattedNumber, Text, Tooltip } from 'components'
import { useSettings } from 'stores'
interface Props {
balance: number
@ -28,26 +27,25 @@ export const BorrowCapacity = ({
hideValues,
decimals = 2,
}: Props) => {
const enableAnimations = useSettings((s) => s.enableAnimations)
const [percentOfMaxRound, setPercentOfMaxRound] = useState(0)
const [percentOfMaxRange, setPercentOfMaxRange] = useState(0)
const [limitPercentOfMax, setLimitPercentOfMax] = useState(0)
useEffect(
() => {
if (max === 0) {
setPercentOfMaxRound(0)
setPercentOfMaxRange(0)
setLimitPercentOfMax(0)
return
}
useEffect(() => {
if (max === 0) {
setPercentOfMaxRound(0)
setPercentOfMaxRange(0)
setLimitPercentOfMax(0)
return
}
const pOfMax = +((balance / max) * 100)
setPercentOfMaxRound(+(Math.round(pOfMax * 100) / 100))
setPercentOfMaxRange(Math.min(Math.max(pOfMax, 0), 100))
setLimitPercentOfMax((limit / max) * 100)
}, // eslint-disable-next-line react-hooks/exhaustive-deps
[balance, max],
)
const pOfMax = +((balance / max) * 100)
setPercentOfMaxRound(+(Math.round(pOfMax * 100) / 100))
setPercentOfMaxRange(Math.min(Math.max(pOfMax, 0), 100))
setLimitPercentOfMax((limit / max) * 100)
}, [balance, max, limit])
return (
<div className={classNames('flex items-center justify-center', className)}>
@ -63,7 +61,8 @@ export const BorrowCapacity = ({
{!hideValues && (
<div
className={classNames(
'duration-800 transition-[opcity] delay-[1600ms] text-3xs-caps',
enableAnimations && 'duration-800 transition-[opcity] delay-[1600ms]',
'text-3xs-caps',
limitPercentOfMax ? 'opacity-60' : 'opacity-0',
)}
>
@ -79,7 +78,10 @@ export const BorrowCapacity = ({
>
<div className='absolute h-full w-full rounded-lg shadow-inset gradient-hatched '>
<div
className='ease-loss absolute left-0 h-full max-w-full rounded-l-3xl bg-body-dark transition-[right] duration-1000'
className={classNames(
'absolute left-0 h-full max-w-full rounded-l-3xl bg-body-dark',
enableAnimations && 'transition-[right] duration-1000 ease-linear',
)}
style={{
right: `${limitPercentOfMax ? 100 - limitPercentOfMax : 100}%`,
}}
@ -87,7 +89,10 @@ export const BorrowCapacity = ({
<div className='absolute top-0 h-full w-full'>
<div
className='h-full rounded-lg transition-[width] duration-1000 ease-linear'
className={classNames(
'h-full rounded-lg',
enableAnimations && 'transition-[width] duration-1000 ease-linear',
)}
style={{
width: `${percentOfMaxRange || 0.02}%`,
WebkitMask: 'linear-gradient(#fff 0 0)',
@ -97,11 +102,19 @@ export const BorrowCapacity = ({
</div>
<div
className='absolute bottom-0 h-[120%] w-[1px] bg-white transition-[left] duration-1000 ease-linear'
className={classNames(
'absolute bottom-0 h-[120%] w-[1px] bg-white',
enableAnimations && 'transition-[left] duration-1000 ease-linear',
)}
style={{ left: `${limitPercentOfMax || 0}%` }}
/>
{showPercentageText ? (
<span className='absolute top-1/2 mt-[1px] w-full -translate-y-1/2 animate-fadein text-center opacity-0 text-2xs-caps'>
<span
className={classNames(
'absolute top-1/2 mt-[1px] w-full -translate-y-1/2 text-center text-2xs-caps',
enableAnimations && 'animate-fadein opacity-0',
)}
>
{max !== 0 && (
<FormattedNumber
className='text-white'

View File

@ -4,21 +4,20 @@ import React, { useMemo, useState } from 'react'
import { NumericFormat } from 'react-number-format'
import { toast } from 'react-toastify'
import Button from 'components/Button'
import CircularProgress from 'components/CircularProgress'
import ContainerSecondary from 'components/ContainerSecondary'
import Gauge from 'components/Gauge'
import ProgressBar from 'components/ProgressBar'
import Slider from 'components/Slider'
import Text from 'components/Text'
import Tooltip from 'components/Tooltip'
import useBorrowFunds from 'hooks/mutations/useBorrowFunds'
import useAccountStats, { AccountStatsAction } from 'hooks/useAccountStats'
import useAllBalances from 'hooks/useAllBalances'
import useCalculateMaxBorrowAmount from 'hooks/useCalculateMaxBorrowAmount'
import useCreditAccountPositions from 'hooks/useCreditAccountPositions'
import useMarkets from 'hooks/useMarkets'
import useTokenPrices from 'hooks/useTokenPrices'
import {
Button,
CircularProgress,
ContainerSecondary,
Gauge,
PositionsList,
ProgressBar,
Slider,
Text,
Tooltip,
} from 'components'
import { useAccountStats, useBalances, useCalculateMaxBorrowAmount } from 'hooks/data'
import { useBorrowFunds } from 'hooks/mutations'
import { useAllBalances, useMarkets, useTokenPrices } from 'hooks/queries'
import { useAccountDetailsStore } from 'stores'
import { chain } from 'utils/chains'
import { formatCurrency, formatValue } from 'utils/formatters'
@ -30,14 +29,13 @@ type Props = {
tokenDenom: string
}
const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
export const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
const [amount, setAmount] = useState(0)
const [isBorrowToCreditAccount, setIsBorrowToCreditAccount] = useState(false)
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
const { data: positionsData, isLoading: isLoadingPositions } = useCreditAccountPositions(
selectedAccount ?? '',
)
const balances = useBalances()
const { actions, borrowAmount } = useMemo(() => {
const borrowAmount = BigNumber(amount)
@ -124,17 +122,6 @@ const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
setAmount(0)
}
const getTokenTotalUSDValue = (amount: string, denom: string) => {
// early return if prices are not fetched yet
if (!tokenPrices) return 0
return (
BigNumber(amount)
.div(10 ** getTokenDecimals(denom))
.toNumber() * tokenPrices[denom]
)
}
return (
<Transition appear show={show} as={React.Fragment}>
<Dialog as='div' className='relative z-10' onClose={onClose}>
@ -310,62 +297,7 @@ const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
</div>
</div>
</div>
<div className='rounded-md border border-white/20 p-3'>
<h4 className='mb-2 font-bold'>Balances</h4>
{isLoadingPositions ? (
<div>Loading...</div>
) : (
<table className='w-full border-separate border-spacing-1'>
<thead className='text-left text-xs font-semibold'>
<tr>
<th>Asset</th>
<th>Value</th>
<th>Size</th>
<th className='text-right'>APY</th>
</tr>
</thead>
<tbody>
{accountStats?.assets.map((coin) => (
<tr key={coin.denom} className='text-xs text-white/50'>
<td>{getTokenSymbol(coin.denom)}</td>
<td>
{formatCurrency(getTokenTotalUSDValue(coin.amount, coin.denom))}
</td>
<td>
{BigNumber(coin.amount)
.div(10 ** getTokenDecimals(coin.denom))
.toNumber()
.toLocaleString(undefined, {
maximumFractionDigits: getTokenDecimals(coin.denom),
})}
</td>
<td className='text-right'>-</td>
</tr>
))}
{accountStats?.debts.map((coin) => (
<tr key={coin.denom} className='text-xs text-red-500'>
<td className='text-white/50'>{getTokenSymbol(coin.denom)}</td>
<td>
-{formatCurrency(getTokenTotalUSDValue(coin.amount, coin.denom))}
</td>
<td>
-
{BigNumber(coin.amount)
.div(10 ** getTokenDecimals(coin.denom))
.toNumber()
.toLocaleString(undefined, {
maximumFractionDigits: 6,
})}
</td>
<td className='text-right'>
-{(Number(marketsData?.[coin.denom].borrow_rate) * 100).toFixed(1)}%
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
<PositionsList title='Balances' data={balances} />
</div>
</Dialog.Panel>
</Transition.Child>
@ -375,5 +307,3 @@ const BorrowModal = ({ show, onClose, tokenDenom }: Props) => {
</Transition>
)
}
export default BorrowModal

View File

@ -1,7 +1,8 @@
import classNames from 'classnames'
import React, { LegacyRef, ReactNode } from 'react'
import CircularProgress from 'components/CircularProgress'
import { CircularProgress } from 'components'
import { useSettings } from 'stores'
interface Props {
children?: string | ReactNode
@ -57,7 +58,7 @@ export const buttonVariantClasses = {
text: 'border-none bg-transparent',
}
const Button = React.forwardRef(function Button(
export const Button = React.forwardRef(function Button(
{
children,
className = '',
@ -73,6 +74,7 @@ const Button = React.forwardRef(function Button(
ref,
) {
const buttonClasses = []
const enableAnimations = useSettings((s) => s.enableAnimations)
switch (variant) {
case 'round':
@ -96,7 +98,8 @@ const Button = React.forwardRef(function Button(
return (
<button
className={classNames(
'cursor-pointer appearance-none break-normal rounded-3xl outline-none transition-colors',
'outline-nones cursor-pointer appearance-none break-normal rounded-3xl',
enableAnimations && 'transition-color',
buttonClasses,
buttonVariantClasses[variant],
disabled && 'pointer-events-none opacity-50',
@ -114,5 +117,3 @@ const Button = React.forwardRef(function Button(
</button>
)
})
export default Button

View File

@ -6,7 +6,7 @@ interface Props {
className?: string
}
const Card = ({ children, className }: Props) => {
export const Card = ({ children, className }: Props) => {
return (
<div
className={classNames(
@ -18,5 +18,3 @@ const Card = ({ children, className }: Props) => {
</div>
)
}
export default Card

View File

@ -1,18 +1,32 @@
import classNames from 'classnames'
import { Text } from 'components'
import { useSettings } from 'stores'
interface Props {
color?: string
size?: number
className?: string
}
const CircularProgress = ({ color = '#FFFFFF', size = 20, className }: Props) => {
export const CircularProgress = ({ color = '#FFFFFF', size = 20, className }: Props) => {
const enableAnimations = useSettings((s) => s.enableAnimations)
const borderWidth = `${size / 10}px`
const borderColor = `${color} transparent transparent transparent`
const loaderClasses = classNames('inline-block relative', className)
const elementClasses =
'block absolute w-4/5 h-4/5 m-[10%] rounded-full animate-progress border-solid'
if (!enableAnimations)
return (
<div className={loaderClasses} style={{ width: `${size}px`, height: `${size}px` }}>
<Text className='text-center' uppercase size='lg'>
...
</Text>
</div>
)
return (
<div className={loaderClasses} style={{ width: `${size}px`, height: `${size}px` }}>
<div
@ -49,5 +63,3 @@ const CircularProgress = ({ color = '#FFFFFF', size = 20, className }: Props) =>
</div>
)
}
export default CircularProgress

View File

@ -1,6 +1,6 @@
import React from 'react'
const ContainerSecondary = ({
export const ContainerSecondary = ({
children,
className,
}: {
@ -13,5 +13,3 @@ const ContainerSecondary = ({
</div>
)
}
export default ContainerSecondary

View File

@ -0,0 +1,66 @@
import classNames from 'classnames'
import React, { useEffect, useRef } from 'react'
import { animated, useSpring } from 'react-spring'
import { useSettings } from 'stores'
import { formatValue } from 'utils/formatters'
export const FormattedNumber = React.memo(
({
amount,
animate = false,
className,
minDecimals = 2,
maxDecimals = 2,
thousandSeparator = true,
prefix = false,
suffix = false,
rounded = false,
abbreviated = false,
}: FormattedNumberProps) => {
const enableAnimations = useSettings((s) => s.enableAnimations)
const prevAmountRef = useRef<number>(0)
useEffect(() => {
if (prevAmountRef.current !== Number(amount)) prevAmountRef.current = Number(amount)
}, [amount])
const springAmount = useSpring({
number: Number(amount),
from: { number: prevAmountRef.current },
config: { duration: 1000 },
})
return (prevAmountRef.current === amount && amount === 0) || !animate || !enableAnimations ? (
<span className={classNames('number', className)}>
{formatValue(
amount,
minDecimals,
maxDecimals,
thousandSeparator,
prefix,
suffix,
rounded,
abbreviated,
)}
</span>
) : (
<animated.span className={classNames('number', className)}>
{springAmount.number.to((num) =>
formatValue(
num,
minDecimals,
maxDecimals,
thousandSeparator,
prefix,
suffix,
rounded,
abbreviated,
),
)}
</animated.span>
)
},
)
FormattedNumber.displayName = 'FormattedNumber'

View File

@ -1,9 +1,10 @@
import classNames from 'classnames'
import { ReactNode } from 'react'
import Tooltip from './Tooltip'
import { Tooltip } from 'components'
import { useSettings } from 'stores'
type Props = {
interface Props {
tooltip: string | ReactNode
strokeWidth?: number
background?: string
@ -12,7 +13,15 @@ type Props = {
label?: string
}
const Gauge = ({ background = '#15161A', diameter = 40, value = 0, label, tooltip }: Props) => {
export const Gauge = ({
background = '#15161A',
diameter = 40,
value = 0,
label,
tooltip,
}: Props) => {
const enableAnimations = useSettings((s) => s.enableAnimations)
const percentage = value * 100
const percentageValue = percentage > 100 ? 100 : percentage < 0 ? 0 : percentage
const semiCirclePercentage = Math.abs(percentageValue / 2 - 50)
@ -59,7 +68,7 @@ const Gauge = ({ background = '#15161A', diameter = 40, value = 0, label, toolti
strokeWidth={5}
style={{
strokeDashoffset: semiCirclePercentage,
transition: 'stroke-dashoffset 1s ease',
transition: enableAnimations ? 'stroke-dashoffset 1s ease' : 'none',
}}
shapeRendering='geometricPrecision'
/>
@ -82,5 +91,3 @@ const Gauge = ({ background = '#15161A', diameter = 40, value = 0, label, toolti
</Tooltip>
)
}
export default Gauge

View File

Before

Width:  |  Height:  |  Size: 964 B

After

Width:  |  Height:  |  Size: 964 B

View File

Before

Width:  |  Height:  |  Size: 672 B

After

Width:  |  Height:  |  Size: 672 B

View File

Before

Width:  |  Height:  |  Size: 382 B

After

Width:  |  Height:  |  Size: 382 B

View File

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

View File

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 933 B

View File

Before

Width:  |  Height:  |  Size: 397 B

After

Width:  |  Height:  |  Size: 397 B

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 451 B

After

Width:  |  Height:  |  Size: 451 B

View File

Before

Width:  |  Height:  |  Size: 272 B

After

Width:  |  Height:  |  Size: 272 B

View File

Before

Width:  |  Height:  |  Size: 166 B

After

Width:  |  Height:  |  Size: 166 B

View File

Before

Width:  |  Height:  |  Size: 324 B

After

Width:  |  Height:  |  Size: 324 B

View File

Before

Width:  |  Height:  |  Size: 325 B

After

Width:  |  Height:  |  Size: 325 B

View File

Before

Width:  |  Height:  |  Size: 328 B

After

Width:  |  Height:  |  Size: 328 B

View File

Before

Width:  |  Height:  |  Size: 329 B

After

Width:  |  Height:  |  Size: 329 B

View File

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,3 +1,3 @@
;<svg fill='currentColor' viewBox='0 0 12 14' xmlns='http://www.w3.org/2000/svg'>
<svg fill='currentColor' viewBox='0 0 12 14' xmlns='http://www.w3.org/2000/svg'>
<path d='M6.47317 3.19325C6.40977 3.13256 6.335 3.08498 6.25317 3.05325C6.09086 2.98657 5.90881 2.98657 5.7465 3.05325C5.66467 3.08498 5.58991 3.13256 5.5265 3.19325L2.85984 5.85992C2.79768 5.92208 2.74837 5.99587 2.71473 6.07709C2.68109 6.1583 2.66378 6.24535 2.66378 6.33325C2.66378 6.42116 2.68109 6.5082 2.71473 6.58942C2.74837 6.67063 2.79768 6.74443 2.85984 6.80659C2.922 6.86874 2.99579 6.91805 3.077 6.95169C3.15822 6.98533 3.24526 7.00265 3.33317 7.00265C3.42108 7.00265 3.50812 6.98533 3.58934 6.95169C3.67055 6.91805 3.74434 6.86874 3.8065 6.80659L5.33317 5.27325V12.9999C5.33317 13.1767 5.40341 13.3463 5.52843 13.4713C5.65346 13.5963 5.82303 13.6666 5.99984 13.6666C6.17665 13.6666 6.34622 13.5963 6.47124 13.4713C6.59627 13.3463 6.6665 13.1767 6.6665 12.9999V5.27325L8.19317 6.80659C8.25515 6.86907 8.32888 6.91867 8.41012 6.95251C8.49136 6.98636 8.5785 7.00378 8.6665 7.00378C8.75451 7.00378 8.84165 6.98636 8.92289 6.95251C9.00413 6.91867 9.07786 6.86907 9.13984 6.80659C9.20232 6.74461 9.25192 6.67088 9.28576 6.58964C9.31961 6.5084 9.33704 6.42126 9.33704 6.33325C9.33704 6.24524 9.31961 6.15811 9.28576 6.07687C9.25192 5.99563 9.20232 5.92189 9.13984 5.85992L6.47317 3.19325ZM10.6665 0.333252H1.33317C1.15636 0.333252 0.98679 0.40349 0.861766 0.528514C0.736742 0.653538 0.666504 0.823108 0.666504 0.999919C0.666504 1.17673 0.736742 1.3463 0.861766 1.47132C0.98679 1.59635 1.15636 1.66659 1.33317 1.66659H10.6665C10.8433 1.66659 11.0129 1.59635 11.1379 1.47132C11.2629 1.3463 11.3332 1.17673 11.3332 0.999919C11.3332 0.823108 11.2629 0.653538 11.1379 0.528514C11.0129 0.40349 10.8433 0.333252 10.6665 0.333252Z' />
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 225 B

After

Width:  |  Height:  |  Size: 225 B

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 944 B

After

Width:  |  Height:  |  Size: 944 B

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

Before

Width:  |  Height:  |  Size: 664 B

After

Width:  |  Height:  |  Size: 664 B

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 388 B

After

Width:  |  Height:  |  Size: 388 B

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 191 B

After

Width:  |  Height:  |  Size: 191 B

View File

Before

Width:  |  Height:  |  Size: 746 B

After

Width:  |  Height:  |  Size: 746 B

View File

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 442 B

View File

Before

Width:  |  Height:  |  Size: 443 B

After

Width:  |  Height:  |  Size: 443 B

View File

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 547 B

View File

Before

Width:  |  Height:  |  Size: 485 B

After

Width:  |  Height:  |  Size: 485 B

View File

Before

Width:  |  Height:  |  Size: 371 B

After

Width:  |  Height:  |  Size: 371 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 165 B

After

Width:  |  Height:  |  Size: 165 B

View File

Before

Width:  |  Height:  |  Size: 615 B

After

Width:  |  Height:  |  Size: 615 B

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 498 B

View File

@ -0,0 +1,48 @@
// @index(['./*.svg'], f => `export { default as ${f.name} } from '${f.path}.svg'`)
export { default as Add } from './Add.svg'
export { default as ArrowBack } from './ArrowBack.svg'
export { default as ArrowDown } from './ArrowDown.svg'
export { default as ArrowLeftLine } from './ArrowLeftLine.svg'
export { default as ArrowRightLine } from './ArrowRightLine.svg'
export { default as ArrowsLeftRight } from './ArrowsLeftRight.svg'
export { default as ArrowsUpDown } from './ArrowsUpDown.svg'
export { default as ArrowUp } from './ArrowUp.svg'
export { default as BurgerMenu } from './BurgerMenu.svg'
export { default as Check } from './Check.svg'
export { default as ChevronDown } from './ChevronDown.svg'
export { default as ChevronLeft } from './ChevronLeft.svg'
export { default as ChevronRight } from './ChevronRight.svg'
export { default as ChevronUp } from './ChevronUp.svg'
export { default as Close } from './Close.svg'
export { default as Copy } from './Copy.svg'
export { default as Deposit } from './Deposit.svg'
export { default as Discord } from './Discord.svg'
export { default as Edit } from './Edit.svg'
export { default as Ellipsis } from './Ellipsis.svg'
export { default as ExternalLink } from './ExternalLink.svg'
export { default as Failed } from './Failed.svg'
export { default as Github } from './Github.svg'
export { default as Info } from './Info.svg'
export { default as Logo } from './Logo.svg'
export { default as MarsProtocol } from './MarsProtocol.svg'
export { default as Medium } from './Medium.svg'
export { default as Osmo } from './Osmo.svg'
export { default as Questionmark } from './Questionmark.svg'
export { default as Reddit } from './Reddit.svg'
export { default as Rubbish } from './Rubbish.svg'
export { default as Search } from './Search.svg'
export { default as SmallClose } from './SmallClose.svg'
export { default as SortAsc } from './SortAsc.svg'
export { default as SortDesc } from './SortDesc.svg'
export { default as SortNone } from './SortNone.svg'
export { default as Subtract } from './Subtract.svg'
export { default as Success } from './Success.svg'
export { default as Telegram } from './Telegram.svg'
export { default as TriangleDown } from './TriangleDown.svg'
export { default as Twitter } from './Twitter.svg'
export { default as Wallet } from './Wallet.svg'
export { default as WalletConnect } from './WalletConnect.svg'
export { default as Warning } from './Warning.svg'
export { default as Withdraw } from './Withdraw.svg'
export { default as YouTube } from './YouTube.svg'
// @endindex

View File

@ -0,0 +1,24 @@
import classNames from 'classnames'
import { FormattedNumber, Text } from 'components'
interface ValueData extends FormattedNumberProps {
format?: 'number' | 'string'
}
interface Props {
label: string
value: ValueData
className?: string
}
export const LabelValuePair = ({ label, value, className }: Props) => (
<div className={classNames('flex w-full', className)}>
<Text size='xs' className='flex-grow text-white/60'>
{label}
</Text>
<Text size='xs' className='text-white/60'>
{value.format === 'number' ? <FormattedNumber animate {...value} /> : value.amount || ''}
</Text>
</div>
)

View File

@ -1,19 +1,21 @@
import { useWallet, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
import classNames from 'classnames'
import React, { useEffect } from 'react'
import { useWallet, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
import AccountManager from 'components/Account/AccountDetails'
import DesktopNavigation from 'components/Navigation/DesktopNavigation'
import useCreditAccounts from 'hooks/useCreditAccounts'
import { useWalletStore } from 'stores'
import { AccountDetails } from 'components/Account'
import { DesktopNavigation } from 'components/Navigation'
import { useCreditAccounts } from 'hooks/queries'
import { useSettings, useWalletStore } from 'stores'
const filter = {
day: 'brightness-100 hue-rotate-0',
night: '-hue-rotate-82 brightness-30',
}
const Layout = ({ children }: { children: React.ReactNode }) => {
const { data: creditAccountsList, isLoading: isLoadingCreditAccounts } = useCreditAccounts()
export const Layout = ({ children }: { children: React.ReactNode }) => {
const enableAnimations = useSettings((s) => s.enableAnimations)
const { data: creditAccountsList } = useCreditAccounts()
const hasCreditAccounts = creditAccountsList && creditAccountsList.length > 0
const { status, signingCosmWasmClient, chainInfo, address, name } = useWallet()
@ -27,19 +29,18 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
const backgroundClasses = classNames(
isConnected ? filter.day : filter.night,
'top-0 left-0 absolute block h-full w-full flex-col bg-body bg-mars bg-desktop bg-top bg-no-repeat filter transition-background duration-3000 ease-linear',
'top-0 left-0 absolute block h-full w-full flex-col bg-body bg-mars bg-desktop bg-top bg-no-repeat filter',
enableAnimations && 'transition-background duration-3000 ease-linear',
)
return (
<div className='relative min-h-screen w-full'>
<div className={backgroundClasses} />
<DesktopNavigation />
<main className='relative flex lg:h-[calc(100vh-120px)]'>
<main className='relative flex lg:min-h-[calc(100vh-120px)]'>
<div className='flex flex-grow flex-wrap p-6'>{children}</div>
{hasCreditAccounts && <AccountManager />}
{hasCreditAccounts && <AccountDetails />}
</main>
</div>
)
}
export default Layout

View File

@ -1,8 +1,8 @@
import classNames from 'classnames'
import { ReactNode } from 'react'
import Card from 'components/Card'
import CloseIcon from 'components/Icons/close.svg'
import { Card } from 'components'
import { Close } from 'components/Icons'
interface Props {
children?: ReactNode | string
@ -12,7 +12,7 @@ interface Props {
setOpen?: (open: boolean) => void
}
const Modal = ({ children, content, className, open, setOpen }: Props) => {
export const Modal = ({ children, content, className, open, setOpen }: Props) => {
const onClickAway = () => {
if (setOpen) setOpen(false)
}
@ -27,7 +27,7 @@ const Modal = ({ children, content, className, open, setOpen }: Props) => {
onClick={onClickAway}
role='button'
>
<CloseIcon />
<Close />
</span>
)}
{children ? children : content}
@ -41,5 +41,3 @@ const Modal = ({ children, content, className, open, setOpen }: Props) => {
</div>
) : null
}
export default Modal

View File

@ -1,11 +1,9 @@
import { ConfirmModal, FundAccountModal, WithdrawModal } from './Account'
const Modals = () => (
export const Modals = () => (
<>
<FundAccountModal />
<WithdrawModal />
<ConfirmModal />
</>
)
export default Modals

View File

@ -1,14 +1,13 @@
import Link from 'next/link'
import { AccountNavigation, AccountStatus } from 'components/Account'
import Logo from 'components/Icons/logo.svg'
import { menuTree, NavLink } from 'components/Navigation'
import SearchInput from 'components/Navigation/SearchInput'
import Wallet from 'components/Wallet/Wallet'
import useCreditAccounts from 'hooks/useCreditAccounts'
import { Logo } from 'components/Icons'
import { menuTree, NavLink, SearchInput } from 'components/Navigation'
import { Wallet } from 'components/Wallet'
import { useCreditAccounts } from 'hooks/queries'
import { useAccountDetailsStore, useWalletStore } from 'stores'
const Navigation = () => {
export const DesktopNavigation = () => {
const address = useWalletStore((s) => s.address)
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
@ -52,5 +51,3 @@ const Navigation = () => {
</div>
)
}
export default Navigation

View File

@ -8,7 +8,7 @@ interface Props {
children: string | ReactNode
}
const NavLink = ({ href, children }: Props) => {
export const NavLink = ({ href, children }: Props) => {
const router = useRouter()
const isActive = router.pathname === href
@ -25,5 +25,3 @@ const NavLink = ({ href, children }: Props) => {
</Link>
)
}
export default NavLink

View File

@ -1,8 +1,8 @@
import SearchIcon from 'components/Icons/search.svg'
const SearchInput = () => (
import { Search } from 'components/Icons'
export const SearchInput = () => (
<div className='relative mt-[1px] py-2 text-white'>
<span className='absolute top-1/2 left-0 flex h-6 w-8 -translate-y-1/2 items-center pl-2'>
<SearchIcon />
<Search />
</span>
<input
className='w-[280px] rounded-md border border-white/20 bg-black/30 py-2 pl-10 text-sm text-white placeholder:text-white/40 focus:border-white/60 focus:outline-none'
@ -10,5 +10,3 @@ const SearchInput = () => (
/>
</div>
)
export default SearchInput

View File

@ -0,0 +1,6 @@
// @index(['./*.ts*'], f => `export { ${f.name} } from '${f.path}'`)
export { DesktopNavigation } from './DesktopNavigation'
export { menuTree } from './menuTree'
export { NavLink } from './NavLink'
export { SearchInput } from './SearchInput'
// @endindex

View File

@ -1,9 +1,7 @@
const navItems = [
export const menuTree = [
{ href: '/trade', label: 'Trade' },
{ href: '/earn', label: 'Earn' },
{ href: '/borrow', label: 'Borrow' },
{ href: '/portfolio', label: 'Portfolio' },
{ href: '/council', label: 'Council' },
]
export default navItems

View File

@ -9,7 +9,7 @@ interface Props {
setShow: (show: boolean) => void
}
const Overlay = ({ children, content, className, show, setShow }: Props) => {
export const Overlay = ({ children, content, className, show, setShow }: Props) => {
const onClickAway = () => {
setShow(false)
}
@ -32,5 +32,3 @@ const Overlay = ({ children, content, className, show, setShow }: Props) => {
</>
) : null
}
export default Overlay

View File

@ -1,7 +1,7 @@
import classNames from 'classnames'
import { ReactNode } from 'react'
import Button from 'components/Button'
import { Button } from 'components'
interface Props {
className?: string
@ -11,7 +11,7 @@ interface Props {
text: string | ReactNode
}
const OverlayAction = ({ className, icon, onClick, setShow, text }: Props) => {
export const OverlayAction = ({ className, icon, onClick, setShow, text }: Props) => {
return (
<Button
className={classNames(
@ -29,5 +29,3 @@ const OverlayAction = ({ className, icon, onClick, setShow, text }: Props) => {
</Button>
)
}
export default OverlayAction

View File

@ -0,0 +1,4 @@
// @index(['./*.tsx'], f => `export { ${f.name} } from '${f.path}'`)
export { Overlay } from './Overlay'
export { OverlayAction } from './OverlayAction'
// @endindex

View File

@ -0,0 +1,61 @@
import classNames from 'classnames'
import { FormattedNumber, Text } from 'components'
interface Props {
title: string
data?: PositionsData[]
}
export const PositionsList = (props: Props) => {
if (!props?.data || props.data?.length === 0) return null
const arrayKeys = Object.keys(props.data[0])
return (
<div className='flex w-full flex-wrap'>
<Text uppercase className='w-full bg-black/20 px-4 py-2 text-white/40'>
{props.title}
</Text>
<div className='flex w-full flex-wrap'>
<>
<div className='mb-2 flex w-full border-b border-white/20 bg-black/20 px-4 py-2'>
{arrayKeys.map((label, index) => (
<Text key={index} size='xs' uppercase className='flex-1 text-white'>
{label}
</Text>
))}
</div>
{props.data &&
props.data.map((positionsData: PositionsData, index) => (
<div key={index} className='align-center flex w-full px-4 py-2'>
{arrayKeys.map((key, index) => {
if (index === 0)
return (
<Text
size='xs'
key={index}
className={classNames(
'flex-1 border-l-4 pl-2 text-white/60',
positionsData[key].type === 'debt' ? 'border-loss' : 'border-profit',
)}
>
{positionsData[key].amount}
</Text>
)
return (
<Text size='xs' key={index} className='flex-1 text-white/60'>
{positionsData[key].format && positionsData[key].format === 'number' ? (
<FormattedNumber animate {...positionsData[key]} />
) : (
positionsData[key]?.amount || ''
)}
</Text>
)
})}
</div>
))}
</>
</div>
</div>
)
}

View File

@ -4,7 +4,7 @@ type Props = {
value: number
}
const ProgressBar = ({ value }: Props) => {
export const ProgressBar = ({ value }: Props) => {
const percentageValue = `${(value * 100).toFixed(0)}%`
let bgColorClass = 'bg-green-500'
@ -26,5 +26,3 @@ const ProgressBar = ({ value }: Props) => {
</div>
)
}
export default ProgressBar

View File

@ -5,17 +5,12 @@ import React, { useMemo, useState } from 'react'
import { NumericFormat } from 'react-number-format'
import { toast } from 'react-toastify'
import Button from 'components/Button'
import CircularProgress from 'components/CircularProgress'
import ContainerSecondary from 'components/ContainerSecondary'
import Slider from 'components/Slider'
import useRepayFunds from 'hooks/mutations/useRepayFunds'
import useAllBalances from 'hooks/useAllBalances'
import useCreditAccountPositions from 'hooks/useCreditAccountPositions'
import useTokenPrices from 'hooks/useTokenPrices'
import { Button, CircularProgress, ContainerSecondary, Slider } from 'components'
import { useRepayFunds } from 'hooks/mutations'
import { useAccountDetailsStore } from 'stores'
import { formatCurrency } from 'utils/formatters'
import { getTokenDecimals, getTokenSymbol } from 'utils/tokens'
import { useAllBalances, useCreditAccountPositions, useTokenPrices } from 'hooks/queries'
// 0.001% buffer / slippage to avoid repay action from not fully repaying the debt amount
const REPAY_BUFFER = 1.00001
@ -26,7 +21,7 @@ type Props = {
tokenDenom: string
}
const RepayModal = ({ show, onClose, tokenDenom }: Props) => {
export const RepayModal = ({ show, onClose, tokenDenom }: Props) => {
const [amount, setAmount] = useState(0)
const selectedAccount = useAccountDetailsStore((s) => s.selectedAccount)
@ -190,5 +185,3 @@ const RepayModal = ({ show, onClose, tokenDenom }: Props) => {
</Transition>
)
}
export default RepayModal

View File

@ -8,7 +8,7 @@ type Props = {
onMaxClick: () => void
}
const Slider = ({ className, value, onChange, onMaxClick }: Props) => {
export const Slider = ({ className, value, onChange, onMaxClick }: Props) => {
return (
<div className={`relative flex flex-1 items-center ${className || ''}`}>
<RadixSlider.Root
@ -35,5 +35,3 @@ const Slider = ({ className, value, onChange, onMaxClick }: Props) => {
</div>
)
}
export default Slider

Some files were not shown because too many files have changed in this diff Show More