204 lines
6.2 KiB
Vue
204 lines
6.2 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>
|
|
</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";
|
|
|
|
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() {
|
|
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 = true
|
|
}
|
|
}
|
|
tx.submit() // this assigns the tx to walletStore.transaction
|
|
}
|
|
}
|
|
|
|
</script>
|
|
|
|
<style lang="scss"> // NOT scoped
|
|
body {
|
|
overflow-y: hidden;
|
|
}
|
|
</style>
|