Mp 2344 fund credit account flow (#145)
* MP-2344: first draft for the fund account flow * tidy: refactor * fix: fixed the callback functions * fix: fixed the toast message for funding * fix: some logic fixes * feat: enabled closing of “fund account” * fix: z-1 to isolate use isolate to create a stacking context * tidy: deleted icons * MP-2344: updated the tooltip * MP-2344: new create and funding logic * MP-2344: finished AccountList UI * tidy: svg icon updates * chore: updated dependencies * feat: convert inputValues to amounts and amounts to inputValues * fix: build fix * fix: fixed imports * fix: pr updated * fix: fixed the SWR queries to not override themselves * tidy: refactor * feat: added TokenInputWithSlider * tidy: refactor TokenInputWithSlider * feat: preparations for the accountBalance calculations * fix: removed formatCurrency from store * feat: added global Coin type * tidy: refactor delete and create credit account * add useCallback to FundAccount * update api + swr * refactor naming, ssr accounts menu * wip: added static params and href to DesktopNavigation * fix: added TODO statement * add middleware to get url * feat: added scrolling to the active account * tidy: UX improvement on the accounts list * fix: updated the page params * fix: fixed the navigation * fix: fixed the getRouteParams * fix: some logic updates * fix: fixed the accountMenu view * Keep page when selecting new account * fix: fixed useParams * fix: navigation update * fix pr comments * fixed build --------- Co-authored-by: Bob van der Helm <34470358+bobthebuidlr@users.noreply.github.com>
24
package.json
@ -13,9 +13,9 @@
|
||||
"dependencies": {
|
||||
"@cosmjs/cosmwasm-stargate": "^0.30.1",
|
||||
"@cosmjs/stargate": "^0.30.1",
|
||||
"@marsprotocol/wallet-connector": "^1.5.2",
|
||||
"@sentry/nextjs": "^7.44.2",
|
||||
"@tanstack/react-table": "^8.7.9",
|
||||
"@marsprotocol/wallet-connector": "^1.5.3",
|
||||
"@sentry/nextjs": "^7.46.0",
|
||||
"@tanstack/react-table": "^8.8.5",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"bignumber.js": "^9.1.1",
|
||||
"classnames": "^2.3.2",
|
||||
@ -30,24 +30,24 @@
|
||||
"react-toastify": "^9.1.2",
|
||||
"react-use-clipboard": "^1.0.9",
|
||||
"recharts": "^2.5.0",
|
||||
"swr": "^2.1.1",
|
||||
"swr": "^2.1.2",
|
||||
"tailwind-scrollbar-hide": "^1.1.7",
|
||||
"zustand": "^4.3.6"
|
||||
"zustand": "^4.3.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "^6.5.1",
|
||||
"@types/node": "^18.15.5",
|
||||
"@types/react": "18.0.28",
|
||||
"@svgr/webpack": "^7.0.0",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/react": "18.0.32",
|
||||
"@types/react-dom": "18.0.11",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "8.36.0",
|
||||
"eslint": "8.37.0",
|
||||
"eslint-config-next": "^13.2.4",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"postcss": "^8.4.21",
|
||||
"prettier": "^2.8.7",
|
||||
"prettier-plugin-tailwindcss": "^0.2.5",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"typescript": "5.0.2"
|
||||
"prettier-plugin-tailwindcss": "^0.2.6",
|
||||
"tailwindcss": "^3.3.1",
|
||||
"typescript": "5.0.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "18.0.26",
|
||||
|
@ -1,24 +1,25 @@
|
||||
import classNames from 'classnames'
|
||||
import { headers } from 'next/headers'
|
||||
|
||||
import AccountDetails from 'components/Account/AccountDetails'
|
||||
import Background from 'components/Background'
|
||||
import FetchPrices from 'components/FetchPrices'
|
||||
import DesktopHeader from 'components/Header/DesktopHeader'
|
||||
import { Modals } from 'components/Modals'
|
||||
import DesktopNavigation from 'components/Navigation/DesktopNavigation'
|
||||
import Toaster from 'components/Toaster'
|
||||
import { WalletConnectProvider } from 'components/Wallet/WalletConnectProvider'
|
||||
import 'react-toastify/dist/ReactToastify.min.css'
|
||||
import 'styles/globals.css'
|
||||
import { getRouteParams } from 'utils/route'
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function RootLayout(props: { children: React.ReactNode }) {
|
||||
const href = headers().get('x-url') || ''
|
||||
const params = getRouteParams(href)
|
||||
return (
|
||||
<html className='m-0 p-0' lang='en'>
|
||||
<head />
|
||||
<body className='m-0 cursor-default bg-body p-0 font-sans text-white'>
|
||||
<WalletConnectProvider>
|
||||
<Background />
|
||||
<DesktopNavigation />
|
||||
</WalletConnectProvider>
|
||||
<Background />
|
||||
<DesktopHeader params={params} />
|
||||
<FetchPrices />
|
||||
<main
|
||||
className={classNames(
|
||||
@ -26,7 +27,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
'lg:mt-[65px] lg:h-[calc(100vh-65px)]',
|
||||
)}
|
||||
>
|
||||
<div className='flex max-w-content flex-grow flex-col flex-wrap'>{children}</div>
|
||||
<div className='flex max-w-content flex-grow flex-col flex-wrap'>{props.children}</div>
|
||||
<AccountDetails />
|
||||
</main>
|
||||
<Modals />
|
||||
|
@ -1,10 +1,7 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
import Card from 'components/Card'
|
||||
import { Plus, Subtract } from 'components/Icons'
|
||||
import { Text } from 'components/Text'
|
||||
|
||||
import { Plus, Subtract } from './Icons'
|
||||
import Card from './Card'
|
||||
|
||||
interface Props {
|
||||
items: Item[]
|
||||
}
|
||||
@ -20,7 +17,7 @@ export default function Accordion(props: Props) {
|
||||
{props.items.map((item, index) => (
|
||||
<details key={item.title} className='group border-b-white/10 [&:not(:last-child)]:border-b'>
|
||||
<summary className='mb-0 flex cursor-pointer items-center justify-between border-t border-white/10 bg-white/10 p-4 text-white group-[&:first-child]:border-t-0 group-[[open]]:border-b [&::marker]:hidden [&::marker]:content-[""]'>
|
||||
<Text size='base'>{item.title}</Text>
|
||||
<Text>{item.title}</Text>
|
||||
<div className='block h-[14px] w-[14px] group-[[open]]:hidden'>
|
||||
<Plus />
|
||||
</div>
|
||||
|
@ -2,17 +2,18 @@
|
||||
import { Gauge } from 'components/Gauge'
|
||||
import { Heart } from 'components/Icons'
|
||||
import { Text } from 'components/Text'
|
||||
import useParams from 'hooks/useParams'
|
||||
import { isNumber } from 'utils/parsers'
|
||||
import useParams from 'utils/route'
|
||||
|
||||
export default function AccountDetails() {
|
||||
const params = useParams()
|
||||
const hasAccount = params.account && !isNaN(Number(params.account))
|
||||
const hasAccount = isNumber(params.accountId)
|
||||
|
||||
return hasAccount ? (
|
||||
<div className='fixed top-[89px] right-4 w-16 rounded-base border border-white/20 bg-white/5 backdrop-blur-sticky'>
|
||||
<div className='fixed right-4 top-[89px] w-16 rounded-base border border-white/20 bg-white/5 backdrop-blur-sticky'>
|
||||
<div className='flex w-full flex-wrap justify-center py-4'>
|
||||
<Gauge tooltip='Health Factor' value={0.2} icon={<Heart />} />
|
||||
<Text size='2xs' className='mt-1 mb-0.5 w-full text-center text-white/50'>
|
||||
<Text size='2xs' className='mb-0.5 mt-1 w-full text-center text-white/50'>
|
||||
Health
|
||||
</Text>
|
||||
<Text size='xs' className='w-full text-center'>
|
||||
@ -30,7 +31,7 @@ export default function AccountDetails() {
|
||||
<div className='w-full py-4'>
|
||||
<Text size='2xs' className='mb-0.5 w-full text-center text-white/50'>
|
||||
Balance
|
||||
</Text>{' '}
|
||||
</Text>
|
||||
<Text size='xs' className='w-full text-center'>
|
||||
$300M
|
||||
</Text>
|
||||
|
174
src/components/Account/AccountList.tsx
Normal file
@ -0,0 +1,174 @@
|
||||
'use client'
|
||||
|
||||
import classNames from 'classnames'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import AccountStats from 'components/Account/AccountStats'
|
||||
import { Button } from 'components/Button'
|
||||
import Card from 'components/Card'
|
||||
import { ArrowCircledTopRight, ArrowDownLine, ArrowUpLine, TrashBin } from 'components/Icons'
|
||||
import Radio from 'components/Radio'
|
||||
import SwitchWithLabel from 'components/SwitchWithLabel'
|
||||
import { Text } from 'components/Text'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import useParams, { getRoute } from 'utils/route'
|
||||
import useStore from 'store'
|
||||
import { calculateAccountBalance } from 'utils/accounts'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
import { formatValue } from 'utils/formatters'
|
||||
|
||||
interface Props {
|
||||
setShowFundAccount: (showFundAccount: boolean) => void
|
||||
accounts: Account[]
|
||||
}
|
||||
|
||||
const accountCardHeaderClasses = classNames(
|
||||
'flex w-full items-center justify-between bg-white/20 px-4 py-2.5 text-white/70',
|
||||
'border border-transparent border-b-white/20',
|
||||
)
|
||||
|
||||
// TODO: Make this dynamic (token select)
|
||||
const formatOptions = {
|
||||
decimals: ASSETS[0].decimals,
|
||||
minDecimals: 0,
|
||||
maxDecimals: ASSETS[0].decimals,
|
||||
suffix: ` ${ASSETS[0].symbol}`,
|
||||
}
|
||||
|
||||
export default function AccountList(props: Props) {
|
||||
const router = useRouter()
|
||||
const params = useParams()
|
||||
|
||||
const selectedAccount = params.accountId
|
||||
const prices = useStore((s) => s.prices)
|
||||
|
||||
const deleteAccount = useStore((s) => s.deleteAccount)
|
||||
|
||||
const [isLending, setIsLending] = useState(false)
|
||||
const accountSelected = !!selectedAccount && !isNaN(Number(selectedAccount))
|
||||
const selectedAccountDetails = props.accounts.find((account) => account.id === selectedAccount)
|
||||
const selectedAccountBalance = selectedAccountDetails
|
||||
? calculateAccountBalance(selectedAccountDetails, prices)
|
||||
: 0
|
||||
|
||||
async function deleteAccountHandler() {
|
||||
if (!accountSelected) return
|
||||
const isSuccess = await deleteAccount({ fee: hardcodedFee, accountId: selectedAccount })
|
||||
if (isSuccess) {
|
||||
router.push(`/wallets/${params.address}/accounts`)
|
||||
}
|
||||
}
|
||||
|
||||
function onChangeLendSwitch(isLending: boolean) {
|
||||
setIsLending(isLending)
|
||||
/* TODO: handle lending assets */
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const element = document.getElementById(`account-${selectedAccount}`)
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' })
|
||||
}
|
||||
}, [selectedAccount])
|
||||
|
||||
if (!props.accounts?.length) return null
|
||||
|
||||
return (
|
||||
<div className='flex w-full flex-wrap p-4'>
|
||||
{props.accounts.map((account) => {
|
||||
const positionBalance = calculateAccountBalance(account, prices)
|
||||
const isActive = selectedAccount === account.id
|
||||
return (
|
||||
<div key={account.id} id={`account-${account.id}`} className='w-full pt-4'>
|
||||
<Card
|
||||
id={`account-${account.id}`}
|
||||
key={account.id}
|
||||
className='w-full'
|
||||
contentClassName='bg-white/10'
|
||||
title={
|
||||
<div
|
||||
className={classNames(
|
||||
accountCardHeaderClasses,
|
||||
!isActive && 'group hover:cursor-pointer',
|
||||
)}
|
||||
role={!isActive ? 'button' : undefined}
|
||||
onClick={() => {
|
||||
if (isActive) return
|
||||
router.push(getRoute(params, { accountId: account.id }))
|
||||
}}
|
||||
>
|
||||
<Text size='xs' className='flex flex-1'>
|
||||
Credit Account {account.id}
|
||||
</Text>
|
||||
<Radio active={isActive} className='group-hover:opacity-100' />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{isActive ? (
|
||||
<>
|
||||
<div className='w-full border border-transparent border-b-white/20 p-4'>
|
||||
<AccountStats
|
||||
balance={formatValue(selectedAccountBalance, formatOptions)}
|
||||
risk={75}
|
||||
health={0.85}
|
||||
/>
|
||||
</div>
|
||||
<div className='grid grid-flow-row grid-cols-2 gap-4 p-4'>
|
||||
<Button
|
||||
className='w-full'
|
||||
text='Fund'
|
||||
color='tertiary'
|
||||
leftIcon={<ArrowUpLine />}
|
||||
onClick={() => props.setShowFundAccount(true)}
|
||||
/>
|
||||
<Button
|
||||
className='w-full'
|
||||
color='tertiary'
|
||||
leftIcon={<ArrowDownLine />}
|
||||
text='Withdraw'
|
||||
onClick={() => {
|
||||
useStore.setState({ withdrawModal: true })
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
className='w-full'
|
||||
color='tertiary'
|
||||
leftIcon={<TrashBin />}
|
||||
text='Delete'
|
||||
onClick={() => deleteAccountHandler()}
|
||||
/>
|
||||
<Button
|
||||
className='w-full'
|
||||
color='tertiary'
|
||||
leftIcon={<ArrowCircledTopRight />}
|
||||
text='Transfer'
|
||||
onClick={() => {}}
|
||||
/>
|
||||
<div className='col-span-2 border border-transparent border-t-white/10 pt-4'>
|
||||
<SwitchWithLabel
|
||||
name='isLending'
|
||||
label='Lend assets to earn yield'
|
||||
value={isLending}
|
||||
onChange={onChangeLendSwitch}
|
||||
tooltip={`Fund your account and lend assets effortlessly! By lending, you'll earn attractive interest (APY) without impacting your LTV. It's a win-win situation - don't miss out on this easy opportunity to grow your holdings!`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className='w-full p-4'>
|
||||
<AccountStats
|
||||
balance={formatValue(positionBalance, formatOptions)}
|
||||
risk={60}
|
||||
health={0.5}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,200 +1,23 @@
|
||||
'use client'
|
||||
import { Suspense } from 'react'
|
||||
|
||||
import classNames from 'classnames'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useState } from 'react'
|
||||
|
||||
import { Button } from 'components/Button'
|
||||
import {
|
||||
Account,
|
||||
Add,
|
||||
ArrowDownLine,
|
||||
ArrowRight,
|
||||
ArrowsLeftRight,
|
||||
ArrowUpLine,
|
||||
Rubbish,
|
||||
} from 'components/Icons'
|
||||
import AccountMenuContent from 'components/Account/AccountMenuContent'
|
||||
import Loading from 'components/Loading'
|
||||
import { Overlay } from 'components/Overlay/Overlay'
|
||||
import { Text } from 'components/Text'
|
||||
import useParams from 'hooks/useParams'
|
||||
import useStore from 'store'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
import { getAccounts } from 'utils/api'
|
||||
|
||||
export default function AccountMenu() {
|
||||
const router = useRouter()
|
||||
const params = useParams()
|
||||
const selectedAccount = params.account
|
||||
interface Props {
|
||||
params: PageParams
|
||||
}
|
||||
|
||||
const createCreditAccount = useStore((s) => s.createCreditAccount)
|
||||
const deleteCreditAccount = useStore((s) => s.deleteCreditAccount)
|
||||
const creditAccounts = useStore((s) => s.creditAccounts)
|
||||
const address = useStore((s) => s.address)
|
||||
const deposit = useStore((s) => s.deposit)
|
||||
async function Content(props: Props) {
|
||||
const accounts = await getAccounts(props.params.address)
|
||||
return <AccountMenuContent accounts={accounts} />
|
||||
}
|
||||
|
||||
const hasCreditAccounts = !!creditAccounts?.length
|
||||
const accountSelected = !!selectedAccount && !isNaN(Number(selectedAccount))
|
||||
|
||||
const [showMenu, setShowMenu] = useState(false)
|
||||
|
||||
const [createAccount, setCreateAccount] = useState(false)
|
||||
|
||||
async function createAccountHandler() {
|
||||
setShowMenu(true)
|
||||
setCreateAccount(true)
|
||||
const accountId = await createCreditAccount({ fee: hardcodedFee })
|
||||
setCreateAccount(false)
|
||||
if (!accountId) return
|
||||
router.push(`/wallets/${params.wallet}/accounts/${accountId}`)
|
||||
}
|
||||
|
||||
async function deleteAccountHandler() {
|
||||
if (!accountSelected) return
|
||||
const isSuccess = await deleteCreditAccount({ fee: hardcodedFee, accountId: selectedAccount })
|
||||
if (isSuccess) {
|
||||
router.push(`/wallets/${params.wallet}/accounts`)
|
||||
}
|
||||
}
|
||||
|
||||
return !address ? null : (
|
||||
<>
|
||||
{creditAccounts === null ? (
|
||||
<Loading className='h-8 w-35' />
|
||||
) : (
|
||||
<div className='relative'>
|
||||
<Button
|
||||
onClick={hasCreditAccounts ? () => setShowMenu(!showMenu) : createAccountHandler}
|
||||
leftIcon={hasCreditAccounts ? <Account /> : <Add />}
|
||||
color={hasCreditAccounts ? 'tertiary' : 'primary'}
|
||||
hasFocus={showMenu}
|
||||
hasSubmenu={hasCreditAccounts}
|
||||
>
|
||||
{hasCreditAccounts
|
||||
? accountSelected
|
||||
? `Account #${selectedAccount}`
|
||||
: 'Select Account'
|
||||
: 'Create Account'}
|
||||
</Button>
|
||||
<Overlay
|
||||
className={classNames(
|
||||
'max-w-screen right-0 mt-2 flex h-[530px] w-[336px] flex-wrap overflow-y-scroll scrollbar-hide',
|
||||
hasCreditAccounts ? 'items-start' : 'items-end',
|
||||
)}
|
||||
show={showMenu}
|
||||
setShow={setShowMenu}
|
||||
>
|
||||
<div className='absolute inset-0 z-1 h-full w-full bg-account' />
|
||||
{(!hasCreditAccounts || createAccount) && (
|
||||
<div className='relative z-10 w-full p-4'>
|
||||
<Text size='lg' className='mb-2 font-bold'>
|
||||
Create your first Credit Account
|
||||
</Text>
|
||||
<Text className='mb-4 text-white/70'>
|
||||
Please approve the transaction in your wallet in order to create your first Credit
|
||||
Account.
|
||||
</Text>
|
||||
<Button
|
||||
className='w-full'
|
||||
showProgressIndicator={createAccount}
|
||||
disabled={createAccount}
|
||||
text='Create Account'
|
||||
rightIcon={<ArrowRight />}
|
||||
onClick={createAccountHandler}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{accountSelected && (
|
||||
<div className='flex w-full flex-wrap'>
|
||||
<Text size='sm' uppercase={true} className='w-full px-4 pt-4'>
|
||||
Manage Account {selectedAccount}
|
||||
</Text>
|
||||
<div className='flex w-full justify-between p-4'>
|
||||
<Button
|
||||
className='flex w-[115px] items-center justify-center pl-0 pr-2'
|
||||
text='Fund'
|
||||
leftIcon={<ArrowUpLine />}
|
||||
onClick={() => {
|
||||
deposit({
|
||||
fee: hardcodedFee,
|
||||
accountId: params.account,
|
||||
coin: { denom: 'uosmo', amount: '10000000' },
|
||||
})
|
||||
setShowMenu(false)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
className='flex w-[115px] items-center justify-center pl-0 pr-2'
|
||||
color='secondary'
|
||||
leftIcon={<ArrowDownLine />}
|
||||
text='Withdraw'
|
||||
onClick={() => {
|
||||
useStore.setState({ withdrawModal: true })
|
||||
setShowMenu(false)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex w-full flex-wrap border-t border-t-white/10 p-4'>
|
||||
<Button
|
||||
className='w-full whitespace-nowrap py-2'
|
||||
variant='transparent'
|
||||
color='quaternary'
|
||||
text='Create New Account'
|
||||
onClick={() => {
|
||||
setShowMenu(false)
|
||||
createAccountHandler()
|
||||
}}
|
||||
leftIcon={<Add />}
|
||||
/>
|
||||
<Button
|
||||
className='w-full whitespace-nowrap py-2'
|
||||
variant='transparent'
|
||||
color='quaternary'
|
||||
text='Close Account'
|
||||
onClick={() => {
|
||||
setShowMenu(false)
|
||||
deleteAccountHandler()
|
||||
}}
|
||||
leftIcon={<Rubbish />}
|
||||
/>
|
||||
<Button
|
||||
className='w-full whitespace-nowrap py-2'
|
||||
variant='transparent'
|
||||
color='quaternary'
|
||||
text='Transfer Balance'
|
||||
onClick={() => {
|
||||
setShowMenu(false)
|
||||
/* TODO: add Transfer Balance Function */
|
||||
}}
|
||||
leftIcon={<ArrowsLeftRight />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{creditAccounts.length > 1 && (
|
||||
<div className='flex w-full flex-wrap border-t border-t-white/10 p-4'>
|
||||
<Text size='sm' uppercase={true} className='w-full pb-2'>
|
||||
Select Account
|
||||
</Text>
|
||||
{creditAccounts.map((account) => {
|
||||
return selectedAccount === account ? null : (
|
||||
<Button
|
||||
key={account}
|
||||
className='w-full whitespace-nowrap py-2'
|
||||
variant='transparent'
|
||||
color='quaternary'
|
||||
onClick={() => {
|
||||
router.push(`/wallets/${params.wallet}/accounts/${account}`)
|
||||
setShowMenu(!showMenu)
|
||||
}}
|
||||
text={`Account ${account}`}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</Overlay>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
export default function AccountMenu(props: Props) {
|
||||
return (
|
||||
<Suspense fallback={<Loading className='h-8 w-35' />}>
|
||||
{/* @ts-expect-error Server Component */}
|
||||
<Content params={props.params} />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
122
src/components/Account/AccountMenuContent.tsx
Normal file
@ -0,0 +1,122 @@
|
||||
'use client'
|
||||
|
||||
import classNames from 'classnames'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import AccountList from 'components/Account/AccountList'
|
||||
import CreateAccount from 'components/Account/CreateAccount'
|
||||
import FundAccount from 'components/Account/FundAccount'
|
||||
import { Button } from 'components/Button'
|
||||
import { CircularProgress } from 'components/CircularProgress'
|
||||
import { Account, Plus, PlusCircled } from 'components/Icons'
|
||||
import { Overlay } from 'components/Overlay/Overlay'
|
||||
import { Text } from 'components/Text'
|
||||
import useParams from 'utils/route'
|
||||
import useStore from 'store'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
import { isNumber } from 'utils/parsers'
|
||||
|
||||
const menuClasses =
|
||||
'absolute isolate flex w-full flex-wrap overflow-y-scroll scrollbar-hide scroll-smooth'
|
||||
|
||||
interface Props {
|
||||
accounts: Account[]
|
||||
}
|
||||
|
||||
export default function AccountMenuContent(props: Props) {
|
||||
const router = useRouter()
|
||||
const params = useParams()
|
||||
const createAccount = useStore((s) => s.createAccount)
|
||||
const [showMenu, setShowMenu] = useState(false)
|
||||
const [isCreating, setIsCreating] = useState(false)
|
||||
|
||||
const selectedAccountId = params.accountId
|
||||
const hasCreditAccounts = !!props.accounts.length
|
||||
const isAccountSelected = isNumber(selectedAccountId)
|
||||
|
||||
const selectedAccountDetails = props.accounts.find((account) => account.id === selectedAccountId)
|
||||
const [showFundAccount, setShowFundAccount] = useState<boolean>(
|
||||
isAccountSelected && !selectedAccountDetails?.deposits?.length,
|
||||
)
|
||||
|
||||
const isLoadingAccount = isAccountSelected && selectedAccountDetails?.id !== selectedAccountId
|
||||
const showCreateAccount = !hasCreditAccounts || isCreating
|
||||
|
||||
async function createAccountHandler() {
|
||||
setShowMenu(true)
|
||||
setIsCreating(true)
|
||||
const accountId = await createAccount({ fee: hardcodedFee })
|
||||
setIsCreating(false)
|
||||
if (!accountId) return
|
||||
router.push(`/wallets/${params.address}/accounts/${accountId}`)
|
||||
}
|
||||
|
||||
if (!params.address) return null
|
||||
|
||||
useStore.setState({ accounts: props.accounts })
|
||||
|
||||
return (
|
||||
<div className='relative'>
|
||||
<Button
|
||||
onClick={hasCreditAccounts ? () => setShowMenu(!showMenu) : createAccountHandler}
|
||||
leftIcon={hasCreditAccounts ? <Account /> : <PlusCircled />}
|
||||
color={hasCreditAccounts ? 'tertiary' : 'primary'}
|
||||
hasFocus={showMenu}
|
||||
hasSubmenu={hasCreditAccounts}
|
||||
>
|
||||
{hasCreditAccounts
|
||||
? isAccountSelected
|
||||
? `Account ${selectedAccountId}`
|
||||
: 'Select Account'
|
||||
: 'Create Account'}
|
||||
</Button>
|
||||
<Overlay
|
||||
className='max-w-screen right-0 mt-2 flex h-[530px] w-[336px] overflow-hidden'
|
||||
show={showMenu}
|
||||
setShow={setShowMenu}
|
||||
>
|
||||
{!showFundAccount && !showCreateAccount ? (
|
||||
<>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex h-[54px] w-full items-center justify-between bg-white/5 px-4 py-3',
|
||||
'border border-transparent border-b-white/10',
|
||||
)}
|
||||
>
|
||||
<Text size='lg' className='font-bold'>
|
||||
Accounts
|
||||
</Text>
|
||||
<Button
|
||||
color='secondary'
|
||||
className='w-[108px]'
|
||||
rightIcon={<Plus />}
|
||||
iconClassName='h-2.5 w-2.5'
|
||||
text='Create'
|
||||
onClick={createAccountHandler}
|
||||
/>
|
||||
</div>
|
||||
<div className={classNames(menuClasses, 'top-[54px] h-[calc(100%-54px)] items-start')}>
|
||||
{isAccountSelected && isLoadingAccount && (
|
||||
<div className='flex h-full w-full items-center justify-center p-4'>
|
||||
<CircularProgress size={40} />
|
||||
</div>
|
||||
)}
|
||||
{hasCreditAccounts && !showFundAccount && !isLoadingAccount && (
|
||||
<AccountList accounts={props.accounts} setShowFundAccount={setShowFundAccount} />
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className={classNames(menuClasses, 'inset-0 h-full items-end bg-account')}>
|
||||
{showCreateAccount ? (
|
||||
<CreateAccount createAccount={createAccountHandler} isCreating={isCreating} />
|
||||
) : showFundAccount ? (
|
||||
<FundAccount setShowFundAccount={setShowFundAccount} setShowMenu={setShowMenu} />
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</Overlay>
|
||||
</div>
|
||||
)
|
||||
}
|
68
src/components/Account/AccountStats.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
'use client'
|
||||
import { Heart, Shield } from 'components/Icons'
|
||||
import { Text } from 'components/Text'
|
||||
import useStore from 'store'
|
||||
|
||||
interface Props {
|
||||
balance: string
|
||||
risk: number
|
||||
health: number
|
||||
}
|
||||
|
||||
export default function AccountStats(props: Props) {
|
||||
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||
const healthBarWidth = 53 * props.health
|
||||
|
||||
return (
|
||||
<div className='w-full flex-wrap'>
|
||||
<Text className='w-full' size='xl'>
|
||||
{props.balance}
|
||||
</Text>
|
||||
<div className='mt-1 flex w-full items-center'>
|
||||
<Text size='xs' className='flex items-center'>
|
||||
<Shield className='mr-1.5 h-3' />
|
||||
<span className='text-white/70'>{`Risk score: ${props.risk}/100`}</span>
|
||||
</Text>
|
||||
<Text size='2xs' className='mx-2 -mt-1'>
|
||||
•
|
||||
</Text>
|
||||
<Text size='xs' className='flex items-center'>
|
||||
<Heart className='mr-1.5 h-3' />
|
||||
<span className='mr-2 text-white/70'>Health</span>
|
||||
<svg
|
||||
width='53'
|
||||
height='4'
|
||||
viewBox='0 0 53 4'
|
||||
fill='none'
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
>
|
||||
<rect width='53' height='4' rx='2' fill='white' fillOpacity='0.1' />
|
||||
<rect
|
||||
width={healthBarWidth}
|
||||
height='4'
|
||||
rx='2'
|
||||
fill='url(#bar)'
|
||||
style={{
|
||||
transition: enableAnimations ? 'width 1s ease' : 'none',
|
||||
}}
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id='bar'
|
||||
x1={healthBarWidth}
|
||||
y1='0'
|
||||
x2='0.208'
|
||||
y2='0'
|
||||
gradientUnits='userSpaceOnUse'
|
||||
>
|
||||
<stop stopColor='#FF645F' />
|
||||
<stop offset='0.489583' stopColor='#FFB1AE' />
|
||||
<stop offset='1' stopColor='#FFD5D3' />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -2,7 +2,7 @@ import Accordion from 'components/Accordion'
|
||||
import Card from 'components/Card'
|
||||
import { ArrowChartLineUp, Shield } from 'components/Icons'
|
||||
import { Text } from 'components/Text'
|
||||
import useParams from 'hooks/useParams'
|
||||
import useParams from 'utils/route'
|
||||
|
||||
export default function AccountSummary() {
|
||||
const params = useParams()
|
||||
@ -32,7 +32,7 @@ export default function AccountSummary() {
|
||||
</Card>
|
||||
<Accordion
|
||||
items={[
|
||||
{ title: `Subaccount ${params.account} Composition`, content: <p>My content</p> },
|
||||
{ title: `Subaccount ${params.accountId} Composition`, content: <p>My content</p> },
|
||||
{ title: 'Risk Score: 60/100', content: <p>My content</p> },
|
||||
{ title: 'Balances', content: <p>My content</p> },
|
||||
]}
|
||||
|
30
src/components/Account/CreateAccount.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
'use client'
|
||||
|
||||
import { Button } from 'components/Button'
|
||||
import { ArrowRight } from 'components/Icons'
|
||||
import { Text } from 'components/Text'
|
||||
|
||||
interface Props {
|
||||
isCreating: boolean
|
||||
createAccount: () => void
|
||||
}
|
||||
|
||||
export default function CreateAccount(props: Props) {
|
||||
return (
|
||||
<div className='relative z-10 w-full p-4'>
|
||||
<Text size='lg' className='mb-2 font-bold'>
|
||||
Create a Credit Account
|
||||
</Text>
|
||||
<Text className='mb-4 text-white/70'>
|
||||
Please approve the transaction in your wallet in order to create your first Credit Account.
|
||||
</Text>
|
||||
<Button
|
||||
className='w-full'
|
||||
showProgressIndicator={props.isCreating}
|
||||
text='Create Account'
|
||||
rightIcon={<ArrowRight />}
|
||||
onClick={props.createAccount}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
104
src/components/Account/FundAccount.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
'use client'
|
||||
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
import { Button } from 'components/Button'
|
||||
import { ArrowRight, Cross } from 'components/Icons'
|
||||
import SwitchWithLabel from 'components/SwitchWithLabel'
|
||||
import { Text } from 'components/Text'
|
||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
import useParams from 'utils/route'
|
||||
import useStore from 'store'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
|
||||
interface Props {
|
||||
setShowFundAccount: (show: boolean) => void
|
||||
setShowMenu: (show: boolean) => void
|
||||
}
|
||||
|
||||
export default function FundAccount(props: Props) {
|
||||
const params = useParams()
|
||||
const deposit = useStore((s) => s.deposit)
|
||||
|
||||
const [amount, setAmount] = useState(0)
|
||||
const [isLending, setIsLending] = useState(false)
|
||||
const [isFunding, setIsFunding] = useState(false)
|
||||
|
||||
const onChangeAmount = useCallback((amount: number) => {
|
||||
setAmount(amount)
|
||||
}, [])
|
||||
|
||||
const handleLendAssets = useCallback((val: boolean) => {
|
||||
setIsLending(val)
|
||||
/* TODO: handle lending assets */
|
||||
}, [])
|
||||
|
||||
async function onDeposit() {
|
||||
setIsFunding(true)
|
||||
// TODO: Make this dynamic (token select)
|
||||
const result = await deposit({
|
||||
fee: hardcodedFee,
|
||||
accountId: params.accountId,
|
||||
coin: {
|
||||
denom: ASSETS[0].denom,
|
||||
amount: amount.toString(),
|
||||
},
|
||||
})
|
||||
setIsFunding(false)
|
||||
if (result) {
|
||||
props.setShowMenu(false)
|
||||
props.setShowFundAccount(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='absolute right-4 top-4'>
|
||||
<Button
|
||||
onClick={() => props.setShowFundAccount(false)}
|
||||
leftIcon={<Cross />}
|
||||
className='h-8 w-8'
|
||||
iconClassName='h-2 w-2'
|
||||
color='tertiary'
|
||||
/>
|
||||
</div>
|
||||
<div className='relative z-10 w-full p-4'>
|
||||
<Text size='lg' className='mb-2 font-bold'>
|
||||
{`Fund Account ${params.accountId}`}
|
||||
</Text>
|
||||
<Text className='mb-4 text-white/70'>
|
||||
Deposit assets from your Osmosis address to your Mars credit account. Bridge assets if
|
||||
your Osmosis address has no assets.
|
||||
</Text>
|
||||
<TokenInputWithSlider
|
||||
asset={ASSETS[0]}
|
||||
onChange={onChangeAmount}
|
||||
amount={amount}
|
||||
max={new BigNumber(1).shiftedBy(ASSETS[0].decimals).toNumber()}
|
||||
className='mb-4'
|
||||
disabled={isFunding}
|
||||
/>
|
||||
<div className='mb-4 w-full border-b border-white/10' />
|
||||
<SwitchWithLabel
|
||||
name='isLending'
|
||||
label='Lend assets to earn yield'
|
||||
value={isLending}
|
||||
onChange={handleLendAssets}
|
||||
className='mb-4'
|
||||
tooltip="Fund your account and lend assets effortlessly! By lending, you'll earn attractive interest (APY) without impacting your LTV. It's a win-win situation - don't miss out on this easy opportunity to grow your holdings!"
|
||||
disabled={isFunding || amount === 0}
|
||||
/>
|
||||
<Button
|
||||
className='w-full'
|
||||
showProgressIndicator={isFunding}
|
||||
disabled={amount === 0}
|
||||
text='Fund Account'
|
||||
rightIcon={<ArrowRight />}
|
||||
onClick={onDeposit}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import { getAccountDebts } from 'utils/api'
|
||||
|
||||
interface Props {
|
||||
account: string
|
||||
accountId: string
|
||||
}
|
||||
|
||||
export async function AccountDebtTable(props: Props) {
|
||||
const debtData = await getAccountDebts(props.account)
|
||||
const debtData = await getAccountDebts(props.accountId)
|
||||
|
||||
return debtData.map((debt) => {
|
||||
return (
|
||||
|
@ -15,7 +15,7 @@ export default function Background() {
|
||||
'h-[20vw] w-[20vw]',
|
||||
'min-h-[150px] min-w-[150px]',
|
||||
'max-h-[500px] max-w-[500px]',
|
||||
'top-[-10vw] left-[-10vw]',
|
||||
'left-[-10vw] top-[-10vw]',
|
||||
'bg-orb-primary blur-orb-primary ',
|
||||
'translate-x-0 translate-y-0 rounded-full opacity-20',
|
||||
enableAnimations && 'animate-[float_120s_ease-in-out_infinite_2s]',
|
||||
@ -39,7 +39,7 @@ export default function Background() {
|
||||
'h-[25vw] w-[25vw]',
|
||||
'min-h-[120px] min-w-[120px]',
|
||||
'max-h-[600px] max-w-[600px]',
|
||||
'top-[-10vw] right-[-4vw]',
|
||||
'right-[-4vw] top-[-10vw]',
|
||||
'bg-orb-tertiary blur-orb-tertiary ',
|
||||
'translate-x-0 translate-y-0 rounded-full opacity-20',
|
||||
enableAnimations && 'animate-[float_180s_ease-in_infinite]',
|
||||
|
@ -10,7 +10,7 @@ interface Props extends PageProps {
|
||||
}
|
||||
|
||||
async function Content(props: Props) {
|
||||
const debtData = await getAccountDebts(props.params?.account)
|
||||
const debtData = await getAccountDebts(props.params?.accountId)
|
||||
const borrowData = await getBorrowData()
|
||||
|
||||
const marketAssets = getMarketAssets()
|
||||
|
@ -100,7 +100,7 @@ export const BorrowCapacity = ({
|
||||
WebkitMask: 'linear-gradient(#fff 0 0)',
|
||||
}}
|
||||
>
|
||||
<div className='absolute top-0 bottom-0 left-0 right-0 gradient-limit' />
|
||||
<div className='absolute bottom-0 left-0 right-0 top-0 gradient-limit' />
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
@ -1,6 +1,6 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import Image from 'next/image'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useState } from 'react'
|
||||
|
||||
import AccountSummary from 'components/Account/AccountSummary'
|
||||
import { Button } from 'components/Button'
|
||||
@ -8,24 +8,25 @@ import Card from 'components/Card'
|
||||
import Divider from 'components/Divider'
|
||||
import { ArrowRight } from 'components/Icons'
|
||||
import { Modal } from 'components/Modal'
|
||||
import Slider from 'components/Slider'
|
||||
import { Text } from 'components/Text'
|
||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||
import TokenInput from 'components/TokenInput'
|
||||
import useParams from 'hooks/useParams'
|
||||
import useStore from 'store'
|
||||
import { hardcodedFee } from 'utils/contants'
|
||||
import { formatPercent, formatValue } from 'utils/formatters'
|
||||
import TokenInputWithSlider from 'components/TokenInputWithSlider'
|
||||
import useParams from 'utils/route'
|
||||
|
||||
export default function BorrowModal() {
|
||||
const params = useParams()
|
||||
const [percentage, setPercentage] = useState(0)
|
||||
const [amount, setAmount] = useState(0)
|
||||
const [selectedAccount, setSelectedAccount] = useState(params.account)
|
||||
const [selectedAccount, setSelectedAccount] = useState(params.accountId)
|
||||
const modal = useStore((s) => s.borrowModal)
|
||||
const borrow = useStore((s) => s.borrow)
|
||||
const repay = useStore((s) => s.repay)
|
||||
const creditAccounts = useStore((s) => s.creditAccounts)
|
||||
const accounts = useStore((s) => s.accounts)?.map((account) => {
|
||||
return account.id
|
||||
})
|
||||
|
||||
function onAccountSelect(accountId: string) {
|
||||
setSelectedAccount(accountId)
|
||||
@ -56,24 +57,6 @@ export default function BorrowModal() {
|
||||
})
|
||||
}
|
||||
|
||||
const onSliderChange = useCallback(
|
||||
(percentage: number, maxAmount: number) => {
|
||||
const amount = new BigNumber(percentage).div(100).times(maxAmount).toNumber()
|
||||
|
||||
setAmount(amount)
|
||||
setPercentage(percentage)
|
||||
},
|
||||
[modal?.asset.decimals],
|
||||
)
|
||||
|
||||
const onInputChange = useCallback(
|
||||
(amount: number, maxAmount: number) => {
|
||||
setAmount(amount)
|
||||
setPercentage(new BigNumber(amount).div(maxAmount).times(100).toNumber())
|
||||
},
|
||||
[modal?.asset.decimals],
|
||||
)
|
||||
|
||||
if (!modal) return null
|
||||
|
||||
const liquidityAmount = Number(modal.marketData.liquidity?.amount || 0)
|
||||
@ -131,22 +114,21 @@ export default function BorrowModal() {
|
||||
className='w-full bg-white/5 p-4'
|
||||
contentClassName='gap-6 flex flex-col justify-between h-full'
|
||||
>
|
||||
<TokenInput
|
||||
<TokenInputWithSlider
|
||||
asset={modal.asset}
|
||||
onChange={(amount) => onInputChange(amount, maxAmount)}
|
||||
onChange={setAmount}
|
||||
amount={amount}
|
||||
max={maxAmount}
|
||||
/>
|
||||
<Slider value={percentage} onChange={(value) => onSliderChange(value, maxAmount)} />
|
||||
<Divider />
|
||||
<Text size='lg'>{modal.isRepay ? 'Repay for' : 'Borrow to'}</Text>
|
||||
<select
|
||||
name='creditAccount'
|
||||
name='account'
|
||||
value={selectedAccount}
|
||||
onChange={(e) => onAccountSelect(e.target.value)}
|
||||
className='rounded-base border border-white/10 bg-white/5 p-4'
|
||||
>
|
||||
{creditAccounts?.map((account) => (
|
||||
{accounts?.map((account) => (
|
||||
<option key={account} value={account}>
|
||||
{account}
|
||||
</option>
|
||||
|
@ -84,7 +84,7 @@ function glowElement(enableAnimations: boolean) {
|
||||
<svg
|
||||
className={classNames(
|
||||
enableAnimations && 'group-hover:animate-glow group-focus:animate-glow',
|
||||
'glow-container z-1 opacity-0 ',
|
||||
'glow-container isolate opacity-0',
|
||||
'pointer-events-none absolute inset-0 h-full w-full',
|
||||
)}
|
||||
>
|
||||
@ -159,13 +159,13 @@ export const Button = React.forwardRef(function Button(
|
||||
buttonVariantClasses[variant],
|
||||
variant === 'solid' && color === 'tertiary' && buttonBorderClasses,
|
||||
variant === 'solid' && color === 'primary' && buttonGradientClasses,
|
||||
disabled && 'pointer-events-none opacity-50',
|
||||
isDisabled && 'pointer-events-none opacity-50',
|
||||
hasFocus && focusClasses[color],
|
||||
className,
|
||||
)}
|
||||
id={id}
|
||||
ref={ref as LegacyRef<HTMLButtonElement>}
|
||||
onClick={disabled ? () => {} : onClick}
|
||||
onClick={isDisabled ? () => {} : onClick}
|
||||
>
|
||||
{leftIcon && !showProgressIndicator && (
|
||||
<span
|
||||
|
@ -4,26 +4,30 @@ import { ReactElement, ReactNode } from 'react'
|
||||
import { Text } from 'components/Text'
|
||||
|
||||
interface Props {
|
||||
title?: string | ReactElement
|
||||
children: ReactNode
|
||||
className?: string
|
||||
contentClassName?: string
|
||||
title?: string | ReactElement
|
||||
id?: string
|
||||
}
|
||||
|
||||
export default function Card(props: Props) {
|
||||
return (
|
||||
<section
|
||||
id={props.id}
|
||||
className={classNames(
|
||||
props.className,
|
||||
'relative z-1 max-w-full overflow-hidden rounded-base',
|
||||
'relative isolate max-w-full overflow-hidden rounded-base',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-base before:p-[1px] before:border-glas',
|
||||
)}
|
||||
>
|
||||
{props.title && (
|
||||
{typeof props.title === 'string' ? (
|
||||
<Text size='lg' className='flex w-full items-center bg-white/10 p-4 font-semibold'>
|
||||
{props.title}
|
||||
</Text>
|
||||
)}
|
||||
) : typeof props.title === 'object' ? (
|
||||
props.title
|
||||
) : null}
|
||||
<div className={classNames('w-full', props.contentClassName)}>{props.children}</div>
|
||||
</section>
|
||||
)
|
||||
|
@ -5,10 +5,10 @@ import Loading from 'components/Loading'
|
||||
import { Text } from 'components/Text'
|
||||
|
||||
async function Content(props: PageProps) {
|
||||
const wallet = props.params.wallet
|
||||
const address = props.params.address
|
||||
|
||||
return wallet ? (
|
||||
<Text size='sm'>{`Council page for ${wallet}`}</Text>
|
||||
return address ? (
|
||||
<Text size='sm'>{`Council page for ${address}`}</Text>
|
||||
) : (
|
||||
<Text size='sm'>Council view only</Text>
|
||||
)
|
||||
|
@ -5,15 +5,16 @@ import Loading from 'components/Loading'
|
||||
import { Text } from 'components/Text'
|
||||
|
||||
async function Content(props: PageProps) {
|
||||
const wallet = props.params.wallet
|
||||
const address = props.params.address
|
||||
|
||||
return wallet ? (
|
||||
<Text size='sm'>{`Earn page for ${wallet}`}</Text>
|
||||
) : (
|
||||
<Text size='sm' className='w-full text-center'>
|
||||
You need to be connected to use the earn page
|
||||
</Text>
|
||||
)
|
||||
if (!address)
|
||||
return (
|
||||
<Text size='sm' className='w-full text-center'>
|
||||
You need to be connected to use the earn page
|
||||
</Text>
|
||||
)
|
||||
|
||||
return <Text size='sm'>{`Earn page for ${address}`}</Text>
|
||||
}
|
||||
|
||||
function Fallback() {
|
||||
|
@ -35,7 +35,7 @@ export const Gauge = ({
|
||||
width={diameter}
|
||||
height={diameter}
|
||||
style={{ transform: 'rotate(-90deg)' }}
|
||||
className='absolute top-0 left-0'
|
||||
className='absolute left-0 top-0'
|
||||
>
|
||||
<linearGradient id='gradient'>
|
||||
<stop stopColor='rgba(255, 160, 187)' offset='0%'></stop>
|
||||
|
42
src/components/Header/DesktopHeader.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
import AccountMenu from 'components/Account/AccountMenu'
|
||||
import DesktopNavigation from 'components/Navigation/DesktopNavigation'
|
||||
import Settings from 'components/Settings'
|
||||
import Wallet from 'components/Wallet/Wallet'
|
||||
import { WalletConnectProvider } from 'components/Wallet/WalletConnectProvider'
|
||||
|
||||
export const menuTree: { href: RouteSegment; label: string }[] = [
|
||||
{ href: 'trade', label: 'Trade' },
|
||||
{ href: 'earn', label: 'Earn' },
|
||||
{ href: 'borrow', label: 'Borrow' },
|
||||
{ href: 'portfolio', label: 'Portfolio' },
|
||||
{ href: 'council', label: 'Council' },
|
||||
]
|
||||
|
||||
interface Props {
|
||||
params: PageParams
|
||||
}
|
||||
|
||||
export default function DesktopHeader(props: Props) {
|
||||
return (
|
||||
<header
|
||||
className={classNames(
|
||||
'fixed left-0 top-0 z-30 hidden w-full',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:h-full before:w-full before:rounded-sm before:backdrop-blur-sticky',
|
||||
'lg:block',
|
||||
)}
|
||||
>
|
||||
<div className='flex items-center justify-between border-b border-white/20 py-3 pl-6 pr-4'>
|
||||
<DesktopNavigation />
|
||||
<div className='flex gap-4'>
|
||||
<AccountMenu params={props.params} />
|
||||
<WalletConnectProvider>
|
||||
<Wallet />
|
||||
</WalletConnectProvider>
|
||||
<Settings />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
<svg version='1.1' viewBox='0 0 48 48' xmlns='http://www.w3.org/2000/svg'>
|
||||
<circle
|
||||
cx='24'
|
||||
cy='24'
|
||||
fill='none'
|
||||
r='23.5'
|
||||
stroke='currentColor'
|
||||
transform='rotate(180 24 24)'
|
||||
/>
|
||||
<path
|
||||
d='M32 25C32.5523 25 33 24.5523 33 24C33 23.4477 32.5523 23 32 23L32 25ZM15.2929 23.2929C14.9024 23.6834 14.9024 24.3166 15.2929 24.7071L21.6569 31.0711C22.0474 31.4616 22.6805 31.4616 23.0711 31.0711C23.4616 30.6805 23.4616 30.0474 23.0711 29.6569L17.4142 24L23.0711 18.3431C23.4616 17.9526 23.4616 17.3195 23.0711 16.9289C22.6805 16.5384 22.0474 16.5384 21.6569 16.9289L15.2929 23.2929ZM32 23L16 23L16 25L32 25L32 23Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 672 B |
3
src/components/Icons/ArrowCircledTopRight.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 10.0007V6.00069M10 6.00069H6.00004M10 6.00069L6.00004 10.0006M14.6666 8.00065C14.6666 11.6826 11.6818 14.6673 7.99992 14.6673C4.31802 14.6673 1.33325 11.6826 1.33325 8.00065C1.33325 4.31875 4.31802 1.33398 7.99992 1.33398C11.6818 1.33398 14.6666 4.31875 14.6666 8.00065Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 436 B |
@ -1,5 +0,0 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 24 24">
|
||||
<path fill='currentColor' d="M10.67,1.33v18.11l-6.21-6.21c-0.52-0.52-1.36-0.52-1.89,0c-0.52,0.52-0.52,1.36,0,1.89l8.49,8.49
|
||||
c0.52,0.52,1.36,0.52,1.89,0l8.49-8.49c0.52-0.52,0.52-1.36,0-1.89c-0.52-0.52-1.36-0.52-1.89,0l-6.21,6.21V1.33
|
||||
C13.33,0.6,12.74,0,12,0S10.67,0.6,10.67,1.33z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 382 B |
@ -1,6 +0,0 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 14 13">
|
||||
<path fill="currentColor" d="M13.8,6.6c0-0.5-0.3-0.8-0.9-0.8H6L4.4,5.8l2.2-2l1.5-1.5c0.2-0.2,0.3-0.4,0.3-0.6c0-0.5-0.3-0.8-0.8-0.8
|
||||
C7.3,0.9,7.1,1,6.9,1.2L2.1,6C2,6.1,1.9,6.2,1.9,6.4V1.6c0-0.5-0.4-0.8-0.8-0.8c-0.5,0-0.8,0.3-0.8,0.8v9.9c0,0.5,0.4,0.8,0.8,0.8
|
||||
c0.5,0,0.8-0.3,0.8-0.8V6.8c0,0.2,0.1,0.3,0.3,0.4L6.9,12c0.2,0.2,0.4,0.3,0.6,0.3c0.5,0,0.8-0.3,0.8-0.8c0-0.2-0.1-0.5-0.3-0.6
|
||||
L6.5,9.3l-2.2-2L6,7.4h7C13.4,7.4,13.8,7.1,13.8,6.6z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 537 B |
@ -1,3 +0,0 @@
|
||||
<svg viewBox="0 0 14 13" fill="currentColor">
|
||||
<path d="M0.234863 6.57567C0.234863 7.07288 0.581403 7.41188 1.08615 7.41188H8.04708L9.62912 7.33655L7.45194 9.31785L5.93771 10.8547C5.77951 11.0129 5.68157 11.2163 5.68157 11.4574C5.68157 11.9244 6.02811 12.2634 6.50272 12.2634C6.72872 12.2634 6.93213 12.173 7.12047 11.9922L11.859 7.20094C11.9871 7.07288 12.0775 6.92221 12.1152 6.74894V11.5478C12.1152 12.0148 12.4692 12.3538 12.9363 12.3538C13.4109 12.3538 13.765 12.0148 13.765 11.5478V1.6111C13.765 1.14403 13.4109 0.797485 12.9363 0.797485C12.4692 0.797485 12.1152 1.14403 12.1152 1.6111V6.39486C12.0775 6.22913 11.9871 6.07846 11.859 5.95039L7.12047 1.15156C6.93213 0.970755 6.72872 0.880354 6.50272 0.880354C6.02811 0.880354 5.68157 1.22689 5.68157 1.68644C5.68157 1.92751 5.77951 2.13845 5.93771 2.28911L7.45194 3.83348L9.62912 5.80725L8.04708 5.73192H1.08615C0.581403 5.73192 0.234863 6.07846 0.234863 6.57567Z" />
|
||||
</svg>
|
Before Width: | Height: | Size: 933 B |
@ -1,6 +0,0 @@
|
||||
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 24 24" >
|
||||
<path fill='currentColor' d="M13.33,22.67V4.55l6.21,6.21c0.52,0.52,1.36,0.52,1.89,0c0.52-0.52,0.52-1.36,0-1.89l-8.49-8.49
|
||||
c-0.52-0.52-1.36-0.52-1.89,0L2.57,8.88c-0.52,0.52-0.52,1.36,0,1.89c0.52,0.52,1.36,0.52,1.89,0l6.21-6.21v18.11
|
||||
c0,0.74,0.6,1.33,1.33,1.33C12.74,24,13.33,23.4,13.33,22.67z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 397 B |
@ -1,3 +0,0 @@
|
||||
<svg viewBox="0 0 14 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.6136 3.74679C13.5819 3.66496 13.5343 3.59019 13.4736 3.52679L10.8069 0.860124C10.7448 0.797965 10.671 0.748658 10.5898 0.715017C10.5085 0.681377 10.4215 0.664063 10.3336 0.664063C10.1561 0.664062 9.98579 0.734588 9.86026 0.860124C9.73472 0.985659 9.6642 1.15592 9.6642 1.33346C9.6642 1.51099 9.73472 1.68125 9.86026 1.80679L11.3936 3.33346H2.60692L4.14026 1.80679C4.20242 1.74463 4.25172 1.67084 4.28536 1.58962C4.319 1.50841 4.33632 1.42136 4.33632 1.33346C4.33632 1.24555 4.319 1.15851 4.28536 1.07729C4.25172 0.996076 4.20242 0.922283 4.14026 0.860124C4.0781 0.797965 4.0043 0.748658 3.92309 0.715017C3.84187 0.681377 3.75483 0.664062 3.66692 0.664063C3.57902 0.664063 3.49197 0.681377 3.41076 0.715017C3.32954 0.748658 3.25575 0.797965 3.19359 0.860124L0.526923 3.52679C0.466229 3.59019 0.418653 3.66496 0.386923 3.74679C0.320244 3.9091 0.320244 4.09115 0.386923 4.25346C0.418653 4.33529 0.466229 4.41005 0.526923 4.47346L3.19359 7.14012C3.25557 7.20261 3.3293 7.25221 3.41054 7.28605C3.49178 7.3199 3.57892 7.33732 3.66692 7.33732C3.75493 7.33732 3.84207 7.3199 3.92331 7.28605C4.00455 7.25221 4.07828 7.20261 4.14026 7.14012C4.20274 7.07815 4.25234 7.00441 4.28618 6.92317C4.32003 6.84194 4.33746 6.7548 4.33746 6.66679C4.33746 6.57878 4.32003 6.49165 4.28618 6.41041C4.25234 6.32917 4.20274 6.25543 4.14026 6.19346L2.60692 4.66679H11.3936L9.86026 6.19346C9.79777 6.25543 9.74817 6.32917 9.71433 6.41041C9.68048 6.49165 9.66306 6.57878 9.66306 6.66679C9.66306 6.7548 9.68048 6.84194 9.71433 6.92317C9.74817 7.00441 9.79777 7.07815 9.86026 7.14012C9.92223 7.20261 9.99597 7.25221 10.0772 7.28605C10.1584 7.3199 10.2456 7.33732 10.3336 7.33732C10.4216 7.33732 10.5087 7.3199 10.59 7.28605C10.6712 7.25221 10.7449 7.20261 10.8069 7.14012L13.4736 4.47346C13.5343 4.41005 13.5819 4.33529 13.6136 4.25346C13.6803 4.09115 13.6803 3.9091 13.6136 3.74679Z" fill="currentColor"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.9 KiB |
@ -1,7 +0,0 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'>
|
||||
<path
|
||||
fill-rule='evenodd'
|
||||
d='M6.97 2.47a.75.75 0 011.06 0l4.5 4.5a.75.75 0 01-1.06 1.06L8.25 4.81V16.5a.75.75 0 01-1.5 0V4.81L3.53 8.03a.75.75 0 01-1.06-1.06l4.5-4.5zm9.53 4.28a.75.75 0 01.75.75v11.69l3.22-3.22a.75.75 0 111.06 1.06l-4.5 4.5a.75.75 0 01-1.06 0l-4.5-4.5a.75.75 0 111.06-1.06l3.22 3.22V7.5a.75.75 0 01.75-.75z'
|
||||
clip-rule='evenodd'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 451 B |
@ -1,5 +0,0 @@
|
||||
<svg version='1.1' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'>
|
||||
<line stroke='currentColor' x1='3' x2='21' y1='12' y2='12' />
|
||||
<line stroke='currentColor' x1='3' x2='21' y1='6' y2='6' />
|
||||
<line stroke='currentColor' x1='3' x2='21' y1='18' y2='18' />
|
||||
</svg>
|
Before Width: | Height: | Size: 272 B |
@ -1,3 +0,0 @@
|
||||
<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 |
@ -1,6 +0,0 @@
|
||||
<svg viewBox='0 -28.5 256 256' version='1.1' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
fill='currentColor'
|
||||
d='M216.856339,16.5966031 C200.285002,8.84328665 182.566144,3.2084988 164.041564,0 C161.766523,4.11318106 159.108624,9.64549908 157.276099,14.0464379 C137.583995,11.0849896 118.072967,11.0849896 98.7430163,14.0464379 C96.9108417,9.64549908 94.1925838,4.11318106 91.8971895,0 C73.3526068,3.2084988 55.6133949,8.86399117 39.0420583,16.6376612 C5.61752293,67.146514 -3.4433191,116.400813 1.08711069,164.955721 C23.2560196,181.510915 44.7403634,191.567697 65.8621325,198.148576 C71.0772151,190.971126 75.7283628,183.341335 79.7352139,175.300261 C72.104019,172.400575 64.7949724,168.822202 57.8887866,164.667963 C59.7209612,163.310589 61.5131304,161.891452 63.2445898,160.431257 C105.36741,180.133187 151.134928,180.133187 192.754523,160.431257 C194.506336,161.891452 196.298154,163.310589 198.110326,164.667963 C191.183787,168.842556 183.854737,172.420929 176.223542,175.320965 C180.230393,183.341335 184.861538,190.991831 190.096624,198.16893 C211.238746,191.588051 232.743023,181.531619 254.911949,164.955721 C260.227747,108.668201 245.831087,59.8662432 216.856339,16.5966031 Z M85.4738752,135.09489 C72.8290281,135.09489 62.4592217,123.290155 62.4592217,108.914901 C62.4592217,94.5396472 72.607595,82.7145587 85.4738752,82.7145587 C98.3405064,82.7145587 108.709962,94.5189427 108.488529,108.914901 C108.508531,123.290155 98.3405064,135.09489 85.4738752,135.09489 Z M170.525237,135.09489 C157.88039,135.09489 147.510584,123.290155 147.510584,108.914901 C147.510584,94.5396472 157.658606,82.7145587 170.525237,82.7145587 C183.391518,82.7145587 193.761324,94.5189427 193.539891,108.914901 C193.539891,123.290155 183.391518,135.09489 170.525237,135.09489 Z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.7 KiB |
@ -1,5 +0,0 @@
|
||||
<svg viewBox='0 0 14 14' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M13.6668 3.8266C13.6673 3.73886 13.6505 3.65188 13.6174 3.57066C13.5842 3.48943 13.5353 3.41556 13.4735 3.35326L10.6468 0.526596C10.5845 0.464809 10.5107 0.415925 10.4294 0.382749C10.3482 0.349573 10.2612 0.332756 10.1735 0.333263C10.0858 0.332756 9.99879 0.349573 9.91757 0.382749C9.83634 0.415925 9.76247 0.464809 9.70017 0.526596L7.81351 2.41326L0.526841 9.69993C0.465053 9.76222 0.416169 9.8361 0.382993 9.91732C0.349817 9.99855 0.333 10.0855 0.333507 10.1733V12.9999C0.333507 13.1767 0.403745 13.3463 0.528769 13.4713C0.653794 13.5964 0.823363 13.6666 1.00017 13.6666H3.82684C3.92013 13.6717 4.01344 13.6571 4.10072 13.6238C4.188 13.5905 4.26731 13.5392 4.33351 13.4733L11.5802 6.1866L13.4735 4.33326C13.5344 4.26865 13.5839 4.19428 13.6202 4.11326C13.6266 4.06012 13.6266 4.0064 13.6202 3.95326C13.6233 3.92223 13.6233 3.89096 13.6202 3.85993L13.6668 3.8266ZM3.55351 12.3333H1.66684V10.4466L8.28684 3.8266L10.1735 5.71326L3.55351 12.3333ZM11.1135 4.77326L9.22684 2.8866L10.1735 1.9466L12.0535 3.8266L11.1135 4.77326Z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,6 +0,0 @@
|
||||
<svg viewBox='0 0 24 24'>
|
||||
<path
|
||||
d='M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 225 B |
3
src/components/Icons/ExclamationMarkCircled.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.99935 5.66797V9.0013M8.99935 12.3346H9.00768M17.3327 9.0013C17.3327 13.6037 13.6017 17.3346 8.99935 17.3346C4.39698 17.3346 0.666016 13.6037 0.666016 9.0013C0.666016 4.39893 4.39698 0.667969 8.99935 0.667969C13.6017 0.667969 17.3327 4.39893 17.3327 9.0013Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 421 B |
@ -1,12 +0,0 @@
|
||||
<svg version='1.1' viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M1.5 40C1.5 18.737 18.737 1.5 40 1.5C61.263 1.5 78.5 18.737 78.5 40C78.5 61.263 61.263 78.5 40 78.5C18.737 78.5 1.5 61.263 1.5 40Z'
|
||||
fill='none'
|
||||
stroke='currentColor'
|
||||
strokeWidth='3'
|
||||
/>
|
||||
<path
|
||||
d='M23.6128 21.9054L23.6128 21.9054C23.272 21.9056 22.9391 22.0074 22.6565 22.1979C22.374 22.3883 22.1546 22.6588 22.0265 22.9745C21.8985 23.2903 21.8675 23.6371 21.9375 23.9706C22.0076 24.3039 22.1753 24.6087 22.4194 24.8462C22.4195 24.8463 22.4197 24.8465 22.4199 24.8467L37.5753 40.0025L22.4199 55.1577C22.4197 55.1579 22.4196 55.1581 22.4194 55.1583C22.2567 55.3163 22.127 55.5051 22.0379 55.7137C21.9486 55.9225 21.9018 56.1469 21.9 56.374C21.8983 56.6011 21.9418 56.8262 22.0279 57.0364C22.114 57.2465 22.241 57.4374 22.4015 57.598C22.5621 57.7585 22.7529 57.8856 22.963 57.9718C23.1731 58.0579 23.3982 58.1016 23.6253 58.1C23.8525 58.0983 24.0769 58.0514 24.2857 57.9622C24.4943 57.8731 24.6831 57.7436 24.8412 57.5809C24.8414 57.5807 24.8416 57.5806 24.8417 57.5804L39.9973 42.4245L55.1536 57.5806C55.1537 57.5807 55.1538 57.5808 55.1539 57.5809C55.3122 57.743 55.5011 57.8719 55.7096 57.9605C55.9182 58.0491 56.1424 58.0955 56.3691 58.0968C56.5958 58.0982 56.8205 58.0546 57.0302 57.9684C57.2399 57.8823 57.4304 57.7553 57.5907 57.595C57.751 57.4347 57.8778 57.2442 57.9639 57.0345C58.05 56.8247 58.0936 56.6 58.0922 56.3733C58.0908 56.1466 58.0444 55.9225 57.9557 55.7139C57.8671 55.5055 57.7381 55.3166 57.5761 55.1584C57.5759 55.1582 57.5757 55.1581 57.5756 55.1579L42.4198 40.0025L57.5751 24.847C57.5753 24.8468 57.5756 24.8465 57.5758 24.8463C57.7395 24.6885 57.8701 24.4997 57.9601 24.2909C58.0502 24.0818 58.0978 23.8569 58.0999 23.6292C58.1021 23.4015 58.0588 23.1757 57.9727 22.9649C57.8866 22.7542 57.7593 22.5627 57.5983 22.4017C57.4373 22.2407 57.2458 22.1134 57.0351 22.0273C56.8243 21.9412 56.5985 21.8979 56.3708 21.9001C56.1432 21.9022 55.9182 21.9497 55.7091 22.0399C55.5003 22.1299 55.3115 22.2605 55.1537 22.4242C55.1535 22.4245 55.1533 22.4247 55.1531 22.4249L39.9973 37.5804L24.8417 22.4245C24.8415 22.4244 24.8414 22.4242 24.8412 22.424C24.6816 22.2599 24.4907 22.1295 24.2799 22.0405C24.0688 21.9513 23.842 21.9053 23.6128 21.9054Z'
|
||||
fill='currentColor'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.2 KiB |
@ -1,5 +0,0 @@
|
||||
<svg fill='currentColor' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M16 0.396c-8.839 0-16 7.167-16 16 0 7.073 4.584 13.068 10.937 15.183 0.803 0.151 1.093-0.344 1.093-0.772 0-0.38-0.009-1.385-0.015-2.719-4.453 0.964-5.391-2.151-5.391-2.151-0.729-1.844-1.781-2.339-1.781-2.339-1.448-0.989 0.115-0.968 0.115-0.968 1.604 0.109 2.448 1.645 2.448 1.645 1.427 2.448 3.744 1.74 4.661 1.328 0.14-1.031 0.557-1.74 1.011-2.135-3.552-0.401-7.287-1.776-7.287-7.907 0-1.751 0.62-3.177 1.645-4.297-0.177-0.401-0.719-2.031 0.141-4.235 0 0 1.339-0.427 4.4 1.641 1.281-0.355 2.641-0.532 4-0.541 1.36 0.009 2.719 0.187 4 0.541 3.043-2.068 4.381-1.641 4.381-1.641 0.859 2.204 0.317 3.833 0.161 4.235 1.015 1.12 1.635 2.547 1.635 4.297 0 6.145-3.74 7.5-7.296 7.891 0.556 0.479 1.077 1.464 1.077 2.959 0 2.14-0.020 3.864-0.020 4.385 0 0.416 0.28 0.916 1.104 0.755 6.4-2.093 10.979-8.093 10.979-15.156 0-8.833-7.161-16-16-16z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 944 B |
@ -1,3 +0,0 @@
|
||||
<svg fill='currentColor' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path d='M10 9C9.73479 9 9.48043 9.10536 9.2929 9.29289C9.10536 9.48043 9 9.73478 9 10V14C9 14.2652 9.10536 14.5196 9.2929 14.7071C9.48043 14.8946 9.73479 15 10 15C10.2652 15 10.5196 14.8946 10.7071 14.7071C10.8946 14.5196 11 14.2652 11 14V10C11 9.73478 10.8946 9.48043 10.7071 9.29289C10.5196 9.10536 10.2652 9 10 9ZM10.38 5.08C10.1365 4.97998 9.86347 4.97998 9.62 5.08C9.49725 5.12759 9.38511 5.19896 9.29 5.29C9.20167 5.3872 9.13065 5.49881 9.08 5.62C9.02402 5.73868 8.99662 5.86882 9 6C8.99924 6.13161 9.02447 6.26207 9.07423 6.38391C9.124 6.50574 9.19732 6.61656 9.29 6.71C9.38721 6.79833 9.49882 6.86936 9.62 6.92C9.7715 6.98224 9.93597 7.00632 10.099 6.99011C10.2619 6.97391 10.4184 6.91792 10.5547 6.82707C10.691 6.73622 10.8029 6.61328 10.8805 6.46907C10.9582 6.32486 10.9992 6.16378 11 6C10.9963 5.73523 10.8927 5.48163 10.71 5.29C10.6149 5.19896 10.5028 5.12759 10.38 5.08ZM10 0C8.02219 0 6.08879 0.58649 4.4443 1.6853C2.79981 2.78412 1.51809 4.3459 0.761209 6.17317C0.00433284 8.00043 -0.193701 10.0111 0.192152 11.9509C0.578004 13.8907 1.53041 15.6725 2.92894 17.0711C4.32746 18.4696 6.10929 19.422 8.0491 19.8079C9.98891 20.1937 11.9996 19.9957 13.8268 19.2388C15.6541 18.4819 17.2159 17.2002 18.3147 15.5557C19.4135 13.9112 20 11.9778 20 10C20 8.68678 19.7413 7.38642 19.2388 6.17317C18.7363 4.95991 17.9997 3.85752 17.0711 2.92893C16.1425 2.00035 15.0401 1.26375 13.8268 0.761205C12.6136 0.258658 11.3132 0 10 0V0ZM10 18C8.41775 18 6.87104 17.5308 5.55544 16.6518C4.23985 15.7727 3.21447 14.5233 2.60897 13.0615C2.00347 11.5997 1.84504 9.99113 2.15372 8.43928C2.4624 6.88743 3.22433 5.46197 4.34315 4.34315C5.46197 3.22433 6.88743 2.4624 8.43928 2.15372C9.99113 1.84504 11.5997 2.00346 13.0615 2.60896C14.5233 3.21447 15.7727 4.23984 16.6518 5.55544C17.5308 6.87103 18 8.41775 18 10C18 12.1217 17.1572 14.1566 15.6569 15.6569C14.1566 17.1571 12.1217 18 10 18V18Z' />
|
||||
</svg>
|
Before Width: | Height: | Size: 1.9 KiB |
@ -1,5 +0,0 @@
|
||||
<svg viewBox='0 0 33 19' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M18.6139 9.49984C18.6139 14.7465 14.4471 19 9.30681 19C4.16656 19 0 14.7478 0 9.49984C0 4.25188 4.16688 0 9.30681 0C14.4467 0 18.6139 4.25316 18.6139 9.49984ZM28.824 9.49984C28.824 14.4389 26.7404 18.4425 24.1704 18.4425C21.6004 18.4425 19.5168 14.4377 19.5168 9.49984C19.5168 4.56201 21.6004 0.557156 24.1704 0.557156C26.7404 0.557156 28.824 4.56201 28.824 9.49984ZM33 9.49984C33 13.925 32.2671 17.5121 31.3633 17.5121C30.4594 17.5121 29.7266 13.9238 29.7266 9.49984C29.7266 5.07592 30.4594 1.48756 31.3636 1.48756C32.2678 1.48756 33 5.07495 33 9.49984Z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 664 B |
Before Width: | Height: | Size: 200 B After Width: | Height: | Size: 200 B |
Before Width: | Height: | Size: 417 B After Width: | Height: | Size: 417 B |
@ -1,5 +0,0 @@
|
||||
<svg viewBox='0 0 24 24' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M15.57,15.284 C14.673,15.284 13.91925,14.5565 13.91925,13.6595 C13.91925,12.7625 14.673,12.011 15.57,12.011 C16.467,12.011 17.1945,12.7625 17.1945,13.6595 C17.1945,14.5565 16.467,15.284 15.57,15.284 M15.951,18.437 C15.1155,19.27175 13.827,19.6775 12.012,19.6775 C12.00825,19.6775 12.00375,19.67675 11.99925,19.67675 C11.9955,19.67675 11.991,19.6775 11.9865,19.6775 C10.1715,19.6775 8.88375,19.27175 8.049,18.437 C7.7925,18.1805 7.7925,17.76575 8.049,17.51 C8.30475,17.25425 8.7195,17.25425 8.976,17.51 C9.552,18.086 10.53675,18.3665 11.9865,18.3665 C11.991,18.3665 11.9955,18.36725 11.99925,18.36725 C12.00375,18.36725 12.00825,18.3665 12.012,18.3665 C13.46175,18.3665 14.44725,18.086 15.024,17.51 C15.2805,17.2535 15.69525,17.25425 15.951,17.51 C16.20675,17.7665 16.20675,18.18125 15.951,18.437 M6.8055,13.6595 C6.8055,12.76325 7.55775,12.011 8.454,12.011 C9.351,12.011 10.0785,12.76325 10.0785,13.6595 C10.0785,14.5565 9.351,15.284 8.454,15.284 C7.55775,15.284 6.8055,14.5565 6.8055,13.6595 M19.998,3.311 C20.6055,3.311 21.09975,3.80525 21.09975,4.412 C21.09975,5.0195 20.6055,5.51375 19.998,5.51375 C19.3905,5.51375 18.89625,5.0195 18.89625,4.412 C18.89625,3.80525 19.3905,3.311 19.998,3.311 M24,11.87525 C24,10.2845 22.70625,8.99075 21.1155,8.99075 C20.427,8.99075 19.79475,9.23375 19.29825,9.638 C17.5395,8.5325 15.3075,7.8665 12.915,7.7255 L14.163,3.77975 L17.59275,4.5875 C17.68275,5.83625 18.72675,6.82475 19.998,6.82475 C21.32775,6.82475 22.41,5.7425 22.41,4.412 C22.41,3.08225 21.32775,2 19.998,2 C19.068,2 18.2595,2.5295 17.85675,3.30275 L13.87125,2.3645 C13.5375,2.28575 13.2,2.47775 13.0965,2.80475 L11.547,7.70225 C8.96925,7.76525 6.546,8.4335 4.65825,9.6035 C4.1685,9.22025 3.55275,8.99075 2.8845,8.99075 C1.29375,8.99075 0,10.2845 0,11.87525 C0,12.8585 0.495,13.72775 1.24875,14.24825 C1.21725,14.477 1.20075,14.70725 1.20075,14.9405 C1.20075,16.92875 2.3565,18.77825 4.455,20.14775 C6.4665,21.461 9.129,22.184 11.95125,22.184 C14.7735,22.184 17.436,21.461 19.4475,20.14775 C21.546,18.77825 22.70175,16.92875 22.70175,14.9405 C22.70175,14.72825 22.6875,14.5175 22.66125,14.30825 C23.46525,13.796 24,12.89675 24,11.87525'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.2 KiB |
@ -1,5 +0,0 @@
|
||||
<svg version='1.1' fill='currentColor' viewBox='0 0 14 16' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M5.23995 0.800781C4.62778 0.800781 4.11995 1.3086 4.11995 1.92078V2.40078H1.07995C1.0633 2.39991 1.04661 2.39991 1.02995 2.40078C0.966911 2.40405 0.905131 2.41971 0.848141 2.44686C0.791151 2.47401 0.740068 2.51213 0.697808 2.55902C0.655549 2.60592 0.622941 2.66068 0.601847 2.72017C0.580753 2.77967 0.571586 2.84274 0.574869 2.90579C0.578153 2.96883 0.593822 3.0306 0.620983 3.08759C0.648144 3.14457 0.686264 3.19565 0.733167 3.2379C0.780069 3.28015 0.834835 3.31275 0.894337 3.33384C0.953839 3.35492 1.01691 3.36408 1.07995 3.36078H11.31L11 14.0658C10.9967 14.1795 10.9368 14.2408 10.84 14.2408H3.15995C3.06314 14.2408 3.00325 14.1795 2.99995 14.0658L2.71995 4.47078C2.71832 4.40774 2.70428 4.34564 2.67865 4.28803C2.65301 4.23041 2.61628 4.17841 2.57054 4.13499C2.52481 4.09158 2.47097 4.05759 2.4121 4.03499C2.35324 4.01238 2.29049 4.00158 2.22745 4.00323C2.16441 4.00487 2.10231 4.01891 2.0447 4.04455C1.98709 4.0702 1.93509 4.10693 1.89168 4.15267C1.84827 4.19841 1.81429 4.25225 1.79169 4.31113C1.76909 4.37 1.7583 4.43274 1.75995 4.49578L2.03995 14.0908C2.0572 14.6859 2.54765 15.2008 3.15995 15.2008H10.84C11.4523 15.2008 11.9427 14.6859 11.96 14.0908L12.27 3.36078H12.92C12.9836 3.36168 13.0467 3.34993 13.1057 3.32621C13.1648 3.30249 13.2185 3.26728 13.2638 3.22262C13.3091 3.17796 13.345 3.12474 13.3696 3.06605C13.3941 3.00737 13.4068 2.94439 13.4068 2.88078C13.4068 2.81717 13.3941 2.75419 13.3696 2.69551C13.345 2.63682 13.3091 2.58361 13.2638 2.53894C13.2185 2.49428 13.1648 2.45907 13.1057 2.43535C13.0467 2.41163 12.9836 2.39988 12.92 2.40078H9.87995V1.92078C9.87995 1.3086 9.37213 0.800781 8.75995 0.800781H5.23995ZM5.23995 1.76078H8.75995C8.8569 1.76078 8.91995 1.82384 8.91995 1.92078V2.40078H5.07995V1.92078C5.07995 1.82384 5.14301 1.76078 5.23995 1.76078ZM4.75495 4.95078C4.69149 4.95143 4.62879 4.96467 4.57048 4.98971C4.51216 5.01475 4.45939 5.05111 4.41522 5.09668C4.37104 5.14224 4.33635 5.19612 4.31313 5.25518C4.28991 5.31425 4.27863 5.37733 4.27995 5.44078V12.1608C4.27905 12.2244 4.2908 12.2875 4.31452 12.3466C4.33824 12.4056 4.37346 12.4593 4.41812 12.5046C4.46278 12.5499 4.516 12.5859 4.57468 12.6104C4.63336 12.635 4.69634 12.6476 4.75995 12.6476C4.82357 12.6476 4.88654 12.635 4.94523 12.6104C5.00391 12.5859 5.05713 12.5499 5.10179 12.5046C5.14645 12.4593 5.18166 12.4056 5.20538 12.3466C5.2291 12.2875 5.24085 12.2244 5.23995 12.1608V5.44078C5.24129 5.37649 5.2297 5.31258 5.20586 5.25286C5.18202 5.19313 5.14643 5.13881 5.10119 5.0931C5.05595 5.0474 5.00199 5.01125 4.94252 4.9868C4.88304 4.96235 4.81926 4.9501 4.75495 4.95078ZM6.99495 4.95078C6.93149 4.95143 6.86879 4.96467 6.81048 4.98971C6.75216 5.01475 6.69939 5.05111 6.65522 5.09668C6.61104 5.14224 6.57634 5.19612 6.55313 5.25518C6.52991 5.31425 6.51863 5.37733 6.51995 5.44078V12.1608C6.51905 12.2244 6.5308 12.2875 6.55452 12.3466C6.57824 12.4056 6.61345 12.4593 6.65812 12.5046C6.70278 12.5499 6.756 12.5859 6.81468 12.6104C6.87336 12.635 6.93634 12.6476 6.99995 12.6476C7.06356 12.6476 7.12654 12.635 7.18523 12.6104C7.24391 12.5859 7.29713 12.5499 7.34179 12.5046C7.38645 12.4593 7.42166 12.4056 7.44538 12.3466C7.4691 12.2875 7.48085 12.2244 7.47995 12.1608V5.44078C7.48129 5.37649 7.4697 5.31258 7.44586 5.25286C7.42202 5.19313 7.38643 5.13881 7.34119 5.0931C7.29595 5.0474 7.24199 5.01125 7.18252 4.9868C7.12304 4.96235 7.05926 4.9501 6.99495 4.95078ZM9.23495 4.95078C9.17149 4.95143 9.10879 4.96467 9.05048 4.98971C8.99216 5.01475 8.93939 5.05111 8.89522 5.09668C8.85104 5.14224 8.81635 5.19612 8.79313 5.25518C8.76991 5.31425 8.75863 5.37733 8.75995 5.44078V12.1608C8.75905 12.2244 8.7708 12.2875 8.79452 12.3466C8.81824 12.4056 8.85346 12.4593 8.89812 12.5046C8.94278 12.5499 8.996 12.5859 9.05468 12.6104C9.11336 12.635 9.17634 12.6476 9.23995 12.6476C9.30357 12.6476 9.36654 12.635 9.42523 12.6104C9.48391 12.5859 9.53713 12.5499 9.58179 12.5046C9.62645 12.4593 9.66166 12.4056 9.68538 12.3466C9.7091 12.2875 9.72085 12.2244 9.71995 12.1608V5.44078C9.72129 5.37649 9.7097 5.31258 9.68586 5.25286C9.66202 5.19313 9.62643 5.13881 9.58119 5.0931C9.53595 5.0474 9.48199 5.01125 9.42252 4.9868C9.36304 4.96235 9.29926 4.9501 9.23495 4.95078Z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 4.2 KiB |
@ -1,3 +0,0 @@
|
||||
<svg fill='none' stroke='currentColor' strokeLinecap='round' strokeLinejoin='round' strokeWidth='2' viewBox='0 0 24 24'>
|
||||
<path d='M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z'></path>
|
||||
</svg>
|
Before Width: | Height: | Size: 191 B |
@ -1,5 +0,0 @@
|
||||
<svg version='1.1' viewBox='0 0 14 13' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M8.07392 6.5156L12.9444 2.02749C13.3034 1.69622 13.3034 1.1598 12.9444 0.82853C12.5843 0.497261 12.0018 0.497261 11.6428 0.82853L6.77235 5.31631L1.90186 0.82853C1.54197 0.497261 0.960351 0.497261 0.600284 0.82853C0.241312 1.1598 0.241312 1.69622 0.600284 2.02749L5.47077 6.5156L0.600284 11.0036C0.241312 11.3343 0.241312 11.8711 0.600284 12.2028C0.780774 12.3681 1.01583 12.451 1.25107 12.451C1.48704 12.451 1.72228 12.3683 1.90167 12.2028L6.77216 7.71507L11.6427 12.2028C11.822 12.3681 12.0582 12.451 12.2933 12.451C12.5285 12.451 12.7636 12.3683 12.944 12.2028C13.303 11.8711 13.303 11.3343 12.944 11.0036L8.07392 6.5156Z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 746 B |
@ -1,17 +0,0 @@
|
||||
<svg fill='none' version='1.1' viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg'>
|
||||
<circle
|
||||
cx='40'
|
||||
cy='40'
|
||||
r='38.5'
|
||||
stroke='currentColor'
|
||||
strokeWidth='3'
|
||||
transform='rotate(180 40 40)'
|
||||
/>
|
||||
<path
|
||||
d='M22 43.5L34.507 54L59 27'
|
||||
stroke='currentColor'
|
||||
strokeLinecap='round'
|
||||
strokeLinejoin='round'
|
||||
strokeWidth='3'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 371 B |
@ -1,7 +0,0 @@
|
||||
<svg viewBox='0 0 28 24' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
fillRule='evenodd'
|
||||
clipRule='evenodd'
|
||||
d='M21.448 23.735C21.8236 24.0086 22.3078 24.077 22.7394 23.909C23.1711 23.7398 23.4884 23.3606 23.5841 22.901C24.5979 18.0002 27.0572 5.59578 27.98 1.13778C28.05 0.801779 27.9333 0.452578 27.6767 0.228178C27.42 0.00377795 27.0642 -0.0610223 26.7469 0.0601779C21.8551 1.92258 6.79031 7.73659 0.632783 10.0802C0.241959 10.229 -0.0123689 10.6154 0.000464152 11.039C0.0144638 11.4638 0.292124 11.8322 0.692282 11.9558C3.45372 12.8054 7.07847 13.9874 7.07847 13.9874C7.07847 13.9874 8.77243 19.2494 9.65558 21.9254C9.76641 22.2614 10.0219 22.5254 10.3591 22.6166C10.6951 22.7066 11.0544 22.6118 11.3052 22.3682C12.7238 20.9906 14.9171 18.8606 14.9171 18.8606C14.9171 18.8606 19.0844 22.0034 21.448 23.735ZM8.60327 13.3226L10.5621 19.9682L10.9972 15.7598C10.9972 15.7598 18.5652 8.73859 22.8794 4.73658C23.0054 4.61898 23.0229 4.42218 22.9179 4.28418C22.8141 4.14618 22.6228 4.11378 22.4793 4.20738C17.4791 7.49179 8.60327 13.3226 8.60327 13.3226Z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
4
src/components/Icons/TrashBin.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.66667 4.00065V3.46732C9.66667 2.72058 9.66667 2.34721 9.52134 2.062C9.39351 1.81111 9.18954 1.60714 8.93865 1.47931C8.65344 1.33398 8.28007 1.33398 7.53333 1.33398H6.46667C5.71993 1.33398 5.34656 1.33398 5.06135 1.47931C4.81046 1.60714 4.60649 1.81111 4.47866 2.062C4.33333 2.34721 4.33333 2.72058 4.33333 3.46732V4.00065M1 4.00065H13M11.6667 4.00065V11.4673C11.6667 12.5874 11.6667 13.1475 11.4487 13.5753C11.2569 13.9516 10.951 14.2576 10.5746 14.4493C10.1468 14.6673 9.58677 14.6673 8.46667 14.6673H5.53333C4.41323 14.6673 3.85318 14.6673 3.42535 14.4493C3.04903 14.2576 2.74307 13.9516 2.55132 13.5753C2.33333 13.1475 2.33333 12.5874 2.33333 11.4673V4.00065" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 827 B |
@ -1,3 +0,0 @@
|
||||
<svg version='1.1' viewBox='0 0 8 6' xmlns='http://www.w3.org/2000/svg' fill="currentColor">
|
||||
<path d='M4 6L0.535899 -1.75695e-07L7.4641 4.29987e-07L4 6Z' />
|
||||
</svg>
|
Before Width: | Height: | Size: 165 B |
@ -1,5 +0,0 @@
|
||||
<svg viewBox='0 0 24 24' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 615 B |
@ -1,3 +0,0 @@
|
||||
<svg viewBox='0 0 300 185' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path d='M61.4385429,36.2562612 C110.349767,-11.6319051 189.65053,-11.6319051 238.561752,36.2562612 L244.448297,42.0196786 C246.893858,44.4140867 246.893858,48.2961898 244.448297,50.690599 L224.311602,70.406102 C223.088821,71.6033071 221.106302,71.6033071 219.883521,70.406102 L211.782937,62.4749541 C177.661245,29.0669724 122.339051,29.0669724 88.2173582,62.4749541 L79.542302,70.9685592 C78.3195204,72.1657633 76.337001,72.1657633 75.1142214,70.9685592 L54.9775265,51.2530561 C52.5319653,48.8586469 52.5319653,44.9765439 54.9775265,42.5821357 L61.4385429,36.2562612 Z M280.206339,77.0300061 L298.128036,94.5769031 C300.573585,96.9713 300.573599,100.85338 298.128067,103.247793 L217.317896,182.368927 C214.872352,184.763353 210.907314,184.76338 208.461736,182.368989 C208.461726,182.368979 208.461714,182.368967 208.461704,182.368957 L151.107561,126.214385 C150.496171,125.615783 149.504911,125.615783 148.893521,126.214385 C148.893517,126.214389 148.893514,126.214393 148.89351,126.214396 L91.5405888,182.368927 C89.095052,184.763359 85.1300133,184.763399 82.6844276,182.369014 C82.6844133,182.369 82.684398,182.368986 82.6843827,182.36897 L1.87196327,103.246785 C-0.573596939,100.852377 -0.573596939,96.9702735 1.87196327,94.5758653 L19.7936929,77.028998 C22.2392531,74.6345898 26.2042918,74.6345898 28.6498531,77.028998 L86.0048306,133.184355 C86.6162214,133.782957 87.6074796,133.782957 88.2188704,133.184355 C88.2188796,133.184346 88.2188878,133.184338 88.2188969,133.184331 L145.571,77.028998 C148.016505,74.6345347 151.981544,74.6344449 154.427161,77.028798 C154.427195,77.0288316 154.427229,77.0288653 154.427262,77.028899 L211.782164,133.184331 C212.393554,133.782932 213.384814,133.782932 213.996204,133.184331 L271.350179,77.0300061 C273.79574,74.6355969 277.760778,74.6355969 280.206339,77.0300061 Z' />
|
||||
</svg>
|
Before Width: | Height: | Size: 1.9 KiB |
@ -1,5 +0,0 @@
|
||||
<svg viewBox='0 0 24 21' fill='currentColor' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M12 14.9998C11.8022 14.9998 11.6088 15.0584 11.4444 15.1683C11.2799 15.2782 11.1518 15.4344 11.0761 15.6171C11.0004 15.7998 10.9806 16.0009 11.0192 16.1949C11.0578 16.3889 11.153 16.567 11.2929 16.7069C11.4327 16.8467 11.6109 16.942 11.8049 16.9806C11.9989 17.0192 12.1999 16.9994 12.3827 16.9237C12.5654 16.848 12.7216 16.7198 12.8314 16.5554C12.9413 16.3909 13 16.1976 13 15.9998C13 15.7346 12.8946 15.4802 12.7071 15.2927C12.5195 15.1051 12.2652 14.9998 12 14.9998ZM22.67 16.4698L14.62 2.46978C14.3598 2.0033 13.9798 1.61474 13.5192 1.34425C13.0586 1.07376 12.5341 0.931152 12 0.931152C11.4658 0.931152 10.9414 1.07376 10.4808 1.34425C10.0202 1.61474 9.64016 2.0033 9.37997 2.46978L1.37997 16.4698C1.11076 16.9238 0.96611 17.4408 0.960612 17.9686C0.955114 18.4964 1.08897 19.0163 1.34865 19.4758C1.60834 19.9354 1.98467 20.3182 2.43965 20.5858C2.89463 20.8534 3.41215 20.9962 3.93997 20.9998H20.06C20.592 21.005 21.1159 20.8687 21.5779 20.6047C22.0399 20.3407 22.4233 19.9586 22.6889 19.4976C22.9546 19.0366 23.0928 18.5132 23.0895 17.9811C23.0861 17.4491 22.9414 16.9274 22.67 16.4698V16.4698ZM20.94 18.4698C20.8523 18.6257 20.7244 18.7553 20.5697 18.845C20.4149 18.9347 20.2389 18.9813 20.06 18.9798H3.93997C3.76108 18.9813 3.58507 18.9347 3.43029 18.845C3.2755 18.7553 3.14762 18.6257 3.05997 18.4698C2.9722 18.3178 2.92599 18.1453 2.92599 17.9698C2.92599 17.7942 2.9722 17.6218 3.05997 17.4698L11.06 3.46978C11.1439 3.30598 11.2714 3.16852 11.4284 3.07253C11.5854 2.97654 11.7659 2.92574 11.95 2.92574C12.134 2.92574 12.3145 2.97654 12.4715 3.07253C12.6286 3.16852 12.756 3.30598 12.84 3.46978L20.89 17.4698C20.9892 17.6196 21.0462 17.7934 21.055 17.9729C21.0638 18.1524 21.0241 18.331 20.94 18.4898V18.4698ZM12 6.99978C11.7348 6.99978 11.4804 7.10514 11.2929 7.29268C11.1053 7.48021 11 7.73457 11 7.99978V11.9998C11 12.265 11.1053 12.5194 11.2929 12.7069C11.4804 12.8944 11.7348 12.9998 12 12.9998C12.2652 12.9998 12.5195 12.8944 12.7071 12.7069C12.8946 12.5194 13 12.265 13 11.9998V7.99978C13 7.73457 12.8946 7.48021 12.7071 7.29268C12.5195 7.10514 12.2652 6.99978 12 6.99978Z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.1 KiB |
@ -1,5 +0,0 @@
|
||||
<svg fill='currentColor' viewBox='0 0 12 14' xmlns='http://www.w3.org/2000/svg'>
|
||||
<path
|
||||
d='M8.19317 9.85992L6.6665 11.3933V3.66659C6.6665 3.48977 6.59627 3.32021 6.47124 3.19518C6.34622 3.07016 6.17665 2.99992 5.99984 2.99992C5.82303 2.99992 5.65346 3.07016 5.52843 3.19518C5.40341 3.32021 5.33317 3.48977 5.33317 3.66659V11.3933L3.8065 9.85992C3.68097 9.73438 3.5107 9.66386 3.33317 9.66386C3.15564 9.66386 2.98537 9.73438 2.85984 9.85992C2.7343 9.98546 2.66378 10.1557 2.66378 10.3333C2.66378 10.5108 2.7343 10.681 2.85984 10.8066L5.5265 13.4733C5.58991 13.5339 5.66467 13.5815 5.7465 13.6133C5.8263 13.6485 5.91259 13.6667 5.99984 13.6667C6.08708 13.6667 6.17337 13.6485 6.25317 13.6133C6.335 13.5815 6.40977 13.5339 6.47317 13.4733L9.13984 10.8066C9.26537 10.681 9.3359 10.5108 9.3359 10.3333C9.3359 10.1557 9.26537 9.98546 9.13984 9.85992C9.07768 9.79776 9.00388 9.74845 8.92267 9.71481C8.84145 9.68117 8.75441 9.66386 8.6665 9.66386C8.48897 9.66386 8.31871 9.73438 8.19317 9.85992ZM10.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.4 KiB |
@ -1,6 +0,0 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 461.001 461.001'>
|
||||
<path
|
||||
fill='currentColor'
|
||||
d='M365.257,67.393H95.744C42.866,67.393,0,110.259,0,163.137v134.728 c0,52.878,42.866,95.744,95.744,95.744h269.513c52.878,0,95.744-42.866,95.744-95.744V163.137 C461.001,110.259,418.135,67.393,365.257,67.393z M300.506,237.056l-126.06,60.123c-3.359,1.602-7.239-0.847-7.239-4.568V168.607 c0-3.774,3.982-6.22,7.348-4.514l126.06,63.881C304.363,229.873,304.298,235.248,300.506,237.056z'
|
||||
/>
|
||||
</svg>
|
Before Width: | Height: | Size: 498 B |
@ -1,18 +1,10 @@
|
||||
// @index(['./*.svg'], f => `export { default as ${f.name} } from 'components/Icons/${f.name}.svg'`)
|
||||
export { default as Account } from 'components/Icons/Account.svg'
|
||||
export { default as Add } from 'components/Icons/Add.svg'
|
||||
export { default as ArrowBack } from 'components/Icons/ArrowBack.svg'
|
||||
export { default as ArrowChartLineUp } from 'components/Icons/ArrowChartLineUp.svg'
|
||||
export { default as ArrowDown } from 'components/Icons/ArrowDown.svg'
|
||||
export { default as ArrowCircledTopRight } from 'components/Icons/ArrowCircledTopRight.svg'
|
||||
export { default as ArrowDownLine } from 'components/Icons/ArrowDownLine.svg'
|
||||
export { default as ArrowLeftLine } from 'components/Icons/ArrowLeftLine.svg'
|
||||
export { default as ArrowRight } from 'components/Icons/ArrowRight.svg'
|
||||
export { default as ArrowRightLine } from 'components/Icons/ArrowRightLine.svg'
|
||||
export { default as ArrowsLeftRight } from 'components/Icons/ArrowsLeftRight.svg'
|
||||
export { default as ArrowsUpDown } from 'components/Icons/ArrowsUpDown.svg'
|
||||
export { default as ArrowUp } from 'components/Icons/ArrowUp.svg'
|
||||
export { default as ArrowUpLine } from 'components/Icons/ArrowUpLine.svg'
|
||||
export { default as BurgerMenu } from 'components/Icons/BurgerMenu.svg'
|
||||
export { default as Check } from 'components/Icons/Check.svg'
|
||||
export { default as CheckCircled } from 'components/Icons/CheckCircled.svg'
|
||||
export { default as ChevronDown } from 'components/Icons/ChevronDown.svg'
|
||||
@ -22,39 +14,22 @@ export { default as ChevronUp } from 'components/Icons/ChevronUp.svg'
|
||||
export { default as Copy } from 'components/Icons/Copy.svg'
|
||||
export { default as Cross } from 'components/Icons/Cross.svg'
|
||||
export { default as CrossCircled } from 'components/Icons/CrossCircled.svg'
|
||||
export { default as Deposit } from 'components/Icons/Deposit.svg'
|
||||
export { default as Discord } from 'components/Icons/Discord.svg'
|
||||
export { default as Edit } from 'components/Icons/Edit.svg'
|
||||
export { default as Ellipsis } from 'components/Icons/Ellipsis.svg'
|
||||
export { default as ExclamationMarkCircled } from 'components/Icons/ExclamationMarkCircled.svg'
|
||||
export { default as ExternalLink } from 'components/Icons/ExternalLink.svg'
|
||||
export { default as Failed } from 'components/Icons/Failed.svg'
|
||||
export { default as Gear } from 'components/Icons/Gear.svg'
|
||||
export { default as Github } from 'components/Icons/Github.svg'
|
||||
export { default as Heart } from 'components/Icons/Heart.svg'
|
||||
export { default as Info } from 'components/Icons/Info.svg'
|
||||
export { default as Logo } from 'components/Icons/Logo.svg'
|
||||
export { default as MarsProtocol } from 'components/Icons/MarsProtocol.svg'
|
||||
export { default as Medium } from 'components/Icons/Medium.svg'
|
||||
export { default as Osmo } from 'components/Icons/Osmo.svg'
|
||||
export { default as OverlayMark } from 'components/Icons/OverlayMark.svg'
|
||||
export { default as Plus } from 'components/Icons/Plus.svg'
|
||||
export { default as PlusCircled } from 'components/Icons/PlusCircled.svg'
|
||||
export { default as Questionmark } from 'components/Icons/Questionmark.svg'
|
||||
export { default as Reddit } from 'components/Icons/Reddit.svg'
|
||||
export { default as Rubbish } from 'components/Icons/Rubbish.svg'
|
||||
export { default as Search } from 'components/Icons/Search.svg'
|
||||
export { default as Shield } from 'components/Icons/Shield.svg'
|
||||
export { default as SliderMark } from 'components/Icons/SliderMark.svg'
|
||||
export { default as SmallClose } from 'components/Icons/SmallClose.svg'
|
||||
export { default as SortAsc } from 'components/Icons/SortAsc.svg'
|
||||
export { default as SortDesc } from 'components/Icons/SortDesc.svg'
|
||||
export { default as SortNone } from 'components/Icons/SortNone.svg'
|
||||
export { default as Subtract } from 'components/Icons/Subtract.svg'
|
||||
export { default as Success } from 'components/Icons/Success.svg'
|
||||
export { default as Telegram } from 'components/Icons/Telegram.svg'
|
||||
export { default as TriangleDown } from 'components/Icons/TriangleDown.svg'
|
||||
export { default as Twitter } from 'components/Icons/Twitter.svg'
|
||||
export { default as TrashBin } from 'components/Icons/TrashBin.svg'
|
||||
export { default as Wallet } from 'components/Icons/Wallet.svg'
|
||||
export { default as WalletConnect } from 'components/Icons/WalletConnect.svg'
|
||||
export { default as Warning } from 'components/Icons/Warning.svg'
|
||||
export { default as Withdraw } from 'components/Icons/Withdraw.svg'
|
||||
export { default as YouTube } from 'components/Icons/YouTube.svg'
|
||||
// @endindex
|
||||
|
@ -40,7 +40,7 @@ export const Modal = (props: Props) => {
|
||||
color='tertiary'
|
||||
/>
|
||||
</div>
|
||||
<div className={classNames(props.contentClassName, ' flex-grow')}>
|
||||
<div className={classNames(props.contentClassName, 'flex-grow')}>
|
||||
{props.children ? props.children : props.content}
|
||||
</div>
|
||||
</Card>
|
||||
|
@ -1,56 +1,33 @@
|
||||
'use client'
|
||||
|
||||
import classNames from 'classnames'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
|
||||
import AccountMenu from 'components/Account/AccountMenu'
|
||||
import { menuTree } from 'components/Header/DesktopHeader'
|
||||
import { Logo } from 'components/Icons'
|
||||
import { NavLink } from 'components/Navigation/NavLink'
|
||||
import Settings from 'components/Settings'
|
||||
import Wallet from 'components/Wallet/Wallet'
|
||||
import { getRoute } from 'utils/route'
|
||||
|
||||
export const menuTree: { href: RouteSegment; label: string }[] = [
|
||||
{ href: 'trade', label: 'Trade' },
|
||||
{ href: 'earn', label: 'Earn' },
|
||||
{ href: 'borrow', label: 'Borrow' },
|
||||
{ href: 'portfolio', label: 'Portfolio' },
|
||||
{ href: 'council', label: 'Council' },
|
||||
]
|
||||
import useParams, { getRoute } from 'utils/route'
|
||||
|
||||
export default function DesktopNavigation() {
|
||||
const pathname = usePathname() || ''
|
||||
const params = useParams()
|
||||
|
||||
return (
|
||||
<header
|
||||
className={classNames(
|
||||
'fixed top-0 left-0 z-30 hidden w-full',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:h-full before:w-full before:rounded-sm before:backdrop-blur-sticky',
|
||||
'lg:block',
|
||||
)}
|
||||
>
|
||||
<div className='flex items-center justify-between border-b border-white/20 py-3 pl-6 pr-4'>
|
||||
<div className='flex flex-grow items-center'>
|
||||
<Link href={getRoute(pathname, { page: 'trade' })}>
|
||||
<span className='block h-10 w-10'>
|
||||
<Logo />
|
||||
</span>
|
||||
</Link>
|
||||
<div className='flex gap-8 px-6'>
|
||||
{menuTree.map((item, index) => (
|
||||
<NavLink key={index} href={getRoute(pathname, { page: item.href })}>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex gap-4'>
|
||||
<AccountMenu />
|
||||
<Wallet />
|
||||
<Settings />
|
||||
</div>
|
||||
<div className='flex flex-grow items-center'>
|
||||
<Link href={getRoute(params, { page: 'trade' })}>
|
||||
<span className='block h-10 w-10'>
|
||||
<Logo />
|
||||
</span>
|
||||
</Link>
|
||||
<div className='flex gap-8 px-6'>
|
||||
{menuTree.map((item, index) => (
|
||||
<NavLink
|
||||
key={index}
|
||||
href={getRoute(params, { page: item.href })}
|
||||
isActive={params.page === item.href}
|
||||
>
|
||||
{item.label}
|
||||
</NavLink>
|
||||
))}
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,26 +1,23 @@
|
||||
import classNames from 'classnames'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
interface Props {
|
||||
href: string
|
||||
children: string | ReactNode
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
export const NavLink = ({ href, children }: Props) => {
|
||||
const pathname = usePathname()
|
||||
const isActive = pathname === href
|
||||
|
||||
export const NavLink = (props: Props) => {
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
href={props.href}
|
||||
className={classNames(
|
||||
'text-sm font-semibold hover:text-white active:text-white',
|
||||
isActive ? 'pointer-events-none text-white' : 'text-white/60',
|
||||
props.isActive ? 'pointer-events-none text-white' : 'text-white/60',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
{props.children}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ interface Props {
|
||||
maxLength?: number
|
||||
allowNegative?: boolean
|
||||
style?: {}
|
||||
disabled?: boolean
|
||||
|
||||
onChange: (amount: number) => void
|
||||
onBlur?: () => void
|
||||
onFocus?: () => void
|
||||
@ -25,7 +27,7 @@ function magnify(value: number, asset: Asset) {
|
||||
}
|
||||
|
||||
function demagnify(amount: number, asset: Asset) {
|
||||
return amount === 0 ? 0 : new BigNumber(amount).dividedBy(10 ** asset.decimals).toNumber()
|
||||
return amount === 0 ? 0 : new BigNumber(amount).dividedBy(-1 * asset.decimals).toNumber()
|
||||
}
|
||||
|
||||
export default function NumberInput(props: Props) {
|
||||
@ -43,7 +45,7 @@ export default function NumberInput(props: Props) {
|
||||
formatted: demagnify(props.amount, props.asset).toString(),
|
||||
value: demagnify(props.amount, props.asset),
|
||||
})
|
||||
}, [props.amount])
|
||||
}, [props.amount, props.asset])
|
||||
|
||||
useEffect(() => {
|
||||
if (!props.onRef) return
|
||||
@ -148,6 +150,7 @@ export default function NumberInput(props: Props) {
|
||||
onFocus={onInputFocus}
|
||||
onChange={(e) => onInputChange(e.target.value)}
|
||||
onBlur={props.onBlur}
|
||||
disabled={props.disabled}
|
||||
className={classNames(
|
||||
'w-full cursor-pointer appearance-none border-none bg-transparent text-right outline-none',
|
||||
props.className,
|
||||
|
@ -18,7 +18,7 @@ export const Overlay = ({ children, content, className, show, setShow }: Props)
|
||||
<>
|
||||
<div
|
||||
className={classNames(
|
||||
'max-w-screen absolute z-50 rounded-sm shadow-overlay backdrop-blur-lg gradient-popover',
|
||||
'max-w-screen absolute isolate z-50 rounded-sm shadow-overlay backdrop-blur-lg gradient-popover',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-sm before:p-[1px] before:border-glas',
|
||||
className,
|
||||
)}
|
||||
@ -26,7 +26,7 @@ export const Overlay = ({ children, content, className, show, setShow }: Props)
|
||||
{children ? children : content}
|
||||
</div>
|
||||
<div
|
||||
className='fixed top-0 left-0 z-40 block h-full w-full hover:cursor-pointer'
|
||||
className='fixed left-0 top-0 z-40 block h-full w-full hover:cursor-pointer'
|
||||
onClick={onClickAway}
|
||||
role='button'
|
||||
/>
|
||||
|
@ -1,27 +1,41 @@
|
||||
import { Suspense } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { Suspense } from 'react'
|
||||
|
||||
import Card from 'components/Card'
|
||||
import Loading from 'components/Loading'
|
||||
import { Text } from 'components/Text'
|
||||
import { getCreditAccounts } from 'utils/api'
|
||||
import { getAccounts } from 'utils/api'
|
||||
|
||||
async function Content(props: PageProps) {
|
||||
const wallet = props.params.wallet
|
||||
const currentAccount = props.params.account
|
||||
const address = props.params.address
|
||||
const currentAccount = props.params.accountId
|
||||
const hasAccount = !isNaN(Number(currentAccount))
|
||||
const creditAccounts = await getCreditAccounts(wallet)
|
||||
const account = await getAccounts(address)
|
||||
|
||||
return wallet ? (
|
||||
if (!address) {
|
||||
return (
|
||||
<Card
|
||||
className='h-fit w-full justify-center bg-white/5'
|
||||
title='Portfolio'
|
||||
contentClassName='px-4 py-6'
|
||||
>
|
||||
<Text size='sm' className='w-full text-center'>
|
||||
You need to be connected to view the porfolio page
|
||||
</Text>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('grid grid-cols-1 gap-4', 'md:grid-cols-2', 'lg:grid-cols-3')}>
|
||||
{creditAccounts.map((account: string, index: number) => (
|
||||
{account.map((account: Account, index: number) => (
|
||||
<Card
|
||||
className='h-fit w-full bg-white/5'
|
||||
title={`Account ${account}`}
|
||||
key={index}
|
||||
contentClassName='px-4 py-6'
|
||||
>
|
||||
{hasAccount && currentAccount === account ? (
|
||||
{hasAccount && currentAccount === account.id ? (
|
||||
<Text size='sm'>Current Account</Text>
|
||||
) : (
|
||||
<Text size='sm'>Account details</Text>
|
||||
@ -29,16 +43,6 @@ async function Content(props: PageProps) {
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<Card
|
||||
className='h-fit w-full justify-center bg-white/5'
|
||||
title='Portfolio'
|
||||
contentClassName='px-4 py-6'
|
||||
>
|
||||
<Text size='sm' className='w-full text-center'>
|
||||
You need to be connected to view the porfolio page
|
||||
</Text>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,62 +0,0 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { Text } from 'components/Text'
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
27
src/components/Radio.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
interface Props {
|
||||
active?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
export default function Radio(props: Props) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'group flex h-5 w-5 items-center justify-center rounded-full border',
|
||||
props.active && 'border-primary',
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={classNames(
|
||||
'h-3 w-3 rounded-full',
|
||||
props.active
|
||||
? 'bg-primary'
|
||||
: 'bg-white opacity-0 transition-opacity group-hover:opacity-100',
|
||||
props.className,
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
import classNames from 'classnames'
|
||||
import { ChangeEvent, useRef, useState } from 'react'
|
||||
import Draggable from 'react-draggable'
|
||||
|
||||
import { SliderMark } from 'components/Icons/index'
|
||||
import { OverlayMark } from 'components/Icons/index'
|
||||
|
||||
type Props = {
|
||||
value: number
|
||||
onChange: (value: number) => void
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default function Slider(props: Props) {
|
||||
@ -70,7 +73,15 @@ export default function Slider(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={ref} className='relative w-full' onMouseEnter={handleSliderRect}>
|
||||
<div
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
'relative min-h-3 w-full transition-opacity',
|
||||
props.className,
|
||||
props.disabled && 'pointer-events-none opacity-50',
|
||||
)}
|
||||
onMouseEnter={handleSliderRect}
|
||||
>
|
||||
<input
|
||||
type='range'
|
||||
value={props.value}
|
||||
@ -107,8 +118,8 @@ export default function Slider(props: Props) {
|
||||
}
|
||||
/>
|
||||
{(showTooltip || isDragging) && (
|
||||
<div className='absolute -top-8 left-1/2 -translate-x-1/2 rounded-xs bg-martian-red py-[2px] px-2 text-xs'>
|
||||
<SliderMark className='absolute left-1/2 bottom-[-4px] -z-1 h-2 -translate-x-1/2 text-martian-red' />
|
||||
<div className='absolute -top-8 left-1/2 -translate-x-1/2 rounded-xs bg-martian-red px-2 py-[2px] text-xs'>
|
||||
<OverlayMark className='absolute -bottom-2 left-1/2 -z-1 h-2 -translate-x-1/2 text-martian-red' />
|
||||
{props.value}%
|
||||
</div>
|
||||
)}
|
||||
|
@ -5,11 +5,18 @@ interface Props {
|
||||
checked: boolean
|
||||
onChange: (checked: boolean) => void
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default function Toggle(props: Props) {
|
||||
export default function Switch(props: Props) {
|
||||
return (
|
||||
<div className={classNames('relative', props.className)}>
|
||||
<div
|
||||
className={classNames(
|
||||
'relative transition-opacity',
|
||||
props.className,
|
||||
props.disabled && 'pointer-events-none opacity-50',
|
||||
)}
|
||||
>
|
||||
<input
|
||||
type='checkbox'
|
||||
id={props.name}
|
||||
@ -21,13 +28,20 @@ export default function Toggle(props: Props) {
|
||||
<label
|
||||
htmlFor={props.name}
|
||||
className={classNames(
|
||||
'flex cursor-pointer items-center justify-between',
|
||||
'isolate flex cursor-pointer items-center justify-between overflow-hidden',
|
||||
'relative h-5 w-10 rounded-full bg-white/20 shadow-sm',
|
||||
'before:content-[" "] before:absolute before:left-[1px] before:top-[1px]',
|
||||
'before:z-1 before:h-4.5 before:w-4.5 before:rounded-full before:bg-white before:transition-transform',
|
||||
'peer-checked:gradient-primary-to-secondary peer-checked:before:translate-x-5',
|
||||
'peer-checked:active group peer-checked:before:translate-x-5',
|
||||
)}
|
||||
></label>
|
||||
>
|
||||
<span
|
||||
className={classNames(
|
||||
'absolute inset-0 opacity-0 transition-opacity gradient-primary-to-secondary',
|
||||
props.checked && 'opacity-100',
|
||||
)}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
34
src/components/SwitchWithLabel.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import classNames from 'classnames'
|
||||
|
||||
import Switch from 'components/Switch'
|
||||
import { Text } from 'components/Text'
|
||||
import { Tooltip } from 'components/Tooltip'
|
||||
|
||||
interface Props {
|
||||
name: string
|
||||
label: string
|
||||
value: boolean
|
||||
onChange: (checked: boolean) => void
|
||||
className?: string
|
||||
tooltip?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default function SwitchWithLabel(props: Props) {
|
||||
return (
|
||||
<div className={classNames('flex w-full', props.className)}>
|
||||
<div className='flex flex-1'>
|
||||
<Text className='mr-2 text-white/70' size='sm'>
|
||||
{props.label}
|
||||
</Text>
|
||||
{props.tooltip && <Tooltip content={<Text size='sm'>{props.tooltip}</Text>} />}
|
||||
</div>
|
||||
<Switch
|
||||
name={props.name}
|
||||
checked={props.value}
|
||||
onChange={props.onChange}
|
||||
disabled={props.disabled}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
'use client'
|
||||
import classNames from 'classnames'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { toast as createToast, Slide, ToastContainer } from 'react-toastify'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { Button } from 'components/Button'
|
||||
import { CheckCircled, Cross, CrossCircled } from 'components/Icons'
|
||||
import { Text } from 'components/Text'
|
||||
import useStore from 'store'
|
||||
|
||||
import { Button } from './Button'
|
||||
|
||||
export default function Toaster() {
|
||||
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||
const toast = useStore((s) => s.toast)
|
||||
@ -18,7 +17,7 @@ export default function Toaster() {
|
||||
const Msg = () => (
|
||||
<div
|
||||
className={classNames(
|
||||
'relative z-1 m-0 flex w-full flex-wrap rounded-sm p-6 shadow-overlay backdrop-blur-lg',
|
||||
'relative isolate m-0 flex w-full flex-wrap rounded-sm p-6 shadow-overlay backdrop-blur-lg',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-sm before:p-[1px] before:border-glas',
|
||||
toast.isError ? 'bg-error-bg/20' : 'bg-success-bg/20',
|
||||
)}
|
||||
@ -32,7 +31,6 @@ export default function Toaster() {
|
||||
</span>
|
||||
</div>
|
||||
<Text
|
||||
size='base'
|
||||
className={classNames(
|
||||
'flex items-center font-bold',
|
||||
toast.isError ? 'text-error' : 'text-success',
|
||||
@ -45,7 +43,7 @@ export default function Toaster() {
|
||||
<Text size='sm' className='text-bold text-white'>
|
||||
{toast.message}
|
||||
</Text>
|
||||
<div className='absolute top-8 right-6 '>
|
||||
<div className='absolute right-6 top-8 '>
|
||||
<Button
|
||||
leftIcon={<Cross />}
|
||||
variant='transparent'
|
||||
@ -73,9 +71,10 @@ export default function Toaster() {
|
||||
closeButton={false}
|
||||
position='top-right'
|
||||
newestOnTop
|
||||
closeOnClick
|
||||
transition={enableAnimations ? Slide : undefined}
|
||||
className='p-0'
|
||||
toastClassName='top-[73px] z-50 m-0 mb-4 flex w-full bg-transparent p-0'
|
||||
toastClassName='top-[73px] z-20 m-0 mb-4 flex w-full bg-transparent p-0'
|
||||
bodyClassName='p-0 m-0 w-full flex'
|
||||
/>
|
||||
)
|
||||
|
@ -1,26 +1,34 @@
|
||||
import classNames from 'classnames'
|
||||
import Image from 'next/image'
|
||||
|
||||
import BigNumber from 'bignumber.js'
|
||||
import NumberInput from 'components/NumberInput'
|
||||
import { Text } from 'components/Text'
|
||||
import { useState } from 'react'
|
||||
|
||||
interface Props {
|
||||
amount: number
|
||||
max: number
|
||||
asset: Asset
|
||||
onChange: (amount: number) => void
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default function TokenInput(props: Props) {
|
||||
return (
|
||||
<div className='flex w-full flex-col gap-2'>
|
||||
<div
|
||||
className={classNames(
|
||||
'flex w-full flex-col gap-2 transition-opacity',
|
||||
props.className,
|
||||
props.disabled && 'pointer-events-none opacity-50',
|
||||
)}
|
||||
>
|
||||
<div className='box-content flex h-11 w-full rounded-sm border border-white/20 bg-white/5'>
|
||||
<div className='flex min-w-fit items-center gap-2 border-r border-white/20 bg-white/5 p-3'>
|
||||
<Image src={props.asset.logo} alt='token' width={20} height={20} />
|
||||
<Text size='base'>{props.asset.symbol}</Text>
|
||||
<Text>{props.asset.symbol}</Text>
|
||||
</div>
|
||||
<NumberInput
|
||||
disabled={props.disabled}
|
||||
asset={props.asset}
|
||||
maxDecimals={props.asset.decimals}
|
||||
onChange={props.onChange}
|
||||
|
56
src/components/TokenInputWithSlider.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
import Slider from './Slider'
|
||||
import TokenInput from './TokenInput'
|
||||
|
||||
interface Props {
|
||||
amount: number
|
||||
max: number
|
||||
asset: Asset
|
||||
onChange: (amount: number) => void
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default function TokenInputWithSlider(props: Props) {
|
||||
const [amount, setAmount] = useState(props.amount)
|
||||
const [percentage, setPercentage] = useState(0)
|
||||
|
||||
const onSliderChange = useCallback(
|
||||
(percentage: number, liquidityAmount: number) => {
|
||||
const newAmount = new BigNumber(percentage).div(100).times(liquidityAmount).toNumber()
|
||||
setPercentage(percentage)
|
||||
setAmount(newAmount)
|
||||
props.onChange(newAmount)
|
||||
},
|
||||
[props],
|
||||
)
|
||||
|
||||
const onInputChange = useCallback(
|
||||
(newAmount: number, liquidityAmount: number) => {
|
||||
setAmount(newAmount)
|
||||
setPercentage(new BigNumber(newAmount).div(liquidityAmount).times(100).toNumber())
|
||||
props.onChange(newAmount)
|
||||
},
|
||||
[props],
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={props.className}>
|
||||
<TokenInput
|
||||
asset={props.asset}
|
||||
onChange={(amount) => onInputChange(amount, props.max)}
|
||||
amount={amount}
|
||||
max={props.max}
|
||||
className='mb-4'
|
||||
disabled={props.disabled}
|
||||
/>
|
||||
<Slider
|
||||
value={percentage}
|
||||
onChange={(value) => onSliderChange(value, props.max)}
|
||||
disabled={props.disabled}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -2,7 +2,7 @@ import Tippy from '@tippyjs/react'
|
||||
import classNames from 'classnames'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
import { Questionmark } from 'components/Icons'
|
||||
import { ExclamationMarkCircled, Questionmark } from 'components/Icons'
|
||||
import useStore from 'store'
|
||||
|
||||
interface Props {
|
||||
@ -33,9 +33,10 @@ export const Tooltip = ({
|
||||
render={(attrs) => {
|
||||
return (
|
||||
<div
|
||||
className='max-w-[320px] rounded-lg px-4 py-2 text-xs shadow-tooltip gradient-tooltip'
|
||||
className='max-w-[320px] rounded-lg bg-black/80 p-4 pl-12 text-xs shadow-tooltip backdrop-blur-lg'
|
||||
{...attrs}
|
||||
>
|
||||
<ExclamationMarkCircled className='absolute left-4 top-3.5 h-5 w-5 text-white' />
|
||||
{content}
|
||||
</div>
|
||||
)
|
||||
@ -55,7 +56,7 @@ export const Tooltip = ({
|
||||
) : (
|
||||
<span
|
||||
className={classNames(
|
||||
'mb-2 inline-block w-[18px] cursor-pointer opacity-40 hover:opacity-80',
|
||||
'inline-block w-[18px] cursor-pointer opacity-40 hover:opacity-80',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
@ -5,10 +5,10 @@ import Loading from 'components/Loading'
|
||||
import { Text } from 'components/Text'
|
||||
|
||||
async function Content(props: PageProps) {
|
||||
const wallet = props.params.wallet
|
||||
const address = props.params.address
|
||||
|
||||
return wallet ? (
|
||||
<Text size='sm'>{`Order book for ${wallet}`}</Text>
|
||||
return address ? (
|
||||
<Text size='sm'>{`Order book for ${address}`}</Text>
|
||||
) : (
|
||||
<Text size='sm' className='w-full text-center'>
|
||||
You need to be connected to see the order book
|
||||
|
@ -5,21 +5,15 @@ import Loading from 'components/Loading'
|
||||
import { Text } from 'components/Text'
|
||||
|
||||
async function Content(props: PageProps) {
|
||||
const wallet = props.params.wallet
|
||||
const currentAccount = props.params.account
|
||||
const address = props.params.address
|
||||
const currentAccount = props.params.accountId
|
||||
const hasAccount = !isNaN(Number(currentAccount))
|
||||
|
||||
return wallet ? (
|
||||
<>
|
||||
{hasAccount ? (
|
||||
<Text size='sm'>{`Trade with Account ${currentAccount}`}</Text>
|
||||
) : (
|
||||
<Text size='sm'>Select an Account to trade</Text>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Text size='sm'>You need to be connected to trade</Text>
|
||||
)
|
||||
if (!address) return <Text size='sm'>You need to be connected to trade</Text>
|
||||
|
||||
if (!hasAccount) return <Text size='sm'>Select an Account to trade</Text>
|
||||
|
||||
return <Text size='sm'>{`Trade with Account ${currentAccount}`}</Text>
|
||||
}
|
||||
|
||||
function Fallback() {
|
||||
|
@ -1,6 +1,5 @@
|
||||
'use client'
|
||||
|
||||
import { Coin } from '@cosmjs/stargate'
|
||||
import {
|
||||
ChainInfoID,
|
||||
SimpleChainInfoList,
|
||||
@ -20,7 +19,7 @@ import { Check, Copy, ExternalLink, Osmo } from 'components/Icons'
|
||||
import { Overlay } from 'components/Overlay/Overlay'
|
||||
import { Text } from 'components/Text'
|
||||
import useStore from 'store'
|
||||
import { getWalletBalances } from 'utils/api'
|
||||
import { Endpoints, getEndpoint, getWalletBalancesSWR } from 'utils/api'
|
||||
import { getBaseAsset } from 'utils/assets'
|
||||
import { formatValue, truncate } from 'utils/formatters'
|
||||
|
||||
@ -33,8 +32,10 @@ export default function ConnectedButton() {
|
||||
const address = useStore((s) => s.client?.recentWallet.account?.address)
|
||||
const network = useStore((s) => s.client?.recentWallet.network)
|
||||
const baseAsset = getBaseAsset()
|
||||
|
||||
const { data, isLoading } = useSWR(address, getWalletBalances)
|
||||
const { data, isLoading } = useSWR(
|
||||
getEndpoint(Endpoints.WALLET_BALANCES, { address }),
|
||||
getWalletBalancesSWR,
|
||||
)
|
||||
|
||||
// ---------------
|
||||
// LOCAL STATE
|
||||
@ -95,7 +96,7 @@ export default function ConnectedButton() {
|
||||
<div
|
||||
className={classNames(
|
||||
'relative ml-2 flex h-full items-center pl-2 number',
|
||||
'before:content-[" "] before:absolute before:top-0.5 before:bottom-1.5 before:left-0 before:h-[calc(100%-4px)] before:border-l before:border-white/20',
|
||||
'before:content-[" "] before:absolute before:bottom-1.5 before:left-0 before:top-0.5 before:h-[calc(100%-4px)] before:border-l before:border-white/20',
|
||||
)}
|
||||
>
|
||||
{isLoading ? (
|
||||
|
@ -11,9 +11,8 @@ import { useEffect } from 'react'
|
||||
|
||||
import ConnectButton from 'components/Wallet/ConnectButton'
|
||||
import ConnectedButton from 'components/Wallet/ConnectedButton'
|
||||
import useParams from 'hooks/useParams'
|
||||
import useParams from 'utils/route'
|
||||
import useStore from 'store'
|
||||
import { getCreditAccounts } from 'utils/api'
|
||||
|
||||
export default function Wallet() {
|
||||
const router = useRouter()
|
||||
@ -33,19 +32,11 @@ export default function Wallet() {
|
||||
? {
|
||||
address: recentWallet?.account.address,
|
||||
}
|
||||
: { address: undefined, creditAccounts: null, client: undefined },
|
||||
: { address: undefined, accounts: null, client: undefined },
|
||||
)
|
||||
|
||||
if (!isConnected || !recentWallet) return
|
||||
|
||||
const fetchCreditAccounts = async () => {
|
||||
if (!recentWallet?.account.address) return
|
||||
const walletCreditAccounts = await getCreditAccounts(recentWallet?.account.address)
|
||||
useStore.setState({ creditAccounts: walletCreditAccounts })
|
||||
}
|
||||
|
||||
fetchCreditAccounts()
|
||||
|
||||
if (!client) {
|
||||
const getCosmWasmClient = async () => {
|
||||
const cosmClient = await getClient(recentWallet.network.rpc)
|
||||
@ -63,7 +54,7 @@ export default function Wallet() {
|
||||
getCosmWasmClient()
|
||||
}
|
||||
|
||||
if (!address || address === params.wallet) return
|
||||
if (!address || address === params.address) return
|
||||
router.push(`/wallets/${address}`)
|
||||
}, [address, broadcast, client, params, recentWallet, router, simulate, sign, status])
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { WalletManagerProvider } from '@marsprotocol/wallet-connector'
|
||||
import { ChainInfoID, WalletManagerProvider } from '@marsprotocol/wallet-connector'
|
||||
import { FC } from 'react'
|
||||
|
||||
import { Button } from 'components/Button'
|
||||
@ -21,7 +21,7 @@ export const WalletConnectProvider: FC<Props> = ({ children }) => {
|
||||
const chainInfoOverrides = {
|
||||
rpc: ENV.URL_RPC,
|
||||
rest: ENV.URL_REST,
|
||||
chainID: ENV.CHAIN_ID,
|
||||
chainID: ENV.CHAIN_ID as ChainInfoID,
|
||||
}
|
||||
const enabledWallets: string[] = ENV.WALLETS
|
||||
|
||||
|
@ -1,26 +0,0 @@
|
||||
import { usePathname } from 'next/navigation'
|
||||
|
||||
export default function useParams() {
|
||||
const pathname = usePathname()
|
||||
const params = {
|
||||
wallet: '',
|
||||
account: '',
|
||||
page: '',
|
||||
}
|
||||
|
||||
if (!pathname) return params
|
||||
|
||||
const segments = pathname.split('/')
|
||||
|
||||
segments.forEach((segment, index) => {
|
||||
if (segment === 'wallets' && segments[index + 1]) {
|
||||
params.wallet = segments[index + 1]
|
||||
} else if (segment === 'accounts' && segments[index + 1]) {
|
||||
params.account = segments[index + 1]
|
||||
} else if (index === 5) {
|
||||
params.page = segment
|
||||
}
|
||||
})
|
||||
|
||||
return params
|
||||
}
|
12
src/middleware.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { NextResponse } from 'next/server'
|
||||
|
||||
export function middleware(request: Request) {
|
||||
const requestHeaders = new Headers(request.headers)
|
||||
requestHeaders.set('x-url', request.url)
|
||||
|
||||
return NextResponse.next({
|
||||
request: {
|
||||
headers: requestHeaders,
|
||||
},
|
||||
})
|
||||
}
|
@ -9,12 +9,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
const accountId = req.query.id
|
||||
|
||||
const position: Position = await (
|
||||
const account: Account = await (
|
||||
await fetch(`${ENV.URL_API}/accounts/${accountId}${VERCEL_BYPASS}`)
|
||||
).json()
|
||||
|
||||
if (position) {
|
||||
return res.status(200).json(position.debts)
|
||||
if (account) {
|
||||
return res.status(200).json(account.debts)
|
||||
}
|
||||
|
||||
return res.status(404)
|
||||
|
@ -9,12 +9,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
const accountId = req.query.id
|
||||
|
||||
const position: Position = await (
|
||||
const account: Account = await (
|
||||
await fetch(`${ENV.URL_API}/accounts/${accountId}${VERCEL_BYPASS}`)
|
||||
).json()
|
||||
|
||||
if (position) {
|
||||
return res.status(200).json(position.deposits)
|
||||
if (account) {
|
||||
return res.status(200).json(account.deposits)
|
||||
}
|
||||
|
||||
return res.status(404)
|
||||
|
@ -13,14 +13,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
const client = await CosmWasmClient.connect(ENV.URL_RPC)
|
||||
|
||||
const data: PositionResponse = await client.queryContractSmart(ENV.ADDRESS_CREDIT_MANAGER, {
|
||||
const account: AccountResponse = await client.queryContractSmart(ENV.ADDRESS_CREDIT_MANAGER, {
|
||||
positions: {
|
||||
account_id: accountId,
|
||||
},
|
||||
})
|
||||
|
||||
if (data) {
|
||||
return res.status(200).json(resolvePositionResponse(data))
|
||||
if (account) {
|
||||
return res.status(200).json(resolvePositionResponse(account))
|
||||
}
|
||||
|
||||
return res.status(404)
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Coin } from '@cosmjs/stargate'
|
||||
import { gql, request as gqlRequest } from 'graphql-request'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
import { Coin } from '@cosmjs/stargate'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import { ENV, ENV_MISSING_MESSAGE, VERCEL_BYPASS } from 'constants/env'
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!ENV.URL_API) {
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Coin } from '@cosmjs/stargate'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import { ENV, ENV_MISSING_MESSAGE, VERCEL_BYPASS } from 'constants/env'
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { gql, request as gqlRequest } from 'graphql-request'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { Coin } from '@cosmjs/stargate'
|
||||
|
||||
import { ENV, ENV_MISSING_MESSAGE } from 'constants/env'
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
|
26
src/pages/api/wallets/[address]/accounts/ids.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import { ENV, ENV_MISSING_MESSAGE } from 'constants/env'
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!ENV.URL_RPC || !ENV.ADDRESS_ACCOUNT_NFT) {
|
||||
return res.status(404).json(ENV_MISSING_MESSAGE)
|
||||
}
|
||||
|
||||
const address = req.query.address
|
||||
|
||||
const client = await CosmWasmClient.connect(ENV.URL_RPC)
|
||||
|
||||
const data = await client.queryContractSmart(ENV.ADDRESS_ACCOUNT_NFT, {
|
||||
tokens: {
|
||||
owner: address,
|
||||
},
|
||||
})
|
||||
|
||||
if (data.tokens) {
|
||||
return res.status(200).json(data.tokens)
|
||||
}
|
||||
|
||||
return res.status(404)
|
||||
}
|
@ -1,25 +1,34 @@
|
||||
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import { ENV, ENV_MISSING_MESSAGE } from 'constants/env'
|
||||
import { ENV, ENV_MISSING_MESSAGE, VERCEL_BYPASS } from 'constants/env'
|
||||
import { resolvePositionResponses } from 'utils/resolvers'
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!ENV.URL_RPC || !ENV.ADDRESS_ACCOUNT_NFT) {
|
||||
if (!ENV.URL_RPC || !ENV.ADDRESS_CREDIT_MANAGER || !ENV.URL_API) {
|
||||
return res.status(404).json(ENV_MISSING_MESSAGE)
|
||||
}
|
||||
|
||||
const address = req.query.address
|
||||
|
||||
const accountIds: string[] = await (
|
||||
await fetch(`${ENV.URL_API}/wallets/${address}/accounts/ids${VERCEL_BYPASS}`)
|
||||
).json()
|
||||
|
||||
const client = await CosmWasmClient.connect(ENV.URL_RPC)
|
||||
|
||||
const data = await client.queryContractSmart(ENV.ADDRESS_ACCOUNT_NFT, {
|
||||
tokens: {
|
||||
owner: address,
|
||||
},
|
||||
})
|
||||
const $accounts: Promise<AccountResponse>[] = accountIds.map((accountId) =>
|
||||
client.queryContractSmart(ENV.ADDRESS_CREDIT_MANAGER!, {
|
||||
positions: {
|
||||
account_id: `${accountId}`,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
if (data.tokens) {
|
||||
return res.status(200).json(data.tokens)
|
||||
const accounts = await Promise.all($accounts).then((accounts) => accounts)
|
||||
|
||||
if (accounts) {
|
||||
return res.status(200).json(resolvePositionResponses(accounts))
|
||||
}
|
||||
|
||||
return res.status(404)
|
||||
|
@ -1,35 +0,0 @@
|
||||
import { CosmWasmClient } from '@cosmjs/cosmwasm-stargate'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
import { ENV, ENV_MISSING_MESSAGE, VERCEL_BYPASS } from 'constants/env'
|
||||
import { resolvePositionResponses } from 'utils/resolvers'
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
if (!ENV.URL_RPC || !ENV.ADDRESS_CREDIT_MANAGER || !ENV.URL_API) {
|
||||
return res.status(404).json(ENV_MISSING_MESSAGE)
|
||||
}
|
||||
|
||||
const address = req.query.address
|
||||
|
||||
const accounts: string[] = await (
|
||||
await fetch(`${ENV.URL_API}/wallets/${address}/accounts${VERCEL_BYPASS}`)
|
||||
).json()
|
||||
|
||||
const client = await CosmWasmClient.connect(ENV.URL_RPC)
|
||||
|
||||
const $positions: Promise<PositionResponse>[] = accounts.map((account) =>
|
||||
client.queryContractSmart(ENV.ADDRESS_CREDIT_MANAGER!, {
|
||||
positions: {
|
||||
account_id: `${account}`,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
const positions = await Promise.all($positions).then((positions) => positions)
|
||||
|
||||
if (positions) {
|
||||
return res.status(200).json(resolvePositionResponses(positions))
|
||||
}
|
||||
|
||||
return res.status(404)
|
||||
}
|