vault balances UI
This commit is contained in:
44
src/components/CopyButton.vue
Normal file
44
src/components/CopyButton.vue
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<v-btn v-if="permitted" rounded variant="text" size="small" density="compact" @click="copy()"
|
||||||
|
:class="error?'error':copied?'success':''"
|
||||||
|
:icon="error?'mdi-close-box-outline':copied?'mdi-check-circle-outline':'mdi-content-copy'"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
|
const props = defineProps(['text'])
|
||||||
|
const permitted = ref(true)
|
||||||
|
const copied = ref(false)
|
||||||
|
const error = ref(false)
|
||||||
|
|
||||||
|
navigator.permissions.query({name: "clipboard-write"}).then((permission) => {
|
||||||
|
permitted.value = permission.state === "granted" || permission.state === "prompt"
|
||||||
|
})
|
||||||
|
|
||||||
|
function copy() {
|
||||||
|
if (!copied.value) {
|
||||||
|
navigator.clipboard.writeText(props.text)
|
||||||
|
.then(() => {
|
||||||
|
copied.value = true
|
||||||
|
setTimeout(() => copied.value = false, 3000)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
error.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use "src/styles/vars" as *;
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: $red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
color: $green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-combobox :items="s.tokens" :auto-select-first="true"
|
<v-combobox :items="Object.values(s.tokens)" :auto-select-first="true"
|
||||||
item-title="symbol"
|
item-title="symbol"
|
||||||
:filter-keys="['raw.name','raw.symbol','raw.address']"
|
:filter-keys="['raw.name','raw.symbol','raw.address']"
|
||||||
:model-value="modelValue"
|
:model-value="modelValue"
|
||||||
@@ -25,6 +25,7 @@ import {ref} from "vue";
|
|||||||
import {ethers} from "ethers";
|
import {ethers} from "ethers";
|
||||||
// noinspection ES6UnusedImports
|
// noinspection ES6UnusedImports
|
||||||
import {vAutoSelect} from "@/misc.js";
|
import {vAutoSelect} from "@/misc.js";
|
||||||
|
import {addExtraToken} from "@/blockchain/token.js";
|
||||||
|
|
||||||
const s = useStore2()
|
const s = useStore2()
|
||||||
const props = defineProps(['modelValue', 'label'])
|
const props = defineProps(['modelValue', 'label'])
|
||||||
@@ -81,22 +82,8 @@ function updateValue(v) {
|
|||||||
<script>
|
<script>
|
||||||
import {ethers} from "ethers";
|
import {ethers} from "ethers";
|
||||||
import {useStore} from "@/store/store.js";
|
import {useStore} from "@/store/store.js";
|
||||||
import {socket} from "@/socket.js";
|
|
||||||
|
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
|
|
||||||
async function addExtraToken(addr) {
|
|
||||||
const prom = new Promise((resolve)=>{
|
|
||||||
const chainId = s.chainId
|
|
||||||
socket.emit('lookupToken', chainId, addr, (info) => {
|
|
||||||
if( info === null )
|
|
||||||
return resolve(null)
|
|
||||||
s.addToken(chainId, info)
|
|
||||||
resolve(info)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return await prom
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
27
src/components/TokenRow.vue
Normal file
27
src/components/TokenRow.vue
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<tr>
|
||||||
|
<td><v-img v-if="imageSrc" :src="imageSrc"/></td>
|
||||||
|
<td>{{token.symbol}}</td>
|
||||||
|
<td class="d-none d-sm-table-cell">{{token.name||''}}</td>
|
||||||
|
<td>{{fixed}}</td>
|
||||||
|
<td><!-- todo actions --></td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {useStore} from "@/store/store";
|
||||||
|
import {getToken} from "@/blockchain/token.js";
|
||||||
|
import {FixedNumber} from "ethers";
|
||||||
|
import {computed} from "vue";
|
||||||
|
const s = useStore()
|
||||||
|
const props = defineProps(['addr','amount'])
|
||||||
|
const token = await getToken(props.addr)
|
||||||
|
console.log('token', props.addr, token)
|
||||||
|
const fixed = computed(()=>FixedNumber.fromValue(props.amount, token.decimals, {width:256, decimals: token.decimals}))
|
||||||
|
const imageSrc = computed(()=>null )
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@use "src/styles/vars" as *;
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-card v-if="s.vault===null">
|
<!-- todo we can use something like this for ethereum where the vault creation is too expensive to subsidize
|
||||||
|
<PhoneCard v-if="s.vault===null || s.vault.length === 0">
|
||||||
<v-card-title><v-icon color="warning" icon="mdi-alert"/> Setup Vault</v-card-title>
|
<v-card-title><v-icon color="warning" icon="mdi-alert"/> Setup Vault</v-card-title>
|
||||||
<v-card-subtitle>Create Your Own Personal Dexorder Vault</v-card-subtitle>
|
<v-card-subtitle>Create Your Own Personal Dexorder Vault</v-card-subtitle>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@@ -19,17 +20,54 @@
|
|||||||
vault at any time, and you may save your vault address in your wallet for
|
vault at any time, and you may save your vault address in your wallet for
|
||||||
easy access.
|
easy access.
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
</PhoneCard>
|
||||||
|
-->
|
||||||
|
<v-card v-if="s.vaults.length<num">
|
||||||
|
<v-card-title>No Vault Yet</v-card-title>
|
||||||
|
<v-card-text v-if="num!==0"><!--todo-->Multiple vaults are not yet supported</v-card-text>
|
||||||
|
<v-card-text v-if="num===0">Create an order first, then your vault account will appear here to accept a deposit of trading funds.</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
<v-card v-if="s.vaults.length>num">
|
||||||
|
<v-card-title>Vault {{s.vaults.length>1?'#'+(num+1):''}}</v-card-title> <!-- todo vault nicknames -->
|
||||||
|
<v-card-subtitle v-if="exists">{{addr}} <copy-button :text="addr"/></v-card-subtitle>
|
||||||
|
<v-card-text v-if="empty">
|
||||||
|
<p>There are no funds currently in your vault.</p>
|
||||||
|
<p>Send tokens to the address above to fund your vault.</p>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-item>
|
||||||
|
<v-table v-if="!empty">
|
||||||
|
<tbody>
|
||||||
|
<suspense v-for="(amount,addr) of balances">
|
||||||
|
<token-row :addr="addr" :amount="amount"/>
|
||||||
|
</suspense>
|
||||||
|
</tbody>
|
||||||
|
</v-table>
|
||||||
|
</v-card-item>
|
||||||
</v-card>
|
</v-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {useStore} from "@/store/store.js";
|
import {useStore} from "@/store/store.js";
|
||||||
|
import PhoneCard from "@/components/PhoneCard.vue";
|
||||||
|
import {computed, defineAsyncComponent} from "vue";
|
||||||
|
import {vaultAddress} from "@/blockchain/contract.js";
|
||||||
|
import CopyButton from "@/components/CopyButton.vue";
|
||||||
|
|
||||||
|
const TokenRow = defineAsyncComponent(()=>import('./TokenRow.vue'))
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
|
|
||||||
|
const props = defineProps(['owner', 'num'])
|
||||||
|
const addr = computed(()=>vaultAddress(props.owner, props.num))
|
||||||
|
const balances = computed(()=>{
|
||||||
|
const bs = s.vaultBalances[addr.value]
|
||||||
|
console.log('balances', addr.value, s.vaultBalances, bs)
|
||||||
|
return bs || {}
|
||||||
|
})
|
||||||
|
const tokenAddrs = computed(()=>Object.keys(balances))
|
||||||
|
const empty = computed(()=>Object.keys(balances.value).length===0)
|
||||||
|
const exists = computed(()=>s.vaults.length>0)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@use "../styles/vars" as *;
|
@use "../styles/vars" as *;
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-main>
|
<v-main>
|
||||||
<v-container>
|
<v-container>
|
||||||
<div class="maxw">
|
<div>
|
||||||
<Alerts/>
|
<Alerts/>
|
||||||
<router-view/>
|
<router-view/>
|
||||||
<v-skeleton-loader v-if="!store.chainInfo" type="card" class="order-card"/>
|
<v-skeleton-loader v-if="!store.chainInfo" type="card" class="order-card"/>
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ socket.on('p', async (pool, price) => {
|
|||||||
socket.on('vb', async (vault, balances) => {
|
socket.on('vb', async (vault, balances) => {
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
console.log('vb', vault, balances)
|
console.log('vb', vault, balances)
|
||||||
const vb = JSON.parse(balances)
|
const vb = {}
|
||||||
|
vb[vault] = JSON.parse(balances)
|
||||||
s.$patch({vaultBalances:vb})
|
s.$patch({vaultBalances:vb})
|
||||||
console.log('vault balances', vault, vb)
|
console.log('vault balances', vault, vb)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Utilities
|
// Utilities
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import {knownTokens} from "@/tokens.js";
|
import {knownTokens} from "@/knownTokens.js";
|
||||||
|
|
||||||
export const useStore = defineStore('app', {
|
export const useStore = defineStore('app', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@@ -27,7 +27,11 @@ export const useStore = defineStore('app', {
|
|||||||
known = known ? Object.values(known) : []
|
known = known ? Object.values(known) : []
|
||||||
let extras = s.extraTokens[s.chainId]
|
let extras = s.extraTokens[s.chainId]
|
||||||
extras = extras ? Object.values(extras) : []
|
extras = extras ? Object.values(extras) : []
|
||||||
return [...chains, ...known, ...extras] // put chains first so the Mockcoin pool is automatically selected
|
const result = {}
|
||||||
|
const all = [...chains, ...known, ...extras]; // put chains first so the Mockcoin pool is automatically selected
|
||||||
|
for( const token of all)
|
||||||
|
result[token.address] = token
|
||||||
|
return result
|
||||||
},
|
},
|
||||||
factory: (s)=>!s.chain?null:s.chain.factory,
|
factory: (s)=>!s.chain?null:s.chain.factory,
|
||||||
helper: (s)=>!s.chain?null:s.chain.helper,
|
helper: (s)=>!s.chain?null:s.chain.helper,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<Vault/>
|
<!-- todo needs account -->
|
||||||
|
<Vault v-if="s.account" :owner="s.account" :num="0"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|||||||
Reference in New Issue
Block a user