Changeset View
Changeset View
Standalone View
Standalone View
src/resources/vue/Wallet.vue
Show First 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | <div class="container" dusk="wallet-component"> | ||||
<div class="card-text"> | <div class="card-text"> | ||||
<p v-if="receipts.length"> | <p v-if="receipts.length"> | ||||
{{ $t('wallet.receipts-hint') }} | {{ $t('wallet.receipts-hint') }} | ||||
</p> | </p> | ||||
<div v-if="receipts.length" class="input-group"> | <div v-if="receipts.length" class="input-group"> | ||||
<select id="receipt-id" class="form-control"> | <select id="receipt-id" class="form-control"> | ||||
<option v-for="(receipt, index) in receipts" :key="index" :value="receipt">{{ receipt }}</option> | <option v-for="(receipt, index) in receipts" :key="index" :value="receipt">{{ receipt }}</option> | ||||
</select> | </select> | ||||
<div class="input-group-append"> | |||||
<button type="button" class="btn btn-secondary" @click="receiptDownload"> | <button type="button" class="btn btn-secondary" @click="receiptDownload"> | ||||
<svg-icon icon="download"></svg-icon> {{ $t('btn.download') }} | <svg-icon icon="download"></svg-icon> {{ $t('btn.download') }} | ||||
</button> | </button> | ||||
</div> | </div> | ||||
</div> | |||||
<p v-if="!receipts.length"> | <p v-if="!receipts.length"> | ||||
{{ $t('wallet.receipts-none') }} | {{ $t('wallet.receipts-none') }} | ||||
</p> | </p> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="tab-pane" id="wallet-history" role="tabpanel" aria-labelledby="tab-history"> | <div class="tab-pane" id="wallet-history" role="tabpanel" aria-labelledby="tab-history"> | ||||
<div class="card-body"> | <div class="card-body"> | ||||
<transaction-log v-if="walletId && loadTransactions" class="card-text" :wallet-id="walletId"></transaction-log> | <transaction-log v-if="walletId && loadTransactions" class="card-text" :wallet-id="walletId"></transaction-log> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="tab-pane" id="wallet-payments" role="tabpanel" aria-labelledby="tab-payments"> | <div class="tab-pane" id="wallet-payments" role="tabpanel" aria-labelledby="tab-payments"> | ||||
<div class="card-body"> | <div class="card-body"> | ||||
<payment-log v-if="walletId && loadPayments" class="card-text" :wallet-id="walletId"></payment-log> | <payment-log v-if="walletId && loadPayments" class="card-text" :wallet-id="walletId"></payment-log> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div id="payment-dialog" class="modal" tabindex="-1" role="dialog"> | <div id="payment-dialog" class="modal" tabindex="-1" role="dialog"> | ||||
<div class="modal-dialog" role="document"> | <div class="modal-dialog" role="document"> | ||||
<div class="modal-content"> | <div class="modal-content"> | ||||
<div class="modal-header"> | <div class="modal-header"> | ||||
<h5 class="modal-title">{{ paymentDialogTitle }}</h5> | <h5 class="modal-title">{{ paymentDialogTitle }}</h5> | ||||
<button type="button" class="close" data-dismiss="modal" :aria-label="$t('btn.close')"> | <button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="$t('btn.close')"></button> | ||||
<span aria-hidden="true">×</span> | |||||
</button> | |||||
</div> | </div> | ||||
<div class="modal-body"> | <div class="modal-body"> | ||||
<div id="payment-method" v-if="paymentForm == 'method'"> | <div id="payment-method" v-if="paymentForm == 'method'"> | ||||
<form data-validation-prefix="mandate_"> | <form data-validation-prefix="mandate_"> | ||||
<div id="payment-method-selection"> | <div id="payment-method-selection"> | ||||
<a :id="method.id" v-for="method in paymentMethods" :key="method.id" @click="selectPaymentMethod(method)" href="#" class="card link-profile"> | <a :id="method.id" v-for="method in paymentMethods" :key="method.id" @click="selectPaymentMethod(method)" href="#" class="card link-profile"> | ||||
<svg-icon v-if="method.icon" :icon="[method.icon.prefix, method.icon.name]" /> | <svg-icon v-if="method.icon" :icon="[method.icon.prefix, method.icon.name]" /> | ||||
<img v-if="method.image" :src="method.image" /> | <img v-if="method.image" :src="method.image" /> | ||||
<span class="name">{{ method.name }}</span> | <span class="name">{{ method.name }}</span> | ||||
</a> | </a> | ||||
</div> | </div> | ||||
</form> | </form> | ||||
</div> | </div> | ||||
<div id="manual-payment" v-if="paymentForm == 'manual'"> | <div id="manual-payment" v-if="paymentForm == 'manual'"> | ||||
<p v-if="wallet.currency != selectedPaymentMethod.currency"> | <p v-if="wallet.currency != selectedPaymentMethod.currency"> | ||||
{{ $t('wallet.currency-conv', { wc: wallet.currency, pc: selectedPaymentMethod.currency }) }} | {{ $t('wallet.currency-conv', { wc: wallet.currency, pc: selectedPaymentMethod.currency }) }} | ||||
</p> | </p> | ||||
<p v-if="selectedPaymentMethod.id == 'banktransfer'"> | <p v-if="selectedPaymentMethod.id == 'banktransfer'"> | ||||
{{ $t('wallet.banktransfer-hint') }} | {{ $t('wallet.banktransfer-hint') }} | ||||
</p> | </p> | ||||
<p> | <p> | ||||
{{ $t('wallet.payment-amount-hint') }} | {{ $t('wallet.payment-amount-hint') }} | ||||
</p> | </p> | ||||
<form id="payment-form" @submit.prevent="payment"> | <form id="payment-form" @submit.prevent="payment"> | ||||
<div class="form-group"> | |||||
<div class="input-group"> | <div class="input-group"> | ||||
<input type="text" class="form-control" id="amount" v-model="amount" required> | <input type="text" class="form-control" id="amount" v-model="amount" required> | ||||
<span class="input-group-append"> | |||||
<span class="input-group-text">{{ wallet.currency }}</span> | <span class="input-group-text">{{ wallet.currency }}</span> | ||||
</span> | |||||
</div> | |||||
</div> | </div> | ||||
<div v-if="wallet.currency != selectedPaymentMethod.currency && !isNaN(amount)" class="alert alert-warning"> | <div v-if="wallet.currency != selectedPaymentMethod.currency && !isNaN(amount)" class="alert alert-warning m-0 mt-3"> | ||||
{{ $t('wallet.payment-warning', { price: $root.price(amount * selectedPaymentMethod.exchangeRate * 100, selectedPaymentMethod.currency) }) }} | {{ $t('wallet.payment-warning', { price: $root.price(amount * selectedPaymentMethod.exchangeRate * 100, selectedPaymentMethod.currency) }) }} | ||||
</div> | </div> | ||||
</form> | </form> | ||||
</div> | </div> | ||||
<div id="auto-payment" v-if="paymentForm == 'auto'"> | <div id="auto-payment" v-if="paymentForm == 'auto'"> | ||||
<form data-validation-prefix="mandate_"> | <form data-validation-prefix="mandate_"> | ||||
<p> | <p> | ||||
{{ $t('wallet.auto-payment-hint') }} | {{ $t('wallet.auto-payment-hint') }} | ||||
</p> | </p> | ||||
<div class="form-group row"> | <div class="row mb-3"> | ||||
<label for="mandate_amount" class="col-sm-6 col-form-label">{{ $t('wallet.fill-up') }}</label> | <label for="mandate_amount" class="col-sm-6 col-form-label">{{ $t('wallet.fill-up') }}</label> | ||||
<div class="input-group col-sm-6"> | <div class="col-sm-6"> | ||||
<div class="input-group"> | |||||
<input type="text" class="form-control" id="mandate_amount" v-model="mandate.amount" required> | <input type="text" class="form-control" id="mandate_amount" v-model="mandate.amount" required> | ||||
<span class="input-group-append"> | |||||
<span class="input-group-text">{{ wallet.currency }}</span> | <span class="input-group-text">{{ wallet.currency }}</span> | ||||
</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group row"> | </div> | ||||
<div class="row mb-3"> | |||||
<label for="mandate_balance" class="col-sm-6 col-form-label">{{ $t('wallet.when-below') }}</label> | <label for="mandate_balance" class="col-sm-6 col-form-label">{{ $t('wallet.when-below') }}</label> | ||||
<div class="col-sm-6"> | <div class="col-sm-6"> | ||||
<div class="input-group"> | <div class="input-group"> | ||||
<input type="text" class="form-control" id="mandate_balance" v-model="mandate.balance" required> | <input type="text" class="form-control" id="mandate_balance" v-model="mandate.balance" required> | ||||
<span class="input-group-append"> | |||||
<span class="input-group-text">{{ wallet.currency }}</span> | <span class="input-group-text">{{ wallet.currency }}</span> | ||||
</span> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<p v-if="!mandate.isValid"> | <p v-if="!mandate.isValid"> | ||||
{{ $t('wallet.auto-payment-next') }} | {{ $t('wallet.auto-payment-next') }} | ||||
</p> | </p> | ||||
<div v-if="mandate.isValid && mandate.isDisabled" class="disabled-mandate alert alert-danger"> | <div v-if="mandate.isValid && mandate.isDisabled" class="disabled-mandate alert alert-danger m-0"> | ||||
{{ $t('wallet.auto-payment-disabled-next') }} | {{ $t('wallet.auto-payment-disabled-next') }} | ||||
</div> | </div> | ||||
</form> | </form> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="modal-footer"> | <div class="modal-footer"> | ||||
<button type="button" class="btn btn-secondary modal-cancel" data-dismiss="modal">{{ $t('btn.cancel') }}</button> | <button type="button" class="btn btn-secondary modal-cancel" data-bs-dismiss="modal">{{ $t('btn.cancel') }}</button> | ||||
<button type="button" class="btn btn-primary modal-action" | <button type="button" class="btn btn-primary modal-action" | ||||
v-if="paymentForm == 'auto' && (mandate.isValid || mandate.isPending)" | v-if="paymentForm == 'auto' && (mandate.isValid || mandate.isPending)" | ||||
@click="autoPayment" | @click="autoPayment" | ||||
> | > | ||||
<svg-icon icon="check"></svg-icon> {{ $t('btn.submit') }} | <svg-icon icon="check"></svg-icon> {{ $t('btn.submit') }} | ||||
</button> | </button> | ||||
<button type="button" class="btn btn-primary modal-action" | <button type="button" class="btn btn-primary modal-action" | ||||
v-if="paymentForm == 'auto' && !mandate.isValid && !mandate.isPending" | v-if="paymentForm == 'auto' && !mandate.isValid && !mandate.isPending" | ||||
Show All 10 Lines | <div class="container" dusk="wallet-component"> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</template> | </template> | ||||
<script> | <script> | ||||
import { Modal } from 'bootstrap' | |||||
import TransactionLog from './Widgets/TransactionLog' | import TransactionLog from './Widgets/TransactionLog' | ||||
import PaymentLog from './Widgets/PaymentLog' | import PaymentLog from './Widgets/PaymentLog' | ||||
export default { | export default { | ||||
components: { | components: { | ||||
TransactionLog, | TransactionLog, | ||||
PaymentLog | PaymentLog | ||||
}, | }, | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | export default { | ||||
.catch(this.$root.errorHandler) | .catch(this.$root.errorHandler) | ||||
this.loadMandate() | this.loadMandate() | ||||
axios.get('/api/v4/payments/has-pending') | axios.get('/api/v4/payments/has-pending') | ||||
.then(response => { | .then(response => { | ||||
this.showPendingPayments = response.data.hasPending | this.showPendingPayments = response.data.hasPending | ||||
}) | }) | ||||
}, | }, | ||||
updated() { | updated() { | ||||
$(this.$el).find('ul.nav-tabs a').on('click', e => { | $(this.$el).find('ul.nav-tabs a').on('click', e => { | ||||
e.preventDefault() | this.$root.tab(e) | ||||
$(e.target).tab('show') | |||||
if ($(e.target).is('#tab-history')) { | if ($(e.target).is('#tab-history')) { | ||||
this.loadTransactions = true | this.loadTransactions = true | ||||
} | } else if ($(e.target).is('#tab-payments')) { | ||||
if ($(e.target).is('#tab-payments')) { | |||||
this.loadPayments = true | this.loadPayments = true | ||||
} | } | ||||
}) | }) | ||||
}, | }, | ||||
methods: { | methods: { | ||||
loadMandate() { | loadMandate() { | ||||
const mandate_form = $('#mandate-form') | const mandate_form = $('#mandate-form') | ||||
this.$root.removeLoader(mandate_form) | this.$root.removeLoader(mandate_form) | ||||
if (!this.mandate.id || this.mandate.isPending) { | if (!this.mandate.id || this.mandate.isPending) { | ||||
this.$root.addLoader(mandate_form) | this.$root.addLoader(mandate_form) | ||||
axios.get('/api/v4/payments/mandate') | axios.get('/api/v4/payments/mandate') | ||||
.then(response => { | .then(response => { | ||||
this.$root.removeLoader(mandate_form) | this.$root.removeLoader(mandate_form) | ||||
this.mandate = response.data | this.mandate = response.data | ||||
}) | }) | ||||
.catch(error => { | .catch(error => { | ||||
this.$root.removeLoader(mandate_form) | this.$root.removeLoader(mandate_form) | ||||
}) | }) | ||||
} | } | ||||
}, | }, | ||||
selectPaymentMethod(method) { | selectPaymentMethod(method) { | ||||
this.formLock = false | this.formLock = false | ||||
this.selectedPaymentMethod = method | this.selectedPaymentMethod = method | ||||
this.paymentForm = this.nextForm | this.paymentForm = this.nextForm | ||||
this.formLock = false | |||||
setTimeout(() => { | setTimeout(() => { $('#payment-dialog').find('#amount,#mandate_amount').focus() }, 10) | ||||
this.dialog.find('#mandate_amount').focus() | |||||
this.dialog.find('#amount').focus() | |||||
}, 10) | |||||
}, | }, | ||||
payment() { | payment() { | ||||
if (this.formLock) { | if (this.formLock) { | ||||
return | return | ||||
} | } | ||||
// Lock the form to prevent from double submission | // Lock the form to prevent from double submission | ||||
this.formLock = true | this.formLock = true | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | export default { | ||||
if (response.data.redirectUrl) { | if (response.data.redirectUrl) { | ||||
location.href = response.data.redirectUrl | location.href = response.data.redirectUrl | ||||
} else if (response.data.id) { | } else if (response.data.id) { | ||||
this.stripeCheckout(response.data) | this.stripeCheckout(response.data) | ||||
} | } | ||||
} else { | } else { | ||||
// an update | // an update | ||||
if (response.data.status == 'success') { | if (response.data.status == 'success') { | ||||
this.dialog.modal('hide'); | this.dialog.hide(); | ||||
this.mandate = response.data | this.mandate = response.data | ||||
this.$toast.success(response.data.message) | this.$toast.success(response.data.message) | ||||
} | } | ||||
} | } | ||||
}) | }) | ||||
}, | }, | ||||
autoPaymentChange(event) { | autoPaymentChange(event) { | ||||
this.autoPaymentForm(event, this.$t('wallet.auto-payment-update')) | this.autoPaymentForm(event, this.$t('wallet.auto-payment-update')) | ||||
}, | }, | ||||
autoPaymentDelete() { | autoPaymentDelete() { | ||||
axios.delete('/api/v4/payments/mandate') | axios.delete('/api/v4/payments/mandate') | ||||
.then(response => { | .then(response => { | ||||
this.mandate = { amount: 10, balance: 0 } | this.mandate = { amount: 10, balance: 0 } | ||||
if (response.data.status == 'success') { | if (response.data.status == 'success') { | ||||
this.$toast.success(response.data.message) | this.$toast.success(response.data.message) | ||||
} | } | ||||
}) | }) | ||||
}, | }, | ||||
paymentMethodForm(nextForm) { | paymentMethodForm(nextForm) { | ||||
const dialog = $('#payment-dialog') | |||||
this.formLock = false | this.formLock = false | ||||
this.paymentMethods = [] | this.paymentMethods = [] | ||||
this.paymentForm = 'method' | this.paymentForm = 'method' | ||||
this.nextForm = nextForm | this.nextForm = nextForm | ||||
if (nextForm == 'auto') { | this.paymentDialogTitle = this.$t(nextForm == 'auto' ? 'wallet.auto-payment-setup' : 'wallet.top-up') | ||||
this.paymentDialogTitle = this.$t('wallet.auto-payment-setup') | |||||
} else { | this.dialog = new Modal('#payment-dialog') | ||||
this.paymentDialogTitle = this.$t('wallet.top-up') | this.dialog.show() | ||||
} | |||||
this.$nextTick().then(() => { | |||||
const form = $('#payment-method') | |||||
this.$root.addLoader(form, false, {'min-height': '10em'}) | |||||
const methods = $('#payment-method') | |||||
this.$root.addLoader(methods, false) | |||||
axios.get('/api/v4/payments/methods', {params: {type: nextForm == 'manual' ? 'oneoff' : 'recurring'}}) | axios.get('/api/v4/payments/methods', {params: {type: nextForm == 'manual' ? 'oneoff' : 'recurring'}}) | ||||
.then(response => { | .then(response => { | ||||
this.$root.removeLoader(methods) | this.$root.removeLoader(form) | ||||
this.paymentMethods = response.data | this.paymentMethods = response.data | ||||
}) | }) | ||||
.catch(this.$root.errorHandler) | }) | ||||
this.dialog = dialog.on('shown.bs.modal', () => {}).modal() | |||||
}, | }, | ||||
autoPaymentForm(event, title) { | autoPaymentForm(event, title) { | ||||
const dialog = $('#payment-dialog') | |||||
this.paymentForm = 'auto' | this.paymentForm = 'auto' | ||||
this.paymentDialogTitle = title | this.paymentDialogTitle = title | ||||
this.formLock = false | this.formLock = false | ||||
this.dialog = dialog.on('shown.bs.modal', () => { | this.dialog = new Modal('#payment-dialog') | ||||
dialog.find('#mandate_amount').focus() | this.dialog.show() | ||||
}).modal() | |||||
setTimeout(() => { this.dialog.find('#mandate_amount').focus()}, 10) | |||||
}, | }, | ||||
receiptDownload() { | receiptDownload() { | ||||
const receipt = $('#receipt-id').val() | const receipt = $('#receipt-id').val() | ||||
this.$root.downloadFile('/api/v4/wallets/' + this.walletId + '/receipts/' + receipt) | this.$root.downloadFile('/api/v4/wallets/' + this.walletId + '/receipts/' + receipt) | ||||
}, | }, | ||||
stripeInit() { | stripeInit() { | ||||
let script = $('#stripe-script') | let script = $('#stripe-script') | ||||
Show All 33 Lines |