Files
web/src/components/chart/ChartPlaceOrder.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 Order'}}</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>