Skip to content

Commit

Permalink
Order submit button state disabled if insufficient balance
Browse files Browse the repository at this point in the history
Fixed tooltip messages
  • Loading branch information
peterzen committed Sep 26, 2023
1 parent a72e734 commit 6769d5b
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 6 deletions.
8 changes: 8 additions & 0 deletions client/webserver/site/src/css/market_dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ body.dark {
background-color: #e95e5e99;
}
}

button:disabled {
opacity: 0.4;

&:hover {
cursor: help;
}
}
}

#verifyForm {
Expand Down
2 changes: 1 addition & 1 deletion client/webserver/site/src/html/markets.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@

{{- /* SUBMIT ORDER BUTTON */ -}}
<div class="text-end">
<button id="submitBttn" type="button" class="my-1 fs14 submit text-center buygreen-bg"></button> {{/* textContent set by script */}}
<button id="submitBttn" type="button" class="my-1 fs14 submit text-center buygreen-bg" disabled="disabled"></button> {{/* textContent set by script */}}
</div>
</div>
<div class="fs15 pt-3 text-center d-hide errcolor text-break" id="orderErr"></div>
Expand Down
6 changes: 6 additions & 0 deletions client/webserver/site/src/js/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,19 @@ export const ID_TICKET_STATUS_MISSED = 'TICKET_STATUS_MISSED'
export const ID_TICKET_STATUS_EXPIRED = 'TICKET_STATUS_EXPIRED'
export const ID_TICKET_STATUS_UNSPENT = 'TICKET_STATUS_UNSPENT'
export const ID_TICKET_STATUS_REVOKED = 'TICKET_STATUS_REVOKED'
export const ID_ORDER_BUTTON_BUY_BALANCE_ERROR = 'ID_ORDER_BUTTON_BUY_BALANCE_ERROR'
export const ID_ORDER_BUTTON_SELL_BALANCE_ERROR = 'ID_ORDER_BUTTON_SELL_BALANCE_ERROR'
export const ID_ORDER_BUTTON_QTY_ERROR = 'ID_ORDER_BUTTON_QTY_ERROR'

export const enUS: Locale = {
[ID_NO_PASS_ERROR_MSG]: 'password cannot be empty',
[ID_NO_APP_PASS_ERROR_MSG]: 'app password cannot be empty',
[ID_PASSWORD_NOT_MATCH]: 'passwords do not match',
[ID_SET_BUTTON_BUY]: 'Place order to buy {{ asset }}',
[ID_SET_BUTTON_SELL]: 'Place order to sell {{ asset }}',
[ID_ORDER_BUTTON_BUY_BALANCE_ERROR]: 'Insufficient balance to buy.',
[ID_ORDER_BUTTON_SELL_BALANCE_ERROR]: 'Insufficient balance to sell.',
[ID_ORDER_BUTTON_QTY_ERROR]: 'Order quantity must be specified.',
[ID_OFF]: 'off',
[ID_READY]: 'ready',
[ID_LOCKED]: 'locked',
Expand Down
74 changes: 69 additions & 5 deletions client/webserver/site/src/js/markets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,11 @@ export default class MarketsPage extends BasePage {
const maxSell = this.market.maxSell
if (!maxSell) return
page.lotField.value = String(maxSell.swap.lots)
} else page.lotField.value = String(this.market.maxBuys[this.adjustedRate()].swap.lots)
} else {
const maxBuy = this.market.maxBuys[this.adjustedRate()]
if (!maxBuy) return
page.lotField.value = String(maxBuy.swap.lots)
}
this.lotChanged()
})

Expand Down Expand Up @@ -566,6 +570,7 @@ export default class MarketsPage extends BasePage {
page.submitBttn.classList.add(buyBtnClass)
page.maxLbl.textContent = intl.prep(intl.ID_BUY)
this.setOrderBttnText()
this.setOrderBttnEnabled(false)
this.setOrderVisibility()
this.drawChartLines()
}
Expand All @@ -577,6 +582,7 @@ export default class MarketsPage extends BasePage {
page.submitBttn.classList.remove(buyBtnClass)
page.maxLbl.textContent = intl.prep(intl.ID_SELL)
this.setOrderBttnText()
this.setOrderBttnEnabled(false)
this.setOrderVisibility()
this.drawChartLines()
}
Expand Down Expand Up @@ -1008,6 +1014,17 @@ export default class MarketsPage extends BasePage {
} else this.page.submitBttn.textContent = intl.prep(intl.ID_SET_BUTTON_BUY, { asset: Doc.shortSymbol(this.market.baseCfg.unitInfo.conventional.unit) })
}

setOrderBttnEnabled (isEnabled: boolean, disabledTooltipMsg?: string) {
const btn = this.page.submitBttn
if (isEnabled) {
btn.removeAttribute('disabled')
btn.removeAttribute('title')
} else {
btn.setAttribute('disabled', 'disabled')
if (disabledTooltipMsg) btn.setAttribute('title', disabledTooltipMsg)
}
}

