Mp 2435 display currency (#155)
This commit is contained in:
parent
4847121180
commit
0a796a3d94
@ -28,14 +28,6 @@ const accountCardHeaderClasses = classNames(
|
||||
'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()
|
||||
@ -108,11 +100,7 @@ export default function AccountList(props: Props) {
|
||||
{isActive ? (
|
||||
<>
|
||||
<div className='w-full border border-transparent border-b-white/20 p-4'>
|
||||
<AccountStats
|
||||
balance={formatValue(selectedAccountBalance, formatOptions)}
|
||||
risk={75}
|
||||
health={0.85}
|
||||
/>
|
||||
<AccountStats balance={selectedAccountBalance} risk={75} health={0.85} />
|
||||
</div>
|
||||
<div className='grid grid-flow-row grid-cols-2 gap-4 p-4'>
|
||||
<Button
|
||||
@ -158,11 +146,7 @@ export default function AccountList(props: Props) {
|
||||
</>
|
||||
) : (
|
||||
<div className='w-full p-4'>
|
||||
<AccountStats
|
||||
balance={formatValue(positionBalance, formatOptions)}
|
||||
risk={60}
|
||||
health={0.5}
|
||||
/>
|
||||
<AccountStats balance={positionBalance} risk={60} health={0.5} />
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
|
@ -1,10 +1,11 @@
|
||||
'use client'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { Heart, Shield } from 'components/Icons'
|
||||
import { Text } from 'components/Text'
|
||||
import useStore from 'store'
|
||||
|
||||
interface Props {
|
||||
balance: string
|
||||
balance: number
|
||||
risk: number
|
||||
health: number
|
||||
}
|
||||
@ -12,12 +13,14 @@ interface Props {
|
||||
export default function AccountStats(props: Props) {
|
||||
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||
const healthBarWidth = 53 * props.health
|
||||
const baseCurrency = useStore((s) => s.baseCurrency)
|
||||
|
||||
return (
|
||||
<div className='w-full flex-wrap'>
|
||||
<Text className='w-full' size='xl'>
|
||||
{props.balance}
|
||||
</Text>
|
||||
<DisplayCurrency
|
||||
coin={{ amount: props.balance.toString(), denom: baseCurrency.denom }}
|
||||
className='w-full text-xl'
|
||||
/>
|
||||
<div className='mt-1 flex w-full items-center'>
|
||||
<Text size='xs' className='flex items-center'>
|
||||
<Shield className='mr-1.5 h-3' />
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
|
||||
interface Props {
|
||||
asset: Asset
|
||||
@ -15,12 +16,7 @@ export default function AmountAndValue(props: Props) {
|
||||
options={{ decimals: props.asset.decimals, abbreviated: true }}
|
||||
/>
|
||||
}
|
||||
sub={
|
||||
<FormattedNumber
|
||||
amount={props.amount}
|
||||
options={{ prefix: '$', abbreviated: true, decimals: props.asset.decimals }}
|
||||
/>
|
||||
}
|
||||
sub={<DisplayCurrency coin={{ amount: props.amount, denom: props.asset.denom }} />}
|
||||
className='justify-end'
|
||||
/>
|
||||
)
|
||||
|
@ -1,4 +1,3 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import Image from 'next/image'
|
||||
import { useState } from 'react'
|
||||
|
||||
|
51
src/components/DisplayCurrency.tsx
Normal file
51
src/components/DisplayCurrency.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import { Coin } from '@cosmjs/stargate'
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import useStore from 'store'
|
||||
import { getMarketAssets } from 'utils/assets'
|
||||
|
||||
import { FormattedNumber } from './FormattedNumber'
|
||||
|
||||
interface Props {
|
||||
coin: Coin
|
||||
className?: string
|
||||
prefixClassName?: string
|
||||
valueClassName?: string
|
||||
isApproximation?: boolean
|
||||
}
|
||||
|
||||
export default function DisplayCurrency(props: Props) {
|
||||
const displayCurrency = useStore((s) => s.displayCurrency)
|
||||
const prices = useStore((s) => s.prices)
|
||||
|
||||
function convertToDisplayAmount(coin: Coin) {
|
||||
const price = prices.find((price) => price.denom === coin.denom)
|
||||
const asset = getMarketAssets().find((asset) => asset.denom === coin.denom)
|
||||
|
||||
const displayPrice = prices.find((price) => price.denom === displayCurrency.denom)
|
||||
|
||||
if (!price || !asset || !displayPrice) return '0'
|
||||
|
||||
return new BigNumber(coin.amount)
|
||||
.times(price.amount)
|
||||
.div(displayPrice.amount)
|
||||
.integerValue(BigNumber.ROUND_HALF_DOWN)
|
||||
.toNumber()
|
||||
}
|
||||
|
||||
return (
|
||||
<FormattedNumber
|
||||
amount={convertToDisplayAmount(props.coin)}
|
||||
options={{
|
||||
minDecimals: 0,
|
||||
maxDecimals: 2,
|
||||
abbreviated: true,
|
||||
decimals: displayCurrency.decimals,
|
||||
prefix: `${props.isApproximation ? '~' : ''}${
|
||||
displayCurrency.prefix ? displayCurrency.prefix : ''
|
||||
}`,
|
||||
suffix: displayCurrency.symbol ? ` ${displayCurrency.symbol}` : '',
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
@ -8,15 +8,29 @@ import { Overlay } from 'components/Overlay/Overlay'
|
||||
import Switch from 'components/Switch'
|
||||
import { Text } from 'components/Text'
|
||||
import { Tooltip } from 'components/Tooltip'
|
||||
import { ENABLE_ANIMATIONS_KEY } from 'constants/localStore'
|
||||
import { DISPLAY_CURRENCY_KEY, ENABLE_ANIMATIONS_KEY } from 'constants/localStore'
|
||||
import { useAnimations } from 'hooks/useAnimations'
|
||||
import useStore from 'store'
|
||||
import { getDisplayCurrencies } from 'utils/assets'
|
||||
import { ASSETS } from 'constants/assets'
|
||||
|
||||
export default function Settings() {
|
||||
useAnimations()
|
||||
|
||||
const [showMenu, setShowMenu] = useState(false)
|
||||
const enableAnimations = useStore((s) => s.enableAnimations)
|
||||
const displayCurrency = useStore((s) => s.displayCurrency)
|
||||
const displayCurrencies = getDisplayCurrencies()
|
||||
|
||||
const storageDisplayCurrency = localStorage.getItem(DISPLAY_CURRENCY_KEY)
|
||||
if (storageDisplayCurrency) {
|
||||
const storedDisplayCurrency = ASSETS.find(
|
||||
(asset) => asset.symbol === JSON.parse(storageDisplayCurrency).symbol,
|
||||
)
|
||||
if (storedDisplayCurrency && storedDisplayCurrency !== displayCurrency) {
|
||||
setDisplayCurrency(storedDisplayCurrency)
|
||||
}
|
||||
}
|
||||
|
||||
function handleReduceMotion(val: boolean) {
|
||||
useStore.setState({ enableAnimations: !val })
|
||||
@ -24,6 +38,18 @@ export default function Settings() {
|
||||
window.localStorage.setItem(ENABLE_ANIMATIONS_KEY, val ? 'false' : 'true')
|
||||
}
|
||||
|
||||
function handleCurrencyChange(e: React.ChangeEvent<HTMLSelectElement>) {
|
||||
const displayCurrency = displayCurrencies.find((c) => c.symbol === e.target.value)
|
||||
if (!displayCurrency) return
|
||||
|
||||
setDisplayCurrency(displayCurrency)
|
||||
}
|
||||
|
||||
function setDisplayCurrency(displayCurrency: Asset) {
|
||||
useStore.setState({ displayCurrency: displayCurrency })
|
||||
localStorage.setItem(DISPLAY_CURRENCY_KEY, JSON.stringify(displayCurrency))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='relative'>
|
||||
<Button
|
||||
@ -54,6 +80,31 @@ export default function Settings() {
|
||||
</div>
|
||||
<Switch name='reduceMotion' checked={!enableAnimations} onChange={handleReduceMotion} />
|
||||
</div>
|
||||
<div className='mt-4 flex w-full flex-col'>
|
||||
<div className='flex'>
|
||||
<Text size='sm' className='mr-2'>
|
||||
Display Currency
|
||||
</Text>
|
||||
<Tooltip
|
||||
content={
|
||||
<Text size='sm'>
|
||||
Sets the denomination of values to a different currency. While OSMO is the
|
||||
currency the TWAP oracles return. All other values are fetched from liquidity
|
||||
pools.
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<select
|
||||
value={displayCurrency.symbol}
|
||||
onChange={handleCurrencyChange}
|
||||
className='mt-2 w-full rounded-sm border border-white/20 bg-transparent p-1 text-sm'
|
||||
>
|
||||
{displayCurrencies.map((currency) => (
|
||||
<option key={currency.denom}>{currency.symbol}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</Overlay>
|
||||
</div>
|
||||
|
@ -11,6 +11,7 @@ export const ASSETS: Asset[] = [
|
||||
logo: '/tokens/osmo.svg',
|
||||
isEnabled: true,
|
||||
isMarket: true,
|
||||
isDisplayCurrency: true,
|
||||
},
|
||||
{
|
||||
symbol: 'ATOM',
|
||||
@ -22,6 +23,7 @@ export const ASSETS: Asset[] = [
|
||||
hasOraclePrice: true,
|
||||
isEnabled: IS_TESTNET ? true : false,
|
||||
isMarket: true,
|
||||
isDisplayCurrency: true,
|
||||
},
|
||||
{
|
||||
symbol: 'CRO',
|
||||
@ -58,5 +60,6 @@ export const ASSETS: Asset[] = [
|
||||
hasOraclePrice: true,
|
||||
isMarket: IS_TESTNET,
|
||||
isEnabled: true,
|
||||
isDisplayCurrency: true,
|
||||
},
|
||||
]
|
||||
|
@ -37,3 +37,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
|
||||
return res.status(200).json(data)
|
||||
}
|
||||
|
||||
interface TokenPricesResult {
|
||||
prices: {
|
||||
[key: string]: {
|
||||
denom: string
|
||||
price: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,16 @@ import { devtools } from 'zustand/middleware'
|
||||
|
||||
import { BroadcastSlice, createBroadcastSlice } from 'store/slices/broadcast'
|
||||
import { CommonSlice, createCommonSlice } from 'store/slices/common'
|
||||
import { createCurrencySlice, CurrencySlice } from 'store/slices/currency'
|
||||
import { createModalSlice, ModalSlice } from 'store/slices/modal'
|
||||
|
||||
export interface Store extends CommonSlice, BroadcastSlice {}
|
||||
export interface Store extends CommonSlice, BroadcastSlice, CurrencySlice, ModalSlice {}
|
||||
|
||||
const store = (set: SetState<any>, get: GetState<any>) => ({
|
||||
...createCommonSlice(set, get),
|
||||
...createBroadcastSlice(set, get),
|
||||
...createCurrencySlice(set, get),
|
||||
...createModalSlice(set, get),
|
||||
})
|
||||
|
||||
let useStore: UseBoundStore<StoreApi<Store>>
|
||||
|
@ -2,78 +2,23 @@ import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'
|
||||
import { WalletClient, WalletConnectionStatus } from '@marsprotocol/wallet-connector'
|
||||
import { GetState, SetState } from 'zustand'
|
||||
|
||||
import { ENV } from 'constants/env'
|
||||
import { MarsAccountNftClient } from 'types/generated/mars-account-nft/MarsAccountNft.client'
|
||||
import { MarsCreditManagerClient } from 'types/generated/mars-credit-manager/MarsCreditManager.client'
|
||||
import { MarsSwapperBaseClient } from 'types/generated/mars-swapper-base/MarsSwapperBase.client'
|
||||
|
||||
export interface CommonSlice {
|
||||
accounts: Account[] | null
|
||||
address?: string
|
||||
borrowModal: {
|
||||
asset: Asset
|
||||
marketData: BorrowAsset | BorrowAssetActive
|
||||
isRepay?: boolean
|
||||
} | null
|
||||
client?: WalletClient
|
||||
clients: {
|
||||
accountNft?: MarsAccountNftClient
|
||||
creditManager?: MarsCreditManagerClient
|
||||
swapperBase?: MarsSwapperBaseClient
|
||||
}
|
||||
createAccountModal: boolean
|
||||
deleteAccountModal: boolean
|
||||
enableAnimations: boolean
|
||||
fundAccountModal: boolean
|
||||
isOpen: boolean
|
||||
prices: Coin[]
|
||||
selectedAccount: string | null
|
||||
signingClient?: SigningCosmWasmClient
|
||||
client?: WalletClient
|
||||
status: WalletConnectionStatus
|
||||
withdrawModal: boolean
|
||||
initClients: (address: string, signingClient: SigningCosmWasmClient) => void
|
||||
}
|
||||
|
||||
export function createCommonSlice(set: SetState<CommonSlice>, get: GetState<CommonSlice>) {
|
||||
return {
|
||||
accounts: null,
|
||||
borrowModal: null,
|
||||
createAccountModal: false,
|
||||
clients: {},
|
||||
deleteAccountModal: false,
|
||||
creditAccounts: null,
|
||||
enableAnimations: true,
|
||||
fundAccountModal: false,
|
||||
isOpen: true,
|
||||
prices: [],
|
||||
repayModal: false,
|
||||
selectedAccount: null,
|
||||
status: WalletConnectionStatus.Unconnected,
|
||||
withdrawModal: false,
|
||||
initClients: (address: string, signingClient: SigningCosmWasmClient) => {
|
||||
if (!signingClient) return
|
||||
const accountNft = new MarsAccountNftClient(
|
||||
signingClient,
|
||||
address,
|
||||
ENV.ADDRESS_ACCOUNT_NFT || '',
|
||||
)
|
||||
const creditManager = new MarsCreditManagerClient(
|
||||
signingClient,
|
||||
address,
|
||||
ENV.ADDRESS_CREDIT_MANAGER || '',
|
||||
)
|
||||
const swapperBase = new MarsSwapperBaseClient(
|
||||
signingClient,
|
||||
address,
|
||||
ENV.ADDRESS_SWAPPER || '',
|
||||
)
|
||||
|
||||
set(() => ({
|
||||
clients: {
|
||||
accountNft,
|
||||
creditManager,
|
||||
swapperBase,
|
||||
},
|
||||
}))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
18
src/store/slices/currency.ts
Normal file
18
src/store/slices/currency.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Coin } from '@cosmjs/stargate'
|
||||
import { GetState, SetState } from 'zustand'
|
||||
|
||||
import { ASSETS } from 'constants/assets'
|
||||
|
||||
export interface CurrencySlice {
|
||||
baseCurrency: Asset
|
||||
displayCurrency: Asset
|
||||
prices: Coin[]
|
||||
}
|
||||
|
||||
export function createCurrencySlice(set: SetState<CurrencySlice>, get: GetState<CurrencySlice>) {
|
||||
return {
|
||||
baseCurrency: ASSETS[0],
|
||||
displayCurrency: ASSETS.find((asset) => asset.denom === ASSETS[0].denom)!,
|
||||
prices: [],
|
||||
}
|
||||
}
|
23
src/store/slices/modal.ts
Normal file
23
src/store/slices/modal.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { GetState, SetState } from 'zustand'
|
||||
|
||||
export interface ModalSlice {
|
||||
borrowModal: {
|
||||
asset: Asset
|
||||
marketData: BorrowAsset | BorrowAssetActive
|
||||
isRepay?: boolean
|
||||
} | null
|
||||
createAccountModal: boolean
|
||||
deleteAccountModal: boolean
|
||||
fundAccountModal: boolean
|
||||
withdrawModal: boolean
|
||||
}
|
||||
|
||||
export function createModalSlice(set: SetState<ModalSlice>, get: GetState<ModalSlice>) {
|
||||
return {
|
||||
borrowModal: null,
|
||||
createAccountModal: false,
|
||||
deleteAccountModal: false,
|
||||
fundAccountModal: false,
|
||||
withdrawModal: false,
|
||||
}
|
||||
}
|
2
src/types/interfaces/asset.d.ts
vendored
2
src/types/interfaces/asset.d.ts
vendored
@ -3,6 +3,7 @@ interface Asset {
|
||||
name: string
|
||||
denom: string
|
||||
symbol: 'OSMO' | 'ATOM' | 'CRO' | 'MARS' | 'JUNO'
|
||||
prefix?: string
|
||||
contract_addr?: string
|
||||
logo: string
|
||||
decimals: number
|
||||
@ -10,6 +11,7 @@ interface Asset {
|
||||
poolId?: number
|
||||
isEnabled: boolean
|
||||
isMarket: boolean
|
||||
isDisplayCurrency?: boolean
|
||||
}
|
||||
|
||||
interface OtherAsset extends Omit<Asset, 'symbol'> {
|
||||
|
@ -1,8 +0,0 @@
|
||||
interface TokenPricesResult {
|
||||
prices: {
|
||||
[key: string]: {
|
||||
denom: string
|
||||
price: string
|
||||
}
|
||||
}
|
||||
}
|
@ -15,3 +15,7 @@ export function getMarketAssets(): Asset[] {
|
||||
export function getBaseAsset() {
|
||||
return ASSETS.find((asset) => asset.denom === 'uosmo')!
|
||||
}
|
||||
|
||||
export function getDisplayCurrencies() {
|
||||
return ASSETS.filter((asset) => asset.isDisplayCurrency)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user