* fix: fixed the trading chart load

* fix: prevent wrapped checkboxes to be double clicked

* fix: refactored funding account modal

* fix: fixed modal classes

* fix: adjusted width classes

* fix: fixed the slider masks

* listed: TIA and USDT

* fix: fixed the slider initial position

* env: version update
This commit is contained in:
Linkie Link 2023-11-15 16:27:05 +01:00 committed by GitHub
parent e11875f74f
commit b0c9cca51c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 145 additions and 81 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "mars-v2-frontend", "name": "mars-v2-frontend",
"version": "2.0.4", "version": "2.0.5",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "yarn validate-env && next build", "build": "yarn validate-env && next build",

View File

@ -1,10 +1,8 @@
import getOraclePrices from 'api/prices/getOraclePrices' import getOraclePrices from 'api/prices/getOraclePrices'
import getPoolPrice from 'api/prices/getPoolPrice' import getPoolPrice from 'api/prices/getPoolPrice'
import fetchPythPrices from 'api/prices/getPythPrices' import fetchPythPrices from 'api/prices/getPythPrices'
import { ENV } from 'constants/env'
import useStore from 'store' import useStore from 'store'
import { BNCoin } from 'types/classes/BNCoin' import { BNCoin } from 'types/classes/BNCoin'
import { NETWORK } from 'types/enums/network'
import { partition } from 'utils/array' import { partition } from 'utils/array'
import { getAssetsMustHavePriceInfo } from 'utils/assets' import { getAssetsMustHavePriceInfo } from 'utils/assets'
@ -59,13 +57,13 @@ function separateAssetsByPriceSources(assets: Asset[]) {
// Only fetch Pyth prices for mainnet // Only fetch Pyth prices for mainnet
const [assetsWithPythPriceFeedId, assetsWithoutPythPriceFeedId] = partition( const [assetsWithPythPriceFeedId, assetsWithoutPythPriceFeedId] = partition(
assets, assets,
(asset) => !!asset.pythPriceFeedId && ENV.NETWORK === NETWORK.MAINNET, (asset) => !!asset.pythPriceFeedId,
) )
// Don't get oracle price if it's not mainnet and there is a poolId // Don't get oracle price if it's not mainnet and there is a poolId
const [assetsWithOraclePrice, assetsWithoutOraclePrice] = partition( const [assetsWithOraclePrice, assetsWithoutOraclePrice] = partition(
assetsWithoutPythPriceFeedId, assetsWithoutPythPriceFeedId,
(asset) => (asset.hasOraclePrice && ENV.NETWORK === NETWORK.MAINNET) || !asset.poolId, (asset) => asset.hasOraclePrice || !asset.poolId,
) )
const assetsWithPoolId = assetsWithoutOraclePrice.filter((asset) => !!asset.poolId) const assetsWithPoolId = assetsWithoutOraclePrice.filter((asset) => !!asset.poolId)

View File

@ -74,7 +74,7 @@ export default function AccountSummary(props: Props) {
if (!props.account) return null if (!props.account) return null
return ( return (
<div className='h-[546px] min-w-92.5 basis-92.5 max-w-screen overflow-y-scroll scrollbar-hide'> <div className='h-[546px] max-w-screen overflow-y-scroll scrollbar-hide w-93.5'>
<Card className='mb-4 h-min min-w-fit bg-white/10' contentClassName='flex'> <Card className='mb-4 h-min min-w-fit bg-white/10' contentClassName='flex'>
<Item label='Net worth' classes='flex-1'> <Item label='Net worth' classes='flex-1'>
<DisplayCurrency <DisplayCurrency

View File

@ -8,19 +8,27 @@ interface Props {
onChange: (checked: boolean) => void onChange: (checked: boolean) => void
name: string name: string
text?: string text?: string
noMouseEvents?: boolean
} }
export default function Checkbox(props: Props) { export default function Checkbox(props: Props) {
return ( return (
<> <>
<label className='flex items-center gap-2 border-white cursor-pointer'> <input
<input onChange={() => props.onChange(props.checked)}
onChange={() => props.onChange(props.checked)} id={`checkbox-${props.name}`}
name={props.name} name={props.name}
checked={props.checked} checked={props.checked}
type='checkbox' type='checkbox'
className='absolute w-0 h-0 opacity-0' className={classNames('peer hidden')}
/> />
<label
className={classNames(
'flex items-center gap-2 border-white cursor-pointer',
props.noMouseEvents && 'pointer-events-none',
)}
htmlFor={`checkbox-${props.name}`}
>
<div <div
className={classNames( className={classNames(
'h-5 w-5 rounded-sm p-0.5', 'h-5 w-5 rounded-sm p-0.5',

View File

@ -38,6 +38,7 @@ export default function useAssetTableColumns(isBorrow: boolean) {
name={`asset-${asset.id.toLowerCase()}`} name={`asset-${asset.id.toLowerCase()}`}
checked={row.getIsSelected()} checked={row.getIsSelected()}
onChange={row.getToggleSelectedHandler()} onChange={row.getToggleSelectedHandler()}
noMouseEvents
/> />
<AssetImage asset={asset} size={24} className='ml-4' /> <AssetImage asset={asset} size={24} className='ml-4' />
<div className='ml-2 text-left'> <div className='ml-2 text-left'>

View File

@ -1,24 +1,14 @@
import AccountSummary from 'components/Account/AccountSummary'
import Card from 'components/Card'
import FundAccount from 'components/Modals/FundWithdraw/FundAccount' import FundAccount from 'components/Modals/FundWithdraw/FundAccount'
import WithdrawFromAccount from 'components/Modals/FundWithdraw/WithdrawFromAccount' import WithdrawFromAccount from 'components/Modals/FundWithdraw/WithdrawFromAccount'
interface Props { interface Props {
account: Account account?: Account
isFunding: boolean isFunding: boolean
} }
export default function FundWithdrawModalContent(props: Props) { export default function FundWithdrawModalContent(props: Props) {
const { account, isFunding } = props const { account, isFunding } = props
return ( if (!account) return null
<div className='flex items-start flex-1 gap-6 p-6'> if (isFunding) return <FundAccount account={account} />
<Card return <WithdrawFromAccount account={account} />
className='flex flex-1 p-4 bg-white/5'
contentClassName='gap-6 flex flex-col justify-between h-full min-h-[380px]'
>
{isFunding ? <FundAccount account={account} /> : <WithdrawFromAccount account={account} />}
</Card>
<AccountSummary account={account} />
</div>
)
} }

View File

@ -1,12 +1,13 @@
import { CircularProgress } from 'components/CircularProgress'
import Modal from 'components/Modal'
import FundWithdrawModalContent from 'components/Modals/FundWithdraw/FundAndWithdrawModalContent' import FundWithdrawModalContent from 'components/Modals/FundWithdraw/FundAndWithdrawModalContent'
import ModalContentWithSummary from 'components/Modals/ModalContentWithSummary'
import Text from 'components/Text' import Text from 'components/Text'
import useCurrentAccount from 'hooks/useCurrentAccount' import useAccount from 'hooks/useAccount'
import useAccountId from 'hooks/useAccountId'
import useStore from 'store' import useStore from 'store'
export default function FundAndWithdrawModal() { export default function FundAndWithdrawModal() {
const currentAccount = useCurrentAccount() const accountId = useAccountId()
const { data: account } = useAccount(accountId ?? undefined)
const modal = useStore<string | null>((s) => s.fundAndWithdrawModal) const modal = useStore<string | null>((s) => s.fundAndWithdrawModal)
const isFunding = modal === 'fund' const isFunding = modal === 'fund'
@ -16,27 +17,20 @@ export default function FundAndWithdrawModal() {
if (!modal) return null if (!modal) return null
return ( return (
<Modal <ModalContentWithSummary
onClose={onClose} account={account}
isContentCard
header={ header={
<span className='flex items-center gap-4 px-4'> <span className='flex items-center gap-4 px-4'>
<Text> <Text>
{isFunding {isFunding
? `Fund Credit Account ${currentAccount?.id ?? '0'}` ? `Fund Credit Account ${accountId ?? ''}`
: `Withdraw from Credit Account ${currentAccount?.id ?? '0'}`} : `Withdraw from Credit Account ${accountId ?? ''}`}
</Text> </Text>
</span> </span>
} }
headerClassName='gradient-header pl-2 pr-2.5 py-2.5 border-b-white/5 border-b' onClose={onClose}
contentClassName='flex flex-col min-h-[400px]' content={<FundWithdrawModalContent account={account} isFunding={isFunding} />}
> />
{modal && currentAccount ? (
<FundWithdrawModalContent account={currentAccount} isFunding={isFunding} />
) : (
<div className='flex items-center justify-center w-full h-[380px]'>
<CircularProgress />
</div>
)}
</Modal>
) )
} }

View File

@ -3,12 +3,35 @@ import React from 'react'
import AccountSummary from 'components/Account/AccountSummary' import AccountSummary from 'components/Account/AccountSummary'
import Card from 'components/Card' import Card from 'components/Card'
import { CircularProgress } from 'components/CircularProgress'
import Modal, { ModalProps } from 'components/Modal' import Modal, { ModalProps } from 'components/Modal'
import useStore from 'store' import useStore from 'store'
interface Props extends ModalProps { interface Props extends ModalProps {
account: Account account?: Account
isContentCard?: boolean isContentCard?: boolean
subHeader?: React.ReactNode
}
function modalContent(content: React.ReactNode, isContentCard?: boolean, account?: Account) {
if (!account)
return (
<div className='flex items-center justify-center w-full h-[380px]'>
<CircularProgress />
</div>
)
if (isContentCard)
return (
<Card
className='flex flex-1 p-4 bg-white/5'
contentClassName='gap-6 flex flex-col justify-between h-full min-h-[380px]'
>
{content}
</Card>
)
return content
} }
export default function ModalContentWithSummary(props: Props) { export default function ModalContentWithSummary(props: Props) {
@ -22,17 +45,9 @@ export default function ModalContentWithSummary(props: Props) {
)} )}
contentClassName={classNames('flex items-start flex-1 gap-6 p-6', props.contentClassName)} contentClassName={classNames('flex items-start flex-1 gap-6 p-6', props.contentClassName)}
> >
{props.isContentCard ? ( {props.subHeader && props.subHeader}
<Card {modalContent(props.content, props.isContentCard, props.account)}
className='flex flex-1 p-4 bg-white/5' {props.account && <AccountSummary account={updatedAccount || props.account} />}
contentClassName='gap-6 flex flex-col justify-between h-full min-h-[380px]'
>
{props.content}
</Card>
) : (
props.content
)}
<AccountSummary account={updatedAccount || props.account} />
</Modal> </Modal>
) )
} }

View File

@ -136,7 +136,7 @@ export default function VaultModalContent(props: Props) {
return ( return (
<div className='flex items-start flex-1 gap-6 p-6'> <div className='flex items-start flex-1 gap-6 p-6'>
<Accordion <Accordion
className='h-[546px] overflow-y-scroll scrollbar-hide' className='h-[546px] overflow-y-scroll scrollbar-hide flex-1'
items={[ items={[
{ {
renderContent: () => ( renderContent: () => (

View File

@ -16,10 +16,11 @@ export default function Track(props: Props) {
percentage = ((props.sliderValue - minValue) / (props.maxValue - minValue)) * 100 percentage = ((props.sliderValue - minValue) / (props.maxValue - minValue)) * 100
} }
return ( return (
<div className='relative flex-1 h-1 bg-white/20 rounded-sm w-1'> <div className='relative flex-1 w-1 h-1 rounded-sm bg-white/20'>
<div <div
className={classNames( className={classNames(
'h-1 z-1 rounded-sm w-1', 'relative z-1',
'h-1 rounded-sm w-1',
'before:absolute', 'before:absolute',
'before:top-0 before:bottom-0 before:right-0 before:left-0', 'before:top-0 before:bottom-0 before:right-0 before:left-0',
percentage > 0 && props.bg, percentage > 0 && props.bg,

View File

@ -1,5 +1,5 @@
import classNames from 'classnames' import classNames from 'classnames'
import { ChangeEvent, useRef, useState } from 'react' import { ChangeEvent, useEffect, useMemo, useRef, useState } from 'react'
import Draggable from 'react-draggable' import Draggable from 'react-draggable'
import { OverlayMark } from 'components/Icons' import { OverlayMark } from 'components/Icons'
@ -98,6 +98,17 @@ export default function Slider(props: Props) {
const DraggableElement: any = Draggable const DraggableElement: any = Draggable
const [positionOffset, position] = useMemo(() => {
return [
{ x: (props.value / 100) * -12, y: 0 },
{ x: (sliderRect.width / 100) * props.value, y: -2 },
]
}, [props.value, sliderRect.width])
useEffect(() => {
handleSliderRect()
}, [])
return ( return (
<div> <div>
<div <div
@ -164,10 +175,10 @@ export default function Slider(props: Props) {
axis='x' axis='x'
grid={[sliderRect.width / 100, 0]} grid={[sliderRect.width / 100, 0]}
bounds={{ left: 0, right: sliderRect.width }} bounds={{ left: 0, right: sliderRect.width }}
positionOffset={{ x: (props.value / 100) * -12, y: 0 }} positionOffset={positionOffset}
onDrag={handleDrag} onDrag={handleDrag}
onStop={() => setIsDragging(false)} onStop={() => setIsDragging(false)}
position={{ x: (sliderRect.width / 100) * props.value, y: -2 }} position={position}
> >
<div ref={nodeRef} className='absolute z-20 leading-3'> <div ref={nodeRef} className='absolute z-20 leading-3'>
<div <div
@ -202,7 +213,7 @@ export default function Slider(props: Props) {
)} )}
</div> </div>
{props.leverage && ( {props.leverage && (
<div className='pt-2 flex justify-between'> <div className='flex justify-between pt-2'>
<LeverageLabel <LeverageLabel
leverage={1} leverage={1}
decimals={0} decimals={0}

View File

@ -2,8 +2,8 @@ import dynamic from 'next/dynamic'
import Script from 'next/script' import Script from 'next/script'
import { useState } from 'react' import { useState } from 'react'
import { CircularProgress } from 'components/CircularProgress'
import Card from 'components/Card' import Card from 'components/Card'
import { CircularProgress } from 'components/CircularProgress'
const TVChartContainer = dynamic( const TVChartContainer = dynamic(
() => import('components/Trade/TradeChart/TVChartContainer').then((mod) => mod.TVChartContainer), () => import('components/Trade/TradeChart/TVChartContainer').then((mod) => mod.TVChartContainer),
@ -26,6 +26,9 @@ export default function TradeChart(props: Props) {
onReady={() => { onReady={() => {
setIsScriptReady(true) setIsScriptReady(true)
}} }}
onLoad={() => {
setIsScriptReady(true)
}}
/> />
{isScriptReady ? ( {isScriptReady ? (
<TVChartContainer buyAsset={props.buyAsset} sellAsset={props.sellAsset} /> <TVChartContainer buyAsset={props.buyAsset} sellAsset={props.sellAsset} />

View File

@ -157,6 +157,25 @@ export const ASSETS: Asset[] = [
pythHistoryFeedId: 'Crypto.USDC/USD', pythHistoryFeedId: 'Crypto.USDC/USD',
poolId: ENV.NETWORK === NETWORK.DEVNET ? 678 : 1221, poolId: ENV.NETWORK === NETWORK.DEVNET ? 678 : 1221,
}, },
{
symbol: 'USDT',
id: 'USDT',
name: 'Tether',
denom: 'ibc/4ABBEF4C8926DDDB320AE5188CFD63267ABBCEFC0583E4AE05D6E5AA2401DDAB',
color: '#50af95',
logo: '/images/tokens/usdt.svg',
decimals: 6,
hasOraclePrice: true,
isEnabled: true,
isMarket: true,
isDisplayCurrency: true,
isStable: true,
isAutoLendEnabled: true,
isBorrowEnabled: true,
pythPriceFeedId: '0x2b89b9dc8fdf9f34709a5b106b472f0f39bb6ca9ce04b0fd7f2e971688e2e53b',
poolId: 1077,
pythHistoryFeedId: 'Crypto.USDT/USD',
},
{ {
symbol: 'AXL', symbol: 'AXL',
name: 'Axelar', name: 'Axelar',
@ -174,6 +193,24 @@ export const ASSETS: Asset[] = [
pythHistoryFeedId: 'Crypto.AXL/USD', pythHistoryFeedId: 'Crypto.AXL/USD',
poolId: 812, poolId: 812,
}, },
{
symbol: 'INJ',
id: 'INJ',
name: 'Injective',
denom: 'ibc/64BA6E31FE887D66C6F8F31C7B1A80C7CA179239677B4088BB55F5EA07DBE273',
color: '#00F2FE',
logo: '/images/tokens/inj.svg',
decimals: 18,
hasOraclePrice: true,
isEnabled: true,
isMarket: true,
isDisplayCurrency: true,
isAutoLendEnabled: true,
isBorrowEnabled: true,
pythPriceFeedId: '0x7a5bc1d2b56ad029048cd63964b3ad2776eadf812edc1a43a31406cb54bff592',
poolId: 725,
pythHistoryFeedId: 'Crypto.INJ/USD',
},
{ {
symbol: 'TIA', symbol: 'TIA',
id: 'TIA', id: 'TIA',

View File

@ -827,9 +827,10 @@ export default function createBroadcastSlice(
result: undefined, result: undefined,
error: 'Transaction failed', error: 'Transaction failed',
} }
} catch (e: unknown) { } catch (error) {
const error = typeof e === 'string' ? e : 'Transaction failed' const e = error as { message: string }
return { result: undefined, error } console.log(e)
return { result: undefined, error: e.message }
} }
}, },
} }

View File

@ -3,38 +3,42 @@ interface Asset {
name: string name: string
denom: string denom: string
symbol: symbol:
| 'OSMO'
| 'ATOM' | 'ATOM'
| 'AXL'
| 'INJ'
| 'MARS' | 'MARS'
| 'OSMO'
| 'stATOM' | 'stATOM'
| 'stOSMO' | 'stOSMO'
| 'AXL'
| 'TIA' | 'TIA'
| 'USDC.axl' | 'USDC.axl'
| 'USDC' | 'USDC'
| 'USDT'
| 'WBTC.axl' | 'WBTC.axl'
| 'WETH.axl' | 'WETH.axl'
| 'OSMO-USDC.n' | 'OSMO-USDC.n'
| '$'
| 'OSMO-ATOM' | 'OSMO-ATOM'
| 'OSMO-USDC.axl' | 'OSMO-USDC.axl'
| 'OSMO-WETH.axl' | 'OSMO-WETH.axl'
| 'OSMO-WBTC.axl' | 'OSMO-WBTC.axl'
| 'stATOM-ATOM' | 'stATOM-ATOM'
| '$'
id: id:
| 'OSMO'
| 'ATOM' | 'ATOM'
| 'MARS'
| 'stATOM'
| 'stOSMO'
| 'AXL' | 'AXL'
| 'TIA' | 'INJ'
| 'axlUSDC' | 'axlUSDC'
| 'axlWBTC' | 'axlWBTC'
| 'axlWETH' | 'axlWETH'
| 'USDC' | 'MARS'
| 'OSMO-USDC.n' | 'OSMO'
| 'stATOM'
| 'stOSMO'
| 'TIA'
| 'USD' | 'USD'
| 'USDC'
| 'USDT'
| 'OSMO-USDC.n'
| 'gamm/pool/12' | 'gamm/pool/12'
| 'gamm/pool/1' | 'gamm/pool/1'
| 'gamm/pool/678' | 'gamm/pool/678'

View File

@ -16,6 +16,6 @@ export function getSingleValueFromBroadcastResult(
export function generateErrorMessage(result: BroadcastResult, errorMessage?: string) { export function generateErrorMessage(result: BroadcastResult, errorMessage?: string) {
const error = result.error ? result.error : result.result?.rawLogs const error = result.error ? result.error : result.result?.rawLogs
if (errorMessage) return errorMessage if (errorMessage) return errorMessage
if (error === 'Transaction failed') return 'Transaction rejected by user' if (error === 'Transaction failed: Request rejected') return 'Transaction rejected by user'
return `Transaction failed: ${error}` return `Transaction failed: ${error}`
} }

View File

@ -258,6 +258,7 @@ module.exports = {
60: '240px', 60: '240px',
90: '360px', 90: '360px',
92.5: '370px', 92.5: '370px',
93.5: '374px',
100: '400px', 100: '400px',
110: '440px', 110: '440px',
120: '480px', 120: '480px',