mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-26 23:49:57 +01:00
Fixes #5530. For the use case of giving access to cashiers we need to find another solution than showing the recent transactions for signed out users.
155 lines
6.8 KiB
JavaScript
155 lines
6.8 KiB
JavaScript
document.addEventListener("DOMContentLoaded",function () {
|
|
const displayFontSize = 64;
|
|
new Vue({
|
|
el: '#app',
|
|
mixins: [posCommon],
|
|
data () {
|
|
return {
|
|
mode: 'amounts',
|
|
fontSize: displayFontSize,
|
|
defaultFontSize: displayFontSize,
|
|
keys: ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', '0', '+'],
|
|
amounts: [null],
|
|
recentTransactions: [],
|
|
recentTransactionsLoading: false,
|
|
dateFormatter: new Intl.DateTimeFormat('default', { dateStyle: 'short', timeStyle: 'short' })
|
|
}
|
|
},
|
|
computed: {
|
|
modes () {
|
|
const modes = [{ title: 'Amount', type: 'amounts' }]
|
|
if (this.showDiscount) modes.push({ title: 'Discount', type: 'discount' })
|
|
if (this.enableTips) modes.push({ title: 'Tip', type: 'tip'})
|
|
return modes
|
|
},
|
|
keypadTarget () {
|
|
switch (this.mode) {
|
|
case 'amounts':
|
|
return 'amounts';
|
|
case 'discount':
|
|
return 'discountPercent';
|
|
case 'tip':
|
|
return 'tip';
|
|
}
|
|
},
|
|
calculation () {
|
|
if (!this.tipNumeric && !(this.discountNumeric > 0 || this.discountPercentNumeric > 0) && this.amounts.length < 2) return null
|
|
let calc = this.amounts.map(amt => this.formatCurrency(amt, true)).join(' + ')
|
|
if (this.discountNumeric > 0 || this.discountPercentNumeric > 0) calc += ` - ${this.formatCurrency(this.discountNumeric, true)} (${this.discountPercent}%)`
|
|
if (this.tipNumeric > 0) calc += ` + ${this.formatCurrency(this.tipNumeric, true)}`
|
|
if (this.tipPercent) calc += ` (${this.tipPercent}%)`
|
|
return calc
|
|
}
|
|
},
|
|
watch: {
|
|
total () {
|
|
// This must be timed out because the updated width is not available yet
|
|
this.$nextTick(function () {
|
|
const displayWidth = this.getWidth(this.$refs.display),
|
|
amountWidth = this.getWidth(this.$refs.amount),
|
|
gamma = displayWidth / amountWidth || 0,
|
|
isAmountWider = displayWidth < amountWidth;
|
|
|
|
if (isAmountWider) {
|
|
// Font size will get smaller
|
|
this.fontSize = Math.floor(this.fontSize * gamma);
|
|
} else if (!isAmountWider && this.fontSize < this.defaultFontSize) {
|
|
// Font size will get larger up to the max size
|
|
this.fontSize = Math.min(this.fontSize * gamma, this.defaultFontSize);
|
|
}
|
|
});
|
|
},
|
|
amounts (values) {
|
|
this.amount = values.reduce((total, current) => total + parseFloat(current || '0'), 0);
|
|
}
|
|
},
|
|
methods: {
|
|
getWidth(el) {
|
|
const styles = window.getComputedStyle(el),
|
|
width = parseFloat(el.clientWidth),
|
|
padL = parseFloat(styles.paddingLeft),
|
|
padR = parseFloat(styles.paddingRight);
|
|
return width - padL - padR;
|
|
},
|
|
clear() {
|
|
this.amounts = [null];
|
|
this.tip = this.discount = this.tipPercent = this.discountPercent = null;
|
|
this.mode = 'amounts';
|
|
},
|
|
applyKeyToValue(key, value, divisibility) {
|
|
if (!value || value === '0') value = '';
|
|
value = (value + key)
|
|
.replace('.', '')
|
|
.padStart(divisibility, '0')
|
|
.replace(new RegExp(`(\\d*)(\\d{${divisibility}})`), '$1.$2');
|
|
return parseFloat(value).toFixed(divisibility);
|
|
},
|
|
keyPressed (key) {
|
|
if (this.keypadTarget === 'amounts') {
|
|
const lastIndex = this.amounts.length - 1;
|
|
const lastAmount = this.amounts[lastIndex];
|
|
if (key === 'C') {
|
|
if (!lastAmount && lastIndex === 0) {
|
|
// clear completely
|
|
this.clear();
|
|
} else if (!lastAmount) {
|
|
// remove latest value
|
|
this.amounts.pop();
|
|
} else {
|
|
// clear latest value
|
|
Vue.set(this.amounts, lastIndex, null);
|
|
}
|
|
} else if (key === '+' && parseFloat(lastAmount || '0')) {
|
|
this.amounts.push(null);
|
|
} else { // Is a digit
|
|
const { divisibility } = this.currencyInfo;
|
|
const value = this.applyKeyToValue(key, lastAmount, divisibility);
|
|
Vue.set(this.amounts, lastIndex, value);
|
|
}
|
|
} else {
|
|
if (key === 'C') {
|
|
this[this.keypadTarget] = null;
|
|
} else {
|
|
const divisibility = this.keypadTarget === 'tip' ? this.currencyInfo.divisibility : 0;
|
|
this[this.keypadTarget] = this.applyKeyToValue(key, this[this.keypadTarget], divisibility);
|
|
}
|
|
}
|
|
},
|
|
doubleClick (key) {
|
|
if (key === 'C') {
|
|
// clear completely
|
|
this.clear();
|
|
}
|
|
},
|
|
closeModal() {
|
|
bootstrap.Modal.getInstance(this.$refs.RecentTransactions).hide();
|
|
},
|
|
displayDate(val) {
|
|
const date = new Date(val);
|
|
return this.dateFormatter.format(date);
|
|
},
|
|
async loadRecentTransactions() {
|
|
this.recentTransactionsLoading = true;
|
|
const { url } = this.$refs.RecentTransactions.dataset;
|
|
try {
|
|
const response = await fetch(url);
|
|
if (response.ok) {
|
|
this.recentTransactions = await response.json();
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
} finally {
|
|
this.recentTransactionsLoading = false;
|
|
}
|
|
}
|
|
},
|
|
created() {
|
|
// We need to unset state in case user clicks the browser back button
|
|
window.addEventListener('pagehide', () => { this.payButtonLoading = false })
|
|
},
|
|
mounted() {
|
|
this.$refs.RecentTransactions.addEventListener('show.bs.modal', this.loadRecentTransactions);
|
|
}
|
|
});
|
|
});
|
|
|