setCandleDurBttns () {
const { page, market } = this
Doc.empty(page.durBttnBox)
Expand Down Expand Up @@ -1233,7 +1250,7 @@ export default class MarketsPage extends BasePage {
previewQuoteAmt (show: boolean) {
const page = this.page
if (!this.market.base || !this.market.quote) return // Not a supported asset
const order = this.parseOrder()
const order = this.currentOrder = this.parseOrder()
const adjusted = this.adjustedRate()
page.orderErr.textContent = ''
if (adjusted) {
Expand Down Expand Up @@ -1270,11 +1287,21 @@ export default class MarketsPage extends BasePage {
const baseWallet = app().assets[mkt.base.id].wallet
if (baseWallet.balance.available < mkt.cfg.lotsize) {
this.setMaxOrder(null)
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_SELL_BALANCE_ERROR))
return
}
const orderQty = this.currentOrder.qty
if (mkt.maxSell) {
this.setMaxOrder(mkt.maxSell.swap)
return
if (!orderQty) {
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_QTY_ERROR))
return
}
if (orderQty > mkt.maxSell.swap.value) {
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_SELL_BALANCE_ERROR))
return
}
this.setOrderBttnEnabled(true)
}
if (mkt.maxSellRequested) return
mkt.maxSellRequested = true
Expand All @@ -1284,6 +1311,15 @@ export default class MarketsPage extends BasePage {
mkt.maxSell = res.maxSell
mkt.sellBalance = baseWallet.balance.available
this.setMaxOrder(res.maxSell.swap)
if (!orderQty) {
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_QTY_ERROR))
return
}
if (orderQty > mkt.maxSell.swap.value) {
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_SELL_BALANCE_ERROR))
return
}
this.setOrderBttnEnabled(true)
})
}

Expand All @@ -1298,11 +1334,21 @@ export default class MarketsPage extends BasePage {
const aLot = mkt.cfg.lotsize * (rate / OrderUtil.RateEncodingFactor)
if (quoteWallet.balance.available < aLot) {
this.setMaxOrder(null)
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_BUY_BALANCE_ERROR))
return
}
const orderQty = this.currentOrder.qty
if (mkt.maxBuys[rate]) {
this.setMaxOrder(mkt.maxBuys[rate].swap)
return
if (!orderQty) {
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_QTY_ERROR))
return
}
if (orderQty > mkt.maxBuys[rate].swap.value) {
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_BUY_BALANCE_ERROR))
return
}
this.setOrderBttnEnabled(true)
}
// 0 delay for first fetch after balance update or market change, otherwise
// meter these at 1 / sec.
Expand All @@ -1311,6 +1357,15 @@ export default class MarketsPage extends BasePage {
mkt.maxBuys[rate] = res.maxBuy
mkt.buyBalance = app().assets[mkt.quote.id].wallet.balance.available
this.setMaxOrder(res.maxBuy.swap)
if (!orderQty) {
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_QTY_ERROR))
return
}
if (orderQty > mkt.maxBuys[rate].swap.value) {
this.setOrderBttnEnabled(false, intl.prep(intl.ID_ORDER_BUTTON_BUY_BALANCE_ERROR))
return
}
this.setOrderBttnEnabled(true)
})
}

Expand Down Expand Up @@ -2586,6 +2641,9 @@ export default class MarketsPage extends BasePage {
lotChanged () {
const page = this.page
const lots = parseInt(page.lotField.value || '0')
if (!this.isLimit()) {
this.setOrderBttnEnabled(lots > 0)
}
if (lots <= 0) {
page.lotField.value = '0'
page.qtyField.value = ''
Expand Down Expand Up @@ -2614,6 +2672,9 @@ export default class MarketsPage extends BasePage {
}
const lotSize = this.market.cfg.lotsize
const lots = Math.floor(order.qty / lotSize)
if (!this.isLimit()) {
this.setOrderBttnEnabled(lots > 0)
}
const adjusted = lots * lotSize
page.lotField.value = String(lots)
if (!order.isLimit && !order.sell) return
Expand All @@ -2633,12 +2694,15 @@ export default class MarketsPage extends BasePage {
if (!gap || !qty) {
page.mktBuyLots.textContent = '0'
page.mktBuyScore.textContent = '0'
this.setOrderBttnEnabled(false)
return
}
const lotSize = this.market.cfg.lotsize
const received = qty / gap
page.mktBuyLots.textContent = (received / lotSize).toFixed(1)
const lots = (received / lotSize)
page.mktBuyLots.textContent = lots.toFixed(1)
page.mktBuyScore.textContent = Doc.formatCoinValue(received, this.market.baseUnitInfo)
this.setOrderBttnEnabled(lots >= 1)
}

/*
Expand Down

0 comments on commit 6769d5b

Please sign in to comment.