vault balances UI

This commit is contained in:
Tim Olson
2023-10-30 23:44:05 -04:00
parent 6d99975a9e
commit ee61c96d38
9 changed files with 124 additions and 22 deletions

View 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>

View File

@@ -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>

View 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>

View File

@@ -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"/>&nbsp;Setup&nbsp;Vault</v-card-title> <v-card-title><v-icon color="warning" icon="mdi-alert"/>&nbsp;Setup&nbsp;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>

View File

@@ -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"/>

View File

@@ -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)
}) })

View File

@@ -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,

View File

@@ -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>