My SMM panel
 
 
 
 
 
 

153 line
4.5 KiB

  1. <template>
  2. <section class="select-credits">
  3. <div class="credits-pane"><h2>10 Credits</h2>
  4. <h3>$10.99</h3><div><span>Qty</span><input min="0" max="1000" v-model="packs.credits10" type="number"></div>
  5. </div>
  6. <div class="credits-pane"><div><h2>50 Credits</h2><span>+5 Free Credits</span></div>
  7. <h3>$54.99 </h3><div><span>Qty</span><input min="0" max="1000" v-model="packs.credits50" type="number"></div>
  8. </div>
  9. <div class="credits-pane"><div><h2>100 Credits</h2><span>+10 Free Credits</span></div>
  10. <h3>$109.99</h3> <div><span>Qty</span><input min="0" max="1000" v-model="packs.credits100" type="number"></div>
  11. </div>
  12. <div class="credits-pane"><div><h2>1000 Credits</h2><span>+150 Free Credits</span></div>
  13. <h3>$1010.00</h3> <div><span>Qty</span><input min="0" max="1000" v-model="packs.credits1000" type="number"></div>
  14. </div>
  15. <h3>Total: ${{total.toLocaleString('en')}}</h3>
  16. <div id="credits-errors"></div>
  17. </section>
  18. <section id="payment-section">
  19. <h4>Select a payment method</h4>
  20. <div class="sliding-menu">
  21. <a @click="selectSaved = true" :class="{selected: selectSaved}">Saved Card</a>
  22. <a @click="selectSaved = false" :class="{selected: !selectSaved}">New Card</a>
  23. <div :class="{right: !selectSaved}" class="menu-slider"><div></div></div>
  24. </div>
  25. <saved-cards v-model:picked-card="picked" :cards="cards"
  26. :token="token" v-if="selectSaved"></saved-cards>
  27. <payment-card @set-card="(c) => {card = c}" @card-valid="(val) => {cardValid = val}"
  28. @update-billing-name="billingName = $event.target.value" :stripe="stripe"
  29. v-if="!selectSaved">
  30. </payment-card>
  31. <div id="payment-error"></div>
  32. </section>
  33. <section class="credits-confirm">
  34. <button @click="pay" :disabled="!ready"
  35. class="brand-btn">Buy<loading v-if="loading"></loading></button>
  36. </section>
  37. </template>
  38. <script>
  39. import Loading from '../icons/loading.vue'
  40. import PaymentCard from './payment-card.vue'
  41. import SavedCards from './saved-cards.vue'
  42. function total() {
  43. return this.packs.credits10*10.99 + this.packs.credits50*54.99
  44. + this.packs.credits100*109.99 + this.packs.credits1000*1010
  45. }
  46. //Gets the secret key specific to chosen payment amount and user
  47. function getSecret() {
  48. document.getElementById('credits-errors').textContent = ''
  49. this.loading = true
  50. return fetch('/panel/secret', {
  51. method: 'POST',
  52. headers: {'Content-Type': 'application/json',
  53. 'Accept': 'application/json',
  54. 'X-XSRF-TOKEN': this.token},
  55. body: JSON.stringify({'packs': this.packs})
  56. }).then((response) => {
  57. if (response.ok) {
  58. return response.text()
  59. } else {
  60. document.getElementById('credits-errors').textContent =
  61. `${response.status}: ${response.statusText}`
  62. }
  63. }).then(secret => {
  64. this.loading = false
  65. return secret
  66. })
  67. }
  68. //Gets key from the server then sends it with stripe
  69. //Maybe it should asl attach the user's receipt email
  70. function pay() {
  71. this.getSecret().then(secret => {
  72. if (!secret) {return}
  73. this.loading = true
  74. if (!this.selectSaved) {
  75. return this.stripe.confirmCardPayment(secret, {
  76. payment_method: {
  77. card: this.card,
  78. billing_details: {name:
  79. document.getElementById('billing-name').value},
  80. },
  81. setup_future_usage: document.querySelector(
  82. "#save-card input").value == 'on' ? 'off_session' : null
  83. })
  84. } else {
  85. return this.stripe.confirmCardPayment(secret, {
  86. payment_method: this.picked
  87. })
  88. }
  89. }).then(result => {
  90. if (result.error) {
  91. document.getElementById('payment-error').textContent =
  92. result.error.message
  93. } else if (result.paymentIntent.status === 'succeeded') {
  94. this.complete()
  95. } else {
  96. document.getElementById('payment-error').textContent =
  97. 'An unknown error occured'
  98. }
  99. this.loading = false
  100. })
  101. }
  102. function getCards() {
  103. fetch('/panel/cards', {
  104. method: 'GET',
  105. headers: {'Content-Type': 'application/json',
  106. 'Accept': 'application/json',
  107. 'X-XSRF-TOKEN': this.token}
  108. }).then((response) => {response.json().then(data => {
  109. this.cards = data.data
  110. if (this.cards && this.cards.length > 0) {
  111. this.picked = this.cards[0].id
  112. }
  113. })})
  114. }
  115. function ready() {
  116. return this.total != 0 && !this.loading && ((this.cardValid &&
  117. this.billingName) || this.picked)
  118. }
  119. export default {
  120. components:{Loading, PaymentCard, SavedCards},
  121. data() {
  122. return {packs: {credits10: 0, credits50: 0,
  123. credits100: 0, credits1000: 0}, loading: false, stripe:
  124. window.Stripe(process.env.VUE_APP_STRIPE_KEY), card:
  125. null, billingName: null, selectSaved: true, cardValid: false, cards:
  126. null, picked: null
  127. }
  128. },
  129. computed: {total, ready},
  130. methods: {getSecret, pay, getCards},
  131. props: ['token'],
  132. created() {
  133. this.getCards()
  134. }
  135. }
  136. </script>