Optimize quotes loading

This commit is contained in:
liangping 2021-10-07 21:25:33 +08:00
parent ffa366ee25
commit e34a82402f
14 changed files with 533 additions and 87 deletions

View File

@ -94,6 +94,8 @@ export default {
store.commit('app/UPDATE_WINDOW_WIDTH', val) store.commit('app/UPDATE_WINDOW_WIDTH', val)
}) })
store.dispatch('chains/getQuotes')
return { return {
skinClasses, skinClasses,
} }

View File

@ -15,7 +15,7 @@
"regen": "Regen Network", "regen": "Regen Network",
"secret": "Secret Network", "secret": "Secret Network",
"desmos": "Desmos", "desmos": "Desmos",
"juno": "Juno Hera", "juno": "Juno",
"certik": "Certik", "certik": "Certik",
"sentinel": "Sentinel", "sentinel": "Sentinel",
@ -26,7 +26,8 @@
"blockchains": "Blockchains", "blockchains": "Blockchains",
"uptime": "Uptime", "uptime": "Uptime",
"gravity": "Gravity", "gravity": "Gravity(WIP)",
"pools": "Pools(WIP)",
"proposal_id": "Proposal ID", "proposal_id": "Proposal ID",
"proposal_type": "Proposal Type", "proposal_type": "Proposal Type",

View File

