initial checkin with timed order ui

This commit is contained in:
Tim Olson
2023-08-27 21:01:17 -04:00
commit 986a876f86
39 changed files with 2592 additions and 0 deletions

View File

@@ -0,0 +1,177 @@
<template>
<v-card title="DCA / TWAP" subtitle="Split order across time" class="order-card" elevation="4">
<v-card-text>
<pair-entry v-model="pair"/>
<v-text-field label='Amount' type="number" step="1" variant="outlined" aria-valuemin="0" min="0"
:model-value="amount" :rules="[validateRequired,validateAmount]" class="amount">
<template v-slot:append-inner>
<v-btn @click="amountIsBase=!amountIsBase" variant="outlined">
{{ amountIsBase ? pair.tokenA.symbol : pair.tokenB.symbol }}
</v-btn>
</template>
<template v-slot:append>
<v-btn :text="amountIsTotal ? 'Total' : 'Per Tranche'" variant="outlined"
@click="amountIsTotal=!amountIsTotal" class="total"/>
</template>
</v-text-field>
<v-text-field label="Tranches" type="number" variant="outlined" aria-valuemin="1" min="1"
:model-value="tranches" :rules="[validateRequired]">
<template v-slot:prepend>
<v-btn class="split-into" variant="outlined" @click="amountIsTotal=!amountIsTotal">
{{ amountIsTotal ? 'Split into' : 'Times' }}
</v-btn>
</template>
</v-text-field>
<v-text-field type="number" variant="outlined" :min="1" v-model="interval" class="interval"
:label="intervalIsTotal ? 'Complete within' : 'Time between tranches'">
<!-- <template v-slot:append>APART</template>-->
<template v-slot:prepend>
<v-btn variant="outlined" :text="intervalIsTotal ? 'Within' : 'Spaced apart'" class="within"
@click="intervalIsTotal=!intervalIsTotal"/>
</template>
<template v-slot:append-inner>
<v-btn variant="outlined" :text="timeUnits[timeUnitIndex]" @click="toggleTimeUnits" class="time-units"/>
</template>
</v-text-field>
<v-text-field v-model="limitPrice" :label="(limitIsMinimum?'Minimum':'Maximum')+' Price'" type="number" variant="outlined" aria-valuemin="0" min="0"
clearable :rules="[validateAmount, validateMin]">
<template v-slot:append-inner>
<v-btn variant="outlined" @click="inverted=!inverted">
{{ inverted ? pair.tokenB.symbol + '/' + pair.tokenA.symbol : pair.tokenA.symbol + '/' + pair.tokenB.symbol }}
</v-btn>
</template>
</v-text-field>
<!--
<v-text-field v-model="minPrice" label="Minimum Price" type="number" variant="outlined" aria-valuemin="0" min="0"
clearable :rules="[validateAmount, validateMin]">
<template v-slot:append-inner>
<v-btn variant="outlined" @click="inverted=!inverted">
{{ inverted ? pair.tokenB.symbol + '/' + pair.tokenA.symbol : pair.tokenA.symbol + '/' + pair.tokenB.symbol }}
</v-btn>
</template>
</v-text-field>
<v-text-field v-model="maxPrice" label="Maximum Price" type="number" variant="outlined" aria-valuemin="0" min="0"
clearable :rules="[validateAmount, validateMax]">
<template v-slot:append-inner>
<v-btn variant="outlined" @click="inverted=!inverted">
{{ inverted ? pair.tokenB.symbol + '/' + pair.tokenA.symbol : pair.tokenA.symbol + '/' + pair.tokenB.symbol }}
</v-btn>
</template>
</v-text-field>
-->
</v-card-text>
<v-card-actions class="d-flex justify-space-evenly mb-4">
<v-btn variant="outlined" color="red">Cancel</v-btn>
<v-btn variant="flat" color="green">Place Order</v-btn>
</v-card-actions>
</v-card>
</template>
<script setup>
import {useStore} from "@/store/store";
import {computed, ref} from "vue";
import PairEntry from "@/components/PairEntry.vue";
const s = useStore()
const pair = ref({tokenA: s.tokens[0], tokenB: s.tokens[1], buy: true})
const amount = ref(1)
const amountIsBase = ref(false)
const amountIsTotal = ref(true)
const tranches = ref(3)
const inverted = ref(false)
const minPrice = ref(null)
const maxPrice = ref(null)
const limitPrice = ref(null)
const interval = ref(10)
const intervalIsTotal = ref(true)
const timeUnits = ['minutes', 'hours', 'days']
const timeUnitIndex = ref(1)
const limitIsMinimum = computed(()=>!(pair.value.buy ^ inverted.value))
function toggleTimeUnits() {
timeUnitIndex.value++
if( timeUnitIndex.value >= timeUnits.length )
timeUnitIndex.value = 0
}
function isEmpty(v) {
return v === null || typeof v === 'string' && v.trim() === ''
}
function validateRequired(v) {
if( isEmpty(v) )
return 'Required'
return true
}
function validateAmount(v) {
if( isEmpty(v) )
return true
const floatRegex = /^-?\d*(?:[.,]\d*?)?$/
if (!floatRegex.test(v))
return 'Amount must be a number'
if (parseFloat(v) <= 0)
return 'Amount must be positive'
return true
}
function validateMax(v) {
console.log('validate max',v,isEmpty(v),minPrice,isEmpty(minPrice))
if( !isEmpty(minPrice.value) && !isEmpty(v) && parseFloat(v) < parseFloat(minPrice.value) )
return 'Must be greater than the minimum price'
return true
}
function validateMin(v) {
console.log('validate min',v,isEmpty(v),maxPrice,isEmpty(maxPrice))
if( !isEmpty(maxPrice.value) && !isEmpty(v) && parseFloat(v) > parseFloat(maxPrice.value) )
return 'Must be less than the maximum price'
return true
}
</script>
<style scoped lang="scss">
@use "@/styles/vars" as *;
.order-card {
width: 25em;
}
.amount {
width: 23em;
}
.total {
width: 9em;
}
.split-into {
width: 8em;
}
.v-input {
margin-top: 1em;
margin-bottom: 1em;
}
.interval {
//width: 18em;
}
.within {
width: 10em;
}
.time-units {
width: 8em;
}
</style>