249 lines
7.7 KiB
Vue
249 lines
7.7 KiB
Vue
<template>
|
|
<toolbar-pane title="Order">
|
|
<template #toolbar>
|
|
<!-- <v-btn variant="flat" prepend-icon="mdi-plus" @click="co.newOrder" v-if="co.orders.length===0">New Order</v-btn>-->
|
|
<v-btn variant="text" prepend-icon="mdi-send" @click="placeOrder"
|
|
:color="orderColor" v-if="co.orders.length>0" :disabled="!valid">
|
|
Place Dexorder
|
|
</v-btn>
|
|
<v-btn variant="text" prepend-icon="mdi-delete" v-if="co.orders.length>0"
|
|
:disabled="!orderChanged" @click="resetOrder">Reset</v-btn>
|
|
<v-btn id="share-btn" variant="text" prepend-icon="mdi-share" v-if="co.orders.length>0"
|
|
:disabled="sharing"
|
|
@click="shareOrder">{{sharing?'Preparing...':'Share'}}</v-btn>
|
|
<v-tooltip activator="#share-btn" :text="shareError?'Error copying share link :(':'Copied share link!'" v-model="showSharedTooltip"
|
|
:open-on-hover="false" :open-on-click="false"
|
|
/>
|
|
</template>
|
|
<div class="overflow-y-auto">
|
|
<needs-chart>
|
|
<template v-for="o in co.orders">
|
|
<chart-order :order="o"/>
|
|
</template>
|
|
<v-dialog v-model="showResetDialog" max-width="300">
|
|
<v-card title="Cancel Order?" text="Do you want to cancel this order and start again?">
|
|
<v-card-actions>
|
|
<v-spacer/>
|
|
<v-btn @click="()=>showResetDialog=false">Keep Existing</v-btn>
|
|
<v-btn @click="doResetOrder" color="red" text="Reset Order"/>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
<v-dialog v-model="showWarnings" max-width="300">
|
|
<v-card prepend-icon="mdi-warning" title="Order Warnings">
|
|
<v-card-item>
|
|
<ul class="ml-5">
|
|
<li v-for="w of orderWarnings">{{w}}</li>
|
|
</ul>
|
|
</v-card-item>
|
|
<v-card-text>Continue placing this order?</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer/>
|
|
<v-btn @click="()=>showWarnings=false">Back</v-btn>
|
|
<v-btn @click="doPlaceOrder">Place Order</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
<v-dialog v-model="placementError" max-width="300">
|
|
<v-card prepend-icon="mdi-alert" title="Order Error" text="There was an error placing your order. Please try again or contact support.">
|
|
<v-card-actions>
|
|
<v-spacer/>
|
|
<v-btn @click="()=>{placementError=false;ws.transaction=null}">OK</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</needs-chart>
|
|
</div>
|
|
</toolbar-pane>
|
|
</template>
|
|
|
|
<script setup>
|
|
import {orderFuncs, useChartOrderStore} from "@/orderbuild.js";
|
|
import {addSymbolChangedCallback, removeSymbolChangedCallback} from "@/charts/chart.js";
|
|
import {computed, onBeforeUnmount, ref, toRaw, watchEffect} from "vue";
|
|
import {useOrderStore, useStore} from "@/store/store.js";
|
|
|
|
import {routeFinder} from "@/blockchain/route.js";
|
|
import ChartOrder from "@/components/chart/ChartOrder.vue";
|
|
import {useTheme} from "vuetify";
|
|
import {useWalletStore} from "@/blockchain/wallet.js";
|
|
import ToolbarPane from "@/components/chart/ToolbarPane.vue";
|
|
import NeedsChart from "@/components/NeedsChart.vue";
|
|
import {PlaceOrderTransaction} from "@/blockchain/transaction.js";
|
|
import {errorSuggestsMissingVault} from "@/misc.js";
|
|
import {track} from "@/track.js";
|
|
import {getShareUrl} from "@/share.js";
|
|
|
|
const s = useStore()
|
|
const co = useChartOrderStore()
|
|
const os = useOrderStore()
|
|
const ws = useWalletStore()
|
|
|
|
function changeSymbol(symbol) {
|
|
// console.log('changeSymbol', symbol)
|
|
os.tokenA = symbol.base
|
|
os.tokenB = symbol.quote
|
|
// routeFinder.invoke()
|
|
}
|
|
|
|
|
|
addSymbolChangedCallback(changeSymbol)
|
|
onBeforeUnmount(() => removeSymbolChangedCallback(changeSymbol) )
|
|
|
|
|
|
const showResetDialog = ref(false)
|
|
|
|
const theme = useTheme().current
|
|
const orderColor = computed(()=>co.orders.length===0?null : co.orders[0].buy ? theme.value.colors.success:theme.value.colors.error)
|
|
|
|
const valid = computed(()=>{
|
|
if (!s.approved)
|
|
return false
|
|
if (co.drawing)
|
|
return false
|
|
for ( const order of co.orders )
|
|
if (!order.valid)
|
|
return false
|
|
return true
|
|
})
|
|
|
|
|
|
const orderChanged = computed(()=>!(co.orders.length===1 && co.orders[0].builders.length===0 && !co.orders[0].amount))
|
|
|
|
const showWarnings = ref(false)
|
|
const orderWarnings = ref([])
|
|
|
|
const placementError = ref(false)
|
|
|
|
function resetOrder() {
|
|
showResetDialog.value = true
|
|
}
|
|
|
|
function doResetOrder() {
|
|
co.resetOrders();
|
|
orderWarnings.value = []
|
|
showWarnings.value = false
|
|
showResetDialog.value = false
|
|
placementError.value = false
|
|
}
|
|
|
|
watchEffect(()=>{
|
|
const removable = []
|
|
for (const order of ws.pendingOrders) {
|
|
console.log('pend state', order.state)
|
|
switch (order.state) {
|
|
case PendingOrderState.Sent:
|
|
break
|
|
case PendingOrderState.Rejected:
|
|
removable.push(order)
|
|
break
|
|
case PendingOrderState.Signing:
|
|
break
|
|
case PendingOrderState.Submitted:
|
|
removable.push(order)
|
|
break
|
|
default:
|
|
console.error('unknown pend state', order.state)
|
|
}
|
|
}
|
|
if (removable.length>0) {
|
|
if (ws.pendingOrders.length!==removable.length)
|
|
console.error('Not all orders were rejected') // todo multiple orders / order group
|
|
ws.pendingOrders = []
|
|
}
|
|
})
|
|
|
|
let built = []
|
|
|
|
async function placeOrder() {
|
|
track('place-order')
|
|
const chartOrders = co.orders;
|
|
const allWarns = []
|
|
built = []
|
|
for (const chartOrder of chartOrders) {
|
|
console.log('chartOrder', chartOrder)
|
|
const buildOrder = orderFuncs[chartOrder.id]
|
|
const {order, warnings} = buildOrder()
|
|
built.push(order)
|
|
allWarns.push(...warnings)
|
|
}
|
|
|
|
if (allWarns.length > 0) {
|
|
orderWarnings.value = allWarns
|
|
showWarnings.value = true
|
|
return
|
|
}
|
|
|
|
await doPlaceOrder()
|
|
}
|
|
|
|
async function doPlaceOrder() {
|
|
console.log('place orders')
|
|
placementError.value = false
|
|
showWarnings.value = false
|
|
if (ws.transaction!==null) {
|
|
console.error('Transaction already in progress')
|
|
}
|
|
else {
|
|
const tx = new PlaceOrderTransaction(s.chainId, toRaw(built[0]));
|
|
tx.retries = 60
|
|
const oldFailed = tx.failed
|
|
tx.failed = function(e) {
|
|
console.error('place order failed', errorSuggestsMissingVault(e), e.code, e)
|
|
if (errorSuggestsMissingVault(e) && e.action === 'feeManager' && this.retries-- >= 0) {
|
|
s.creatingVault = true
|
|
}
|
|
else {
|
|
s.creatingVault = false
|
|
oldFailed.bind(this)(e)
|
|
placementError.value = e.info?.error?.code !== 4001
|
|
}
|
|
}
|
|
tx.submit() // this assigns the tx to walletStore.transaction
|
|
}
|
|
}
|
|
|
|
const sharing = ref(false)
|
|
const showSharedTooltip = ref(false)
|
|
const shareError = ref(false)
|
|
const showShareDialog = ref(false)
|
|
const shareUrl = ref(null)
|
|
|
|
function shareOrder() {
|
|
sharing.value = true
|
|
track('share')
|
|
getShareUrl().then(url => {
|
|
shareError.value = url === null
|
|
if (url === null) {
|
|
sharing.value = false
|
|
return
|
|
}
|
|
console.log('share url', url)
|
|
shareUrl.value = url
|
|
sharing.value = false
|
|
navigator.permissions.query({name: "clipboard-write"}).then((permission) => {
|
|
const permitted = permission.state === "granted" || permission.state === "prompt"
|
|
if (!permitted) {
|
|
showShareDialog.value = true
|
|
} else {
|
|
navigator.clipboard.writeText(url)
|
|
.then(() => {
|
|
showSharedTooltip.value = true
|
|
setTimeout(() => showSharedTooltip.value = false, 3000)
|
|
})
|
|
.catch(() => {
|
|
showShareDialog.value = true
|
|
})
|
|
}
|
|
}).catch(() => null)
|
|
})
|
|
}
|
|
|
|
</script>
|
|
|
|
<style lang="scss"> // NOT scoped
|
|
body {
|
|
overflow-y: hidden;
|
|
}
|
|
</style>
|