@ -13,6 +13,7 @@ import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration' import duration from 'dayjs/plugin/duration'
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import localeData from 'dayjs/plugin/localeData' import localeData from 'dayjs/plugin/localeData'
import { $themeColors } from '@themeConfig'
dayjs.extend(localeData) dayjs.extend(localeData)
dayjs.extend(duration) dayjs.extend(duration)
@ -76,6 +77,41 @@ export function addressEnCode(prefix, pubkey) {
return Bech32.encode(prefix, pubkey) return Bech32.encode(prefix, pubkey)
} }
export function getUserCurrency() {
const currency = localStorage.getItem('currency')
return currency || 'usd'
}
export function setUserCurrency(currency) {
localStorage.setItem('currency', currency)
}
export function chartColors() {
const colors = ['#6610f2', '#20c997', '#000000', '#FF0000',
'#800000', '#FFFF00', '#808000', '#00FF00', '#008000', '#00FFFF',
'#008080', '#0000FF', '#000080', '#FF00FF', '#800080']
return Object.values($themeColors).concat(colors)
}
export function getUserCurrencySign() {
let s = ''
switch (getUserCurrency()) {
case 'cny':
case 'jpy':
s = '¥'
break
case 'krw':
s = '₩'
break
case 'eur':
s = '€'
break
default:
s = '$'
}
return s
}
export function consensusPubkeyToHexAddress(consensusPubkey) { export function consensusPubkeyToHexAddress(consensusPubkey) {
let raw = null let raw = null
if (typeof consensusPubkey === 'object') { if (typeof consensusPubkey === 'object') {
@ -218,7 +254,7 @@ export function isToken(value) {
export function formatTokenDenom(tokenDenom) { export function formatTokenDenom(tokenDenom) {
if (tokenDenom) { if (tokenDenom) {
let denom = tokenDenom.toUpperCase() let denom = tokenDenom.denom_trace ? tokenDenom.denom_trace.base_denom.toUpperCase() : tokenDenom.toUpperCase()
if (denom.charAt(0) === 'U') { if (denom.charAt(0) === 'U') {
denom = denom.substring(1) denom = denom.substring(1)
} else if (denom === 'BASECRO') { } else if (denom === 'BASECRO') {

View File

@ -328,6 +328,7 @@ const chainAPI = class ChainFetch {
return ChainFetch.fetchCoinMarketCap(`/quote/${symbol}`) return ChainFetch.fetchCoinMarketCap(`/quote/${symbol}`)
} }
// Tx Submit
async broadcastTx(bodyBytes, config = null) { async broadcastTx(bodyBytes, config = null) {
const txString = toBase64(TxRaw.encode(bodyBytes).finish()) const txString = toBase64(TxRaw.encode(bodyBytes).finish())
const txRaw = { const txRaw = {
@ -365,6 +366,15 @@ const chainAPI = class ChainFetch {
// const response = axios.post((config ? config.api : this.config.api) + url, data) // const response = axios.post((config ? config.api : this.config.api) + url, data)
return response.json() // parses JSON response into native JavaScript objects return response.json() // parses JSON response into native JavaScript objects
} }
// Custom Module
async getOsmosisPools() {
return this.get('/osmosis/gamm/v1beta1/pools')
}
async getOsmosisIncentivesPools() {
return this.get('/osmosis/pool-incentives/v1beta1/incentivized_pools')
}
} }
export default chainAPI export default chainAPI

11
src/libs/osmos.js Normal file
View File

@ -0,0 +1,11 @@
import fetch from 'node-fetch'
export default class OsmosAPI {
static async get(url) {
return fetch(url)
}
static async getPools() {
return OsmosAPI.get('/osmosis/gamm/v1beta1/pools')
}
}

View File

@ -26,11 +26,16 @@ const modules = [
title: 'uptime', title: 'uptime',
route: 'uptime', route: 'uptime',
}, },
// { {
// scope: 'cosmos', scope: 'cosmos',
// title: 'gravity', title: 'gravity',
// route: 'gravity', route: 'gravity',
// }, },
{
scope: 'osmosis',
title: 'pools',
route: 'osmosis-pool',
},
] ]
function processMenu() { function processMenu() {

View File

@ -258,8 +258,10 @@ const router = new VueRouter({
], ],
}, },
}, },
// custom modules for specified chains
// 1. cosmos
{ {
path: '/cosmos/gravity', path: '/:chain/cosmos/pools',
name: 'gravity', name: 'gravity',
component: () => import('@/views/GravityPool.vue'), component: () => import('@/views/GravityPool.vue'),
meta: { meta: {
@ -272,6 +274,22 @@ const router = new VueRouter({
], ],
}, },
}, },
// 2. OSMOSIS
{
path: '/:chain/osmosis/pools',
name: 'osmosis-pool',
component: () => import('@/views/OsmosisPools.vue'),
meta: {
pageTitle: 'Pools',
breadcrumb: [
{
text: 'Pools',
active: true,
},
],
},
},
// common modules
{ {
path: '/user/login', path: '/user/login',
name: 'login', name: 'login',

View File

@ -48,6 +48,7 @@ export default {
avatars: {}, avatars: {},
height: 0, height: 0,
ibcChannels: {}, ibcChannels: {},
quotes: {},
}, },
getters: { getters: {
getchains: state => state.chains, getchains: state => state.chains,
@ -69,6 +70,15 @@ export default {
setChannels(state, { chain, channels }) { setChannels(state, { chain, channels }) {
state.chains.ibcChannels[chain] = channels state.chains.ibcChannels[chain] = channels
}, },
setQuotes(state, quotes) {
state.quotes = quotes
},
},
actions: {
async getQuotes(context) {
fetch('https://price.ping.pub/quotes').then(data => data.json()).then(data => {
context.commit('setQuotes', data)
})
},
}, },
actions: {},
} }

View File

@ -0,0 +1,73 @@
<template>
<chartjs-component-doughnut-chart
:height="height"
:width="width"
:data="data"
:chart-data="data"
:options="options"
class="mb-3"
/>
</template>
<script>
import { percent } from '@/libs/data'
import { $themeColors } from '@themeConfig'
import ChartjsComponentDoughnutChart from './ChartjsComponentDoughnutChart.vue'
export default {
name: 'ChartDoughnut',
components: {
ChartjsComponentDoughnutChart,
},
props: {
height: {
type: Number,
default: 235,
},
width: {
type: Number,
default: 235,
},
data: {
type: Object,
required: true,
},
},
data() {
return {
options: {
responsive: true,
maintainAspectRatio: false,
responsiveAnimationDuration: 500,
cutoutPercentage: 60,
legend: {
display: true,
title: {
display: true,
},
},
tooltips: {
callbacks: {
label(tooltipItem, data) {
const label = data.datasets[0].labels[tooltipItem.index] || ''
const value = data.datasets[0].data[tooltipItem.index]
const total = data.datasets[0].data.reduce((t, c) => t + c)
const output = ` ${label} : ${percent(value / total)} %`
return output
},
},
// Updated default tooltip UI
shadowOffsetX: 1,
shadowOffsetY: 1,
shadowBlur: 8,
// shadowColor: chartColors.tooltipShadow,
backgroundColor: $themeColors.light,
titleFontColor: $themeColors.dark,
bodyFontColor: $themeColors.dark,
},
},
}
},
}
</script>

View File

@ -0,0 +1,31 @@
<script>
import { Bar, mixins } from 'vue-chartjs'
export default {
extends: Bar,
mixins: [mixins.reactiveProp],
props: {
// options: {
// type: Object,
// default: null,
// },
},
data() {
return {
options: {
plugins: {
legend: {
display: false,
labels: {
color: 'rgb(255, 99, 132)',
},
},
},
},
}
},
mounted() {
this.renderChart(this.chartData, this.options)
},
}
</script>

110
src/views/OsmosisPools.vue Normal file
View File

@ -0,0 +1,110 @@
<template>
<div class="container-md">
-------
<b-row class="match-height">
<b-col
v-for="(data,index) in pools.pools"
:key="index"
md="4"
sm="6"
>
<router-link :to="data.id">
<b-card
v-if="data"
class="earnings-card text-left"
>
<b-row>
<b-col cols="8">
<b-card-title class="mb-1 text-uppercase">
#{{ data.id }} {{ formatDenom(data.reserve_coin_denoms[0]) }} - {{ formatDenom(data.reserve_coin_denoms[1]) }}<small class="font-small-2"> xx</small>
</b-card-title>
<div class="font-small-2">
Height
</div>
<h5 class="mb-1">
{{ data.height || '0' }}
</h5>
<b-card-text class="text-muted font-small-2">
<span class="font-weight-bolder">{{ data.pool_coin_denom || '...' }}</span>
</b-card-text>
</b-col>
<b-col
cols="4"
>
<b-avatar
:src="data.logo"
class="mt-1 badge-minimal"
variant="light-primary"
rounded
size="82"
badge
:badge-variant="data.variant"
/></b-col>
</b-row>
</b-card>
</router-link>
</b-col>
</b-row>
</div>
</template>
<script>
import {
BCard, BCardTitle, VBTooltip, BRow, BCol,
} from 'bootstrap-vue'
import { formatTokenDenom } from '@/libs/data'
// import fetch from 'node-fetch'
export default {
components: {
BRow,
BCol,
BCard,
BCardTitle,
},
directives: {
'b-tooltip': VBTooltip,
},
data() {
return {
pools: [],
ibcDenom: {},
}
},
created() {
// const api = new OsmosAPI()
this.$http.getOsmosisIncentivesPools().then(res => {
console.log(res)
})
// this.$http.getGravityPools().then(res => {
// this.pools = res
// res.pools.forEach(x => {
// const denom1 = x.reserve_coin_denoms[0]
// const denom2 = x.reserve_coin_denoms[1]
// if (denom1.startsWith('ibc')) {
// this.$http.getIBCDenomTrace(denom1).then(denom => {
// this.$set(this.ibcDenom, denom1, denom)
// })
// }
// if (denom2.startsWith('ibc')) {
// this.$http.getIBCDenomTrace(denom2).then(denom => {
// this.$set(this.ibcDenom, denom2, denom)
// })
// }
// })
// })
},
beforeDestroy() {
this.islive = false
clearInterval(this.timer)
},
methods: {
formatDenom(v) {
// console.log(v, this.ibcDenom[v])
const denom = (v.startsWith('ibc') ? this.ibcDenom[v].denom_trace.base_denom : v)
return formatTokenDenom(denom)
},
length: v => (Array.isArray(v) ? v.length : 0),
},
}
</script>

View File

@ -72,7 +72,7 @@
<h6 class="mb-0"> <h6 class="mb-0">
Consensus Public Address Consensus Public Address
</h6> </h6>
<small @click="copy(consensusPubkey)">{{ consensusPubkey }}</small> <small @click="copy(JSON.stringify(consensusPubkey))">{{ consensusPubkey }}</small>
</b-media-body> </b-media-body>
</b-media> </b-media>
<b-media <b-media

View File

@ -64,23 +64,24 @@
<b-card-body class="pl-0 pr-0"> <b-card-body class="pl-0 pr-0">
<b-row> <b-row>
<b-col <b-col
class="border-right"
xm="12" xm="12"
md="4" md="4"
> >
<chartjs-component-doughnut-chart <chart-component-doughnut
v-if="chartData" v-if="chartData"
:height="235" :height="235"
:width="235" :width="235"
:data="chartData" :data="chartData"
:chart-data="chartData"
:options="doughnutChart.options"
class="mb-3" class="mb-3"
/> />
</b-col> </b-col>
<b-col
class="border-left d-none d-md-block"
md="1"
/>
<b-col <b-col
xm="12" xm="12"
md="8" md="7"
> >
<!-- tokens --> <!-- tokens -->
<div <div
@ -104,12 +105,12 @@
</div> </div>
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<span class="text-right">{{ formatAmount(token.amount) }} {{ formatDenom(token.denom) }}</span> <span class="text-right">{{ formatAmount(token.amount) }} {{ formatDenom(token.denom) }}</span>
<small class="text-right">${{ token.currency }}</small> <small class="text-right">{{ currency }}{{ token.currency }}</small>
</div> </div>
</div> </div>
<!--/ tokens --> <!--/ tokens -->
<div class="text-right border-top pt-1"> <div class="text-right border-top pt-1">
<h2>Total: ${{ assetTable.currency }}</h2> <h2>Total: {{ currency }}{{ assetTable.currency }}</h2>
</div> </div>
</b-col> </b-col>
</b-row> </b-row>
@ -363,17 +364,16 @@ import Ripple from 'vue-ripple-directive'
import VueQr from 'vue-qr' import VueQr from 'vue-qr'
import chainAPI from '@/libs/fetch' import chainAPI from '@/libs/fetch'
import { import {
formatToken, formatTokenAmount, formatTokenDenom, getStakingValidatorOperator, percent, tokenFormatter, toDay, toDuration, abbrMessage, abbrAddress, formatToken, formatTokenAmount, formatTokenDenom, getStakingValidatorOperator, percent, tokenFormatter, toDay, toDuration, abbrMessage, abbrAddress, getUserCurrency, getUserCurrencySign, chartColors,
} from '@/libs/data' } from '@/libs/data'
import { $themeColors } from '@themeConfig'
import ObjectFieldComponent from './ObjectFieldComponent.vue' import ObjectFieldComponent from './ObjectFieldComponent.vue'
import ChartjsComponentDoughnutChart from './ChartjsComponentDoughnutChart.vue'
import OperationTransferComponent from './OperationTransferComponent.vue' import OperationTransferComponent from './OperationTransferComponent.vue'
import OperationWithdrawComponent from './OperationWithdrawComponent.vue' import OperationWithdrawComponent from './OperationWithdrawComponent.vue'
import OperationUnbondComponent from './OperationUnbondComponent.vue' import OperationUnbondComponent from './OperationUnbondComponent.vue'
import OperationDelegateComponent from './OperationDelegateComponent.vue' import OperationDelegateComponent from './OperationDelegateComponent.vue'
import OperationRedelegateComponent from './OperationRedelegateComponent.vue' import OperationRedelegateComponent from './OperationRedelegateComponent.vue'
import OperationTransfer2Component from './OperationTransfer2Component.vue' import OperationTransfer2Component from './OperationTransfer2Component.vue'
import ChartComponentDoughnut from './ChartComponentDoughnut.vue'
export default { export default {
components: { components: {
@ -398,13 +398,13 @@ export default {
// eslint-disable-next-line vue/no-unused-components // eslint-disable-next-line vue/no-unused-components
ToastificationContent, ToastificationContent,
ObjectFieldComponent, ObjectFieldComponent,
ChartjsComponentDoughnutChart,
OperationTransferComponent, OperationTransferComponent,
OperationWithdrawComponent, OperationWithdrawComponent,
OperationDelegateComponent, OperationDelegateComponent,
OperationRedelegateComponent, OperationRedelegateComponent,
OperationUnbondComponent, OperationUnbondComponent,
OperationTransfer2Component, OperationTransfer2Component,
ChartComponentDoughnut,
}, },
directives: { directives: {
'b-modal': VBModal, 'b-modal': VBModal,
@ -414,6 +414,7 @@ export default {
data() { data() {
const { address } = this.$route.params const { address } = this.$route.params
return { return {
currency: getUserCurrencySign(),
selectedValidator: '', selectedValidator: '',
totalCurrency: 0, totalCurrency: 0,
address, address,
@ -426,39 +427,6 @@ export default {
unbonding: [], unbonding: [],
quotes: {}, quotes: {},
transactions: [], transactions: [],
doughnutChart: {
options: {
responsive: true,
maintainAspectRatio: false,
responsiveAnimationDuration: 500,
cutoutPercentage: 60,
legend: {
display: true,
title: {
display: true,
},
},
tooltips: {
callbacks: {
label(tooltipItem, data) {
const label = data.datasets[0].labels[tooltipItem.index] || ''
const value = data.datasets[0].data[tooltipItem.index]
const total = data.datasets[0].data.reduce((t, c) => t + c)
const output = ` ${label} : ${percent(value / total)} %`
return output
},
},
// Updated default tooltip UI
shadowOffsetX: 1,
shadowOffsetY: 1,
shadowBlur: 8,
// shadowColor: chartColors.tooltipShadow,
// backgroundColor: $themeColors.light,
// titleFontColor: $themeColors.dark,
// bodyFontColor: $themeColors.dark,
},
},
},
} }
}, },
computed: { computed: {
@ -581,7 +549,7 @@ export default {
{ {
labels: Object.keys(data), labels: Object.keys(data),
data: Object.values(data), data: Object.values(data),
backgroundColor: [$themeColors.primary, $themeColors.success, $themeColors.warning, $themeColors.danger, $themeColors.info], backgroundColor: chartColors,
borderWidth: 0, borderWidth: 0,
pointStyle: 'rectRounded', pointStyle: 'rectRounded',
}, },
@ -680,10 +648,10 @@ export default {
formatCurrency(amount, denom) { formatCurrency(amount, denom) {
const qty = this.formatAmount(amount) const qty = this.formatAmount(amount)
const d2 = this.formatDenom(denom) const d2 = this.formatDenom(denom)
const userCurrency = 'USD' const userCurrency = getUserCurrency()
const quote = this.quotes[d2] const quote = this.$store.state.chains.quotes[d2]
if (quote && quote.quote) { if (quote) {
const { price } = quote.quote[userCurrency] const price = quote[userCurrency]
return parseFloat((qty * price).toFixed(2)) return parseFloat((qty * price).toFixed(2))
} }
return 0 return 0

View File

@ -1,5 +1,57 @@
<template> <template>
<div class="text-center"> <div class="text-center">
<b-card border-variant="primary">
<b-row class="mx-0">
<b-col
md="4"
>
<b-dropdown
:text="`Currency: ${currency2.toUpperCase()}`"
size="sm"
class="text-uppercase"
variant="primary"
>
<b-dropdown-item @click="setCurrency('usd')">
USD
</b-dropdown-item>
<b-dropdown-item @click="setCurrency('cny')">
CNY (人民币)
</b-dropdown-item>
<b-dropdown-item @click="setCurrency('eur')">
EUR (Euro)
</b-dropdown-item>
<b-dropdown-item @click="setCurrency('jpy')">
JPY (日本円)
</b-dropdown-item>
<b-dropdown-item @click="setCurrency('hkd')">
HKD (港幣)
</b-dropdown-item>
<b-dropdown-item @click="setCurrency('sgd')">
SGD
</b-dropdown-item>
<b-dropdown-item @click="setCurrency('krw')">
KRW (대한민국원)
</b-dropdown-item>
</b-dropdown>
<h2 class="my-1">
{{ currency }}{{ calculateTotal }}
</h2>
<!-- chart -->
<chart-component-doughnut
:height="235"
:width="235"
:data="calculateChartDoughnut"
class="mb-3"
/>
</b-col>
<b-col md="8">
<chartjs-component-bar
:height="135.0"
:chart-data="calculateChartBar"
/>
</b-col>
</b-row>
</b-card>
<b-tabs <b-tabs
v-for="item,index in accounts" v-for="item,index in accounts"
@ -81,7 +133,7 @@
variant="light-primary" variant="light-primary"
rounded rounded
/> />
<h3>${{ formatBalance(balances[acc.addr]) }}</h3> <h3>{{ currency }}{{ formatBalance(acc.addr) }}</h3>
</div> </div>
<small <small
class="pl-1 float-right text-muted text-overflow " class="pl-1 float-right text-muted text-overflow "
@ -91,7 +143,7 @@
</small> </small>
</b-col> </b-col>
</b-row> </b-row>
<b-row v-if="balances[acc.addr]"> <b-row class="d-none">
<b-col> <b-col>
<b-tabs <b-tabs
active-nav-item-class="font-weight-bold text-second" active-nav-item-class="font-weight-bold text-second"
@ -107,7 +159,7 @@
</div> </div>
<div class="d-flex flex-column text-right"> <div class="d-flex flex-column text-right">
<span class="font-weight-bold mb-0">{{ formatAmount(b.amount) }}</span> <span class="font-weight-bold mb-0">{{ formatAmount(b.amount) }}</span>
<span class="font-small-2 text-muted text-nowrap">${{ formatCurrency(b.amount, b.denom) }}</span> <span class="font-small-2 text-muted text-nowrap">{{ currency }}{{ formatCurrency(b.amount, b.denom) }}</span>
</div> </div>
</div> </div>
</b-tab> </b-tab>
@ -118,7 +170,6 @@
</b-card> </b-card>
</b-col> </b-col>
</b-row> </b-row>
</b-tab> </b-tab>
</b-tabs> </b-tabs>
@ -136,18 +187,20 @@
</template> </template>
<script> <script>
import chainAPI from '@/libs/fetch'
import { import {
BCard, BCardHeader, BCardTitle, BCardBody, VBModal, BRow, BCol, BTabs, BTab, BAvatar, BDropdown, BDropdownItem, BCard, BCardHeader, BCardTitle, BCardBody, VBModal, BRow, BCol, BTabs, BTab, BAvatar, BDropdown, BDropdownItem,
} from 'bootstrap-vue' } from 'bootstrap-vue'
import Ripple from 'vue-ripple-directive' import Ripple from 'vue-ripple-directive'
import FeatherIcon from '@/@core/components/feather-icon/FeatherIcon.vue' import FeatherIcon from '@/@core/components/feather-icon/FeatherIcon.vue'
import { import {
formatTokenAmount, formatTokenDenom, getLocalAccounts, getLocalChains, chartColors,
formatTokenAmount, formatTokenDenom, getLocalAccounts, getLocalChains, getUserCurrency, getUserCurrencySign, setUserCurrency,
} from '@/libs/data' } from '@/libs/data'
import ToastificationContent from '@core/components/toastification/ToastificationContent.vue' import ToastificationContent from '@core/components/toastification/ToastificationContent.vue'
import OperationTransferComponent from './OperationTransferComponent.vue' import OperationTransferComponent from './OperationTransferComponent.vue'
import OperationTransfer2Component from './OperationTransfer2Component.vue' import OperationTransfer2Component from './OperationTransfer2Component.vue'
import ChartComponentDoughnut from './ChartComponentDoughnut.vue'
import ChartjsComponentBar from './ChartjsComponentBar.vue'
export default { export default {
components: { components: {
@ -167,6 +220,8 @@ export default {
// eslint-disable-next-line vue/no-unused-components // eslint-disable-next-line vue/no-unused-components
ToastificationContent, ToastificationContent,
OperationTransfer2Component, OperationTransfer2Component,
ChartComponentDoughnut,
ChartjsComponentBar,
}, },
directives: { directives: {
'b-modal': VBModal, 'b-modal': VBModal,
@ -174,18 +229,128 @@ export default {
}, },
data() { data() {
return { return {
currency: getUserCurrencySign(),
currency2: getUserCurrency(),
selectedAddress: '', selectedAddress: '',
selectedName: '', selectedName: '',
transferWindow: false, transferWindow: false,
accounts: [], accounts: [],
balances: {}, balances: {},
delegations: {},
ibcDenom: {}, ibcDenom: {},
quotes: {}, quotes: {},
} }
}, },
computed: {
calculateTotal() {
const v = Object.values(this.balances)
let total = 0
if (v) {
v.forEach(tokens => {
const subtotal = tokens.map(x => this.formatCurrency(x.amount, x.denom)).reduce((t, c) => t + c)
total += subtotal
})
}
const d = Object.values(this.delegations)
if (d) {
d.forEach(tokens => {
const subtotal = tokens.map(x => this.formatCurrency(x.amount, x.denom)).reduce((t, c) => t + c, 0)
total += subtotal
})
}
return parseFloat(total.toFixed(2))
},
calculateChartDoughnut() {
const v = Object.values(this.balances)
const total = {}
if (v) {
v.forEach(tokens => {
const subtotal = tokens.map(x => ({ denom: x.denom, sub: this.formatCurrency(x.amount, x.denom) }))
subtotal.forEach(x => {
const denom = this.formatDenom(x.denom)
if (total[denom]) {
total[denom] += x.sub
} else {
total[denom] = x.sub
}
})
})
}
const d = Object.values(this.delegations)
if (d) {
d.forEach(tokens => {
const subtotal = tokens.map(x => ({ denom: x.denom, sub: this.formatCurrency(x.amount, x.denom) }))
subtotal.forEach(x => {
const denom = this.formatDenom(x.denom)
if (total[denom]) {
total[denom] += x.sub
} else {
total[denom] = x.sub
}
})
})
}
return {
datasets: [
{
labels: Object.keys(total),
data: Object.values(total),
backgroundColor: chartColors(),
borderWidth: 0,
pointStyle: 'rectRounded',
},
],
}
},
calculateChartBar() {
const v = Object.values(this.balances)
const total = {}
if (v) {
v.forEach(tokens => {
const subtotal = tokens.map(x => ({ denom: x.denom, sub: this.formatCurrency(x.amount, x.denom) }))
subtotal.forEach(x => {
const denom = this.formatDenom(x.denom)
if (total[denom]) {
total[denom] += x.sub
} else {
total[denom] = x.sub
}
})
})
}
const d = Object.values(this.delegations)
if (d) {
d.forEach(tokens => {
const subtotal = tokens.map(x => ({ denom: x.denom, sub: this.formatCurrency(x.amount, x.denom) }))
subtotal.forEach(x => {
const denom = this.formatDenom(x.denom)
if (total[denom]) {
total[denom] += x.sub
} else {
total[denom] = x.sub
}
})
})
}
return {
labels: Object.keys(total),
datasets: [
{
label: '',
data: Object.values(total),
backgroundColor: chartColors(),
borderWidth: 0,
pointStyle: 'rectRounded',
},
],
}
},
},
created() { created() {
this.init() this.init()
}, },
mounted() {
},
methods: { methods: {
init() { init() {
this.accounts = getLocalAccounts() this.accounts = getLocalAccounts()
@ -193,33 +358,33 @@ export default {
if (this.accounts) { if (this.accounts) {
Object.keys(this.accounts).forEach(acc => { Object.keys(this.accounts).forEach(acc => {
this.accounts[acc].address.forEach(add => { this.accounts[acc].address.forEach(add => {
chainAPI.getBankBalance(chains[add.chain].api, add.addr).then(res => { this.$http.getBankBalances(add.addr, chains[add.chain]).then(res => {
if (res && res.length > 0) { if (res && res.length > 0) {
this.$set(this.balances, add.addr, res) this.$set(this.balances, add.addr, res)
res.forEach(token => { res.forEach(token => {
let symbol
if (token.denom.startsWith('ibc')) { if (token.denom.startsWith('ibc')) {
chainAPI.getIBCDenomTraceText(chains[add.chain].api, token.denom).then(denom => { this.$http.getIBCDenomTrace(token.denom, chains[add.chain]).then(denom => {
this.$set(this.ibcDenom, token.denom, denom) this.$set(this.ibcDenom, token.denom, denom)
symbol = formatTokenDenom(denom)
}) })
} else {
symbol = formatTokenDenom(token.denom)
}
if (symbol) {
if (!this.quotes[symbol]) {
chainAPI.fetchTokenQuote(symbol).then(quote => {
this.$set(this.quotes, symbol, quote)
})
}
} }
}) })
} }
}) })
this.$http.getStakingDelegations(add.addr, chains[add.chain]).then(res => {
if (res.delegation_responses) {
const delegation = res.delegation_responses.map(x => x.balance)
this.$set(this.delegations, add.addr, delegation)
}
}).catch(() => {})
}) })
}) })
} }
}, },
setCurrency(c) {
setUserCurrency(c)
this.currency2 = c
this.currency = getUserCurrencySign()
},
transfer(addr) { transfer(addr) {
this.selectedAddress = addr this.selectedAddress = addr
}, },
@ -240,20 +405,26 @@ export default {
formatCurrency(amount, denom) { formatCurrency(amount, denom) {
const qty = this.formatAmount(amount) const qty = this.formatAmount(amount)
const d2 = this.formatDenom(denom) const d2 = this.formatDenom(denom)
const userCurrency = 'USD' const quote = this.$store.state.chains.quotes[d2]
const quote = this.quotes[d2] if (quote) {
if (quote && quote.quote) { const price = quote[this.currency2]
const { price } = quote.quote[userCurrency]
return parseFloat((qty * price).toFixed(2)) return parseFloat((qty * price).toFixed(2))
} }
return 0 return 0
}, },
formatBalance(v) { formatBalance(v) {
if (v) { let total = 0
const ret = v.map(x => this.formatCurrency(x.amount, x.denom)).reduce((t, c) => t + c) const balance = this.balances[v]
return parseFloat(ret.toFixed(2)) if (balance) {
const ret = balance.map(x => this.formatCurrency(x.amount, x.denom)).reduce((t, c) => t + c)
total += ret
} }
return 0 const delegations = this.delegations[v]
if (delegations) {
const ret = delegations.map(x => this.formatCurrency(x.amount, x.denom)).reduce((t, c) => t + c, 0)
total += ret
}
return parseFloat(total.toFixed(2))
}, },
removeAddress(v) { removeAddress(v) {
Object.keys(this.accounts).forEach(key => { Object.keys(this.accounts).forEach(key => {