Add frontend for market settlement
This commit is contained in:
parent
c9bce83891
commit
51e204b64a
|
@ -28,7 +28,7 @@ func (db *DB) CreateMarket(tx *sql.Tx, ctx context.Context, market *Market) erro
|
|||
}
|
||||
|
||||
func (db *DB) FetchMarket(marketId int, market *Market) error {
|
||||
if err := db.QueryRow("SELECT id, description, end_date FROM markets WHERE id = $1", marketId).Scan(&market.Id, &market.Description, &market.EndDate); err != nil {
|
||||
if err := db.QueryRow("SELECT id, description, end_date, pubkey FROM markets WHERE id = $1", marketId).Scan(&market.Id, &market.Description, &market.EndDate, &market.Pubkey); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -29,7 +29,7 @@ type (
|
|||
Id Serial `json:"id"`
|
||||
Description string `json:"description"`
|
||||
EndDate time.Time `json:"endDate"`
|
||||
Pubkey string
|
||||
Pubkey string `json:"pubkey"`
|
||||
InvoiceId UUID
|
||||
}
|
||||
Share struct {
|
||||
|
|
|
@ -44,6 +44,7 @@ func HandleMarket(sc context.ServerContext) echo.HandlerFunc {
|
|||
}
|
||||
data = map[string]any{
|
||||
"Id": market.Id,
|
||||
"Pubkey": market.Pubkey,
|
||||
"Description": market.Description,
|
||||
"Shares": shares,
|
||||
}
|
||||
|
|
|
@ -15,27 +15,32 @@
|
|||
<StyledLink :to="'/market/' + marketId + '/form'">form</StyledLink>
|
||||
<StyledLink :to="'/market/' + marketId + '/orders'">orders</StyledLink>
|
||||
<StyledLink :to="'/market/' + marketId + '/stats'">stats</StyledLink>
|
||||
<StyledLink v-if="mine" :to="'/market/' + marketId + '/settings'"><i>settings</i></StyledLink>
|
||||
</nav>
|
||||
</header>
|
||||
<Suspense>
|
||||
<router-view />
|
||||
<router-view :market="market" />
|
||||
</Suspense>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useSession } from '@/stores/session'
|
||||
import StyledLink from '@/components/StyledLink'
|
||||
|
||||
const session = useSession()
|
||||
const route = useRoute()
|
||||
const marketId = route.params.id
|
||||
|
||||
const market = ref(null)
|
||||
const mine = ref(false)
|
||||
const url = '/api/market/' + marketId
|
||||
await fetch(url)
|
||||
.then(r => r.json())
|
||||
.then(body => {
|
||||
market.value = body
|
||||
mine.value = market.value.Pubkey === session.pubkey
|
||||
})
|
||||
.catch(console.error)
|
||||
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<div id="container2" class="mt-3 mx-3">
|
||||
<div class="grid grid-cols-2 my-3 items-center">
|
||||
<label>market settlement</label>
|
||||
<div class="grid grid-cols-2 my-3">
|
||||
<button :class="yesClass" class="label success font-mono mx-1" @click.prevent="() => click('YES')">YES</button>
|
||||
<button :class="noClass" class="label error font-mono mx-1" @click.prevent="() => click('NO')">NO</button>
|
||||
</div>
|
||||
<div class="col-span-2 mb-3" v-if="selected">
|
||||
<p><b>Are you sure you want to settle this market?</b></p>
|
||||
<p>
|
||||
This will cancel all pending orders and halt trading indefinitely.
|
||||
Users with winning shares will receive 100 sats per winning share. Users with losing shares receive nothing.
|
||||
</p>
|
||||
<p class="red"><b>You cannot undo this action.</b></p>
|
||||
</div>
|
||||
<button class="col-span-2" v-if="selected" @click.prevent="confirm">confirm</button>
|
||||
</div>
|
||||
<div v-if="err" class="red text-center">{{ err }}</div>
|
||||
<div v-if="success" class="green text-center">{{ success }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import { computed, defineProps, ref } from 'vue'
|
||||
|
||||
const props = defineProps(['market'])
|
||||
const market = ref(props.market)
|
||||
|
||||
const err = ref(null)
|
||||
const success = ref(null)
|
||||
|
||||
const selected = ref(null)
|
||||
const yesClass = computed(() => selected.value === 'YES' ? ['active'] : [])
|
||||
const noClass = computed(() => selected.value === 'NO' ? ['active'] : [])
|
||||
const click = (sel) => {
|
||||
selected.value = selected.value === sel ? null : sel
|
||||
}
|
||||
|
||||
const confirm = async () => {
|
||||
const sid = market.value.Shares.find(s => s.Description === selected.value).Id
|
||||
const url = '/api/market/' + market.value.Id + '/settle'
|
||||
const body = JSON.stringify({ sid })
|
||||
try {
|
||||
await fetch(url, { method: 'POST', headers: { 'Content-type': 'application/json' }, body })
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
textarea {
|
||||
padding: 0 0.25em;
|
||||
}
|
||||
|
||||
.label {
|
||||
width: auto;
|
||||
padding: 0.2em 1em
|
||||
}
|
||||
|
||||
.success.active {
|
||||
background-color: #35df8d;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.error.active {
|
||||
background-color: #ff7386;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#container2 {
|
||||
max-width: 33vw;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1024px) {
|
||||
#container2 {
|
||||
max-width: 80vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
#container2 {
|
||||
max-width: 90vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 640px) {
|
||||
#container2 {
|
||||
max-width: 100vw;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -21,6 +21,9 @@ button:disabled {
|
|||
input {
|
||||
color: #000;
|
||||
}
|
||||
textarea {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #8787a4;
|
||||
|
|
|
@ -17,6 +17,7 @@ import UserOrders from '@/components/UserOrders'
|
|||
import OrderForm from '@/components/OrderForm'
|
||||
import MarketOrders from '@/components/MarketOrders'
|
||||
import MarketStats from '@/components/MarketStats'
|
||||
import MarketSettings from '@/components/MarketSettings'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
|
@ -43,7 +44,8 @@ const routes = [
|
|||
children: [
|
||||
{ path: 'form', name: 'form', component: OrderForm },
|
||||
{ path: 'orders', name: 'market-orders', component: MarketOrders },
|
||||
{ path: 'stats', name: 'market-stats', component: MarketStats }
|
||||
{ path: 'stats', name: 'market-stats', component: MarketStats },
|
||||
{ path: 'settings', name: 'market-settings', component: MarketSettings }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue