<template> <section v-if="!complete" class="select-credits"> <div class="credits-pane"><h2>10 Credits</h2> <h3>$10.99</h3><div><span>Qty</span><input min="0" max="1000" v-model="packs.credits10" type="number"></div> </div> <div class="credits-pane"><div><h2>50 Credits</h2><span>+5 Free Credits</span></div> <h3>$54.99 </h3><div><span>Qty</span><input min="0" max="1000" v-model="packs.credits50" type="number"></div> </div> <div class="credits-pane"><div><h2>100 Credits</h2><span>+10 Free Credits</span></div> <h3>$109.99</h3> <div><span>Qty</span><input min="0" max="1000" v-model="packs.credits100" type="number"></div> </div> <div class="credits-pane"><div><h2>1000 Credits</h2><span>+150 Free Credits</span></div> <h3>$1010.00</h3> <div><span>Qty</span><input min="0" max="1000" v-model="packs.credits1000" type="number"></div> </div> <h3>Total: ${{total.toLocaleString('en')}}</h3> <div id="credits-errors"></div> </section> <section v-if="!complete" id="payment-section"> <h4>Select a payment method</h4> <div class="sliding-menu"> <a @click="selectSaved = true" :class="{selected: selectSaved}">Saved Card</a> <a @click="selectSaved = false" :class="{selected: !selectSaved}">New Card</a> <div :class="{right: !selectSaved}" class="menu-slider"><div></div></div> </div> <saved-cards :preferred="preferred" v-model:picked-card="picked" :cards="cards" :token="token" v-if="selectSaved"></saved-cards> <payment-card @set-card="(c) => {card = c}" @card-valid="(val) => {cardValid = val}" @update-billing-name="billingName = $event.target.value" :stripe="stripe" v-if="!selectSaved"> </payment-card> <div id="payment-error"></div> </section> <section v-if="!complete" class="credits-confirm"> <button @click="pay" :disabled="!ready" class="brand-btn">Buy<loading v-if="loading"></loading></button> </section> <PurchaseCompleted v-if="complete"></PurchaseCompleted> </template> <script> import Loading from '../icons/loading.vue' import PaymentCard from './payment-card.vue' import SavedCards from './saved-cards.vue' import PurchaseCompleted from './purchase-completed.vue' function total() { return this.packs.credits10*10.99 + this.packs.credits50*54.99 + this.packs.credits100*109.99 + this.packs.credits1000*1010 } //Gets the secret key specific to chosen payment amount and user function getSecret() { document.getElementById('credits-errors').textContent = '' this.loading = true return fetch('/panel/secret', { method: 'POST', headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'X-XSRF-TOKEN': this.token}, body: JSON.stringify({'packs': this.packs}) }).then((response) => { if (response.ok) { return response.text() } else { document.getElementById('credits-errors').textContent = `${response.status}: ${response.statusText}` } }).then(secret => { this.loading = false return secret }) } //Gets key from the server then sends it with stripe //Maybe it should asl attach the user's receipt email function pay() { this.getSecret().then(secret => { if (!secret) {return} this.loading = true if (!this.selectSaved) { return this.stripe.confirmCardPayment(secret, { payment_method: { card: this.card, billing_details: {name: document.getElementById('billing-name').value}, }, setup_future_usage: document.querySelector( "#save-card input").value == 'on' ? 'off_session' : null }) } else { return this.stripe.confirmCardPayment(secret, { payment_method: this.picked }) } }).then(result => { if (result.error) { document.getElementById('payment-error').textContent = result.error.message } else if (result.paymentIntent.status === 'succeeded') { this.$emit('purchaseComplete') this.complete = true } else { document.getElementById('payment-error').textContent = 'An unknown error occured' } this.loading = false }) } function getCards() { fetch('/panel/cards', { method: 'GET', headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'X-XSRF-TOKEN': this.token} }).then((response) => {response.json().then(data => { this.cards = data.data if (this.cards && this.cards.length > 0) { this.picked = this.cards[0].id } })}) } function ready() { return this.total != 0 && !this.loading && ((this.cardValid && this.billingName) || this.picked) } export default { components:{Loading, PaymentCard, SavedCards, PurchaseCompleted}, data() { return {packs: {credits10: 0, credits50: 0, credits100: 0, credits1000: 0}, loading: false, stripe: window.Stripe(process.env.VUE_APP_STRIPE_KEY), card: null, billingName: null, selectSaved: true, cardValid: false, cards: null, picked: null, complete: false } }, computed: {total, ready}, methods: {getSecret, pay, getCards}, props: ['preferred', 'token'], emits: ['purchaseComplete'], created() { this.getCards() } } </script>