Переглянути джерело

Create a slider for selecting or creating cards

Checkboxes and function changes were also made for for optionally saving
cards. The new payment-card component needed to be created to mount the
stripe card correctly after DOM changes.
tags/v0.1.0
Immanuel Onyeka 3 роки тому
джерело
коміт
19105537d9
8 змінених файлів з 93 додано та 33 видалено
  1. +2
    -1
      app/Http/Controllers/BillingController.php
  2. +2
    -1
      app/Http/Controllers/UserController.php
  3. +1
    -0
      database/seeders/DatabaseSeeder.php
  4. +21
    -28
      resources/js/panel/credits.vue
  5. +38
    -0
      resources/js/panel/payment-card.vue
  6. +17
    -0
      resources/js/panel/payment-slider.vue
  7. +1
    -1
      resources/js/panel/services.vue
  8. +11
    -2
      resources/scss/main.scss

+ 2
- 1
app/Http/Controllers/BillingController.php Переглянути файл

@@ -7,6 +7,7 @@ use Stripe\Stripe;
use Stripe\Customer;
use Stripe\PaymentIntent;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;

class BillingController extends Controller
{
@@ -27,7 +28,7 @@ class BillingController extends Controller
$intent = PaymentIntent::create([
'amount' => $amount,
'currency' => 'usd',
/* 'customer' => Auth::user().customer_id, */
'customer' => Auth::user()->customer_id,
'metadata' => ['integration_check' => 'accept_a_payment']
]);



+ 2
- 1
app/Http/Controllers/UserController.php Переглянути файл

@@ -24,7 +24,8 @@ class UserController extends Controller
'email' => 'required|email|unique:users,email',
'password' => 'required|confirmed|min:8|regex:/[a-z]/|regex:/[A-Z]/|regex:/[0-9]/'
]);
/* Stripe::setApiKey(); */

Stripe::setApiKey(env('STRIPE_SECRET'));

$user = new User;
$user->name = $request->name;


+ 1
- 0
database/seeders/DatabaseSeeder.php Переглянути файл

@@ -19,6 +19,7 @@ class DatabaseSeeder extends Seeder
*/
public function run()
{
Stripe::setApiKey(env('STRIPE_SECRET'));
Service::create([
'name' => 'Unique Views with Engagements',
'type' => 'views',


+ 21
- 28
resources/js/panel/credits.vue Переглянути файл

@@ -19,29 +19,31 @@
<div id="credits-errors"></div>
</section>


<section id="payment-section">
<h4>Payment Method</h4>
<form id="payment-form" action="">

<label for="name">Name on Card</label>
<input id="billing-name" type="name">
<div id="card-element"></div>
<div id="card-errors"></div>
<div id=save-card>
<input name="save-card" value="Save card" type="checkbox">
<label for="">Save Card</label>
<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>

</form>
<payment-card :stripe="stripe" v-if="!selectSaved"></payment-card>

<div id="payment-error"></div>
</section>

<section class="credits-confirm">
<button @click="pay" :disabled="total == 0 || loading" class="brand-btn">Pay</button>
<button @click="pay" :disabled="total == 0 || loading || !cardValid || !billingName"
class="brand-btn">Buy<loading v-if="loading"></loading></button>
</section>
</template>

<script>
import Loading from '../icons/loading.vue'
import PaymentCard from './payment-card.vue'

function total() {
return this.packs.credits10*10.99 + this.packs.credits50*54.99
+ this.packs.credits100*109.99 + this.packs.credits1000*1010
@@ -49,6 +51,7 @@ function total() {

//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',
@@ -69,29 +72,17 @@ function getSecret() {
})
}

function mountPaymentForm() {
this.card = this.stripe.elements().create('card')
this.card.mount('#card-element')

this.card.on('change', function(event) {
let displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
}

//Gets key from the server then sends it with stripe
function pay() {
this.getSecret().then(secret => {
if (!secret) {return}
this.loading = true
return this.stripe.confirmCardPayment(secret, {
payment_method: {
card: this.card,
billing_details: {name:
document.getElementById('billing-name').value}
document.getElementById('billing-name').value},
setup_future_usage: document.querySelector('#save-card input') == 'on' ? 'off_session' : null
}
})
}).then(result => {
@@ -105,21 +96,23 @@ function pay() {
document.getElementById('payment-error').textContent =
'An unknown error occured'
}
this.loading = false
})
}

export default {
components:{Loading, PaymentCard},
data() {
return {packs: {credits10: 0, credits50: 0,
credits100: 0, credits1000: 0}, loading: false, stripe:
Stripe(process.env.VUE_APP_STRIPE_KEY), card:
null}
null, cardValid: false, billingName: null, selectSaved: true}
},
computed: {total},
methods: {getSecret, mountPaymentForm, pay},
methods: {getSecret, pay},
props: ['token'],
mounted() {
this.mountPaymentForm()
/* this.mountPaymentForm() */
}
}
</script>

+ 38
- 0
resources/js/panel/payment-card.vue Переглянути файл

@@ -0,0 +1,38 @@
<template>
<form id="payment-form" action="">
<label for="name">Name on Card</label>
<input v-model="billingName" id="billing-name" type="name">
<div id="card-element"></div>
<div id="card-errors"></div>
<div id=save-card>
<input name="save-card" type="checkbox" checked="true">
<label for="">Save Card</label>
</div>
</form>
</template>

<script>
function mountPaymentForm() {
this.card = this.stripe.elements().create('card')
this.card.mount('#card-element')

this.card.on('change', function(event) {
let displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
this.cardValid = true
}
}.bind(this));
}

export default {
data() {
return {billingName: null}
},
methods: {mountPaymentForm},
props: ['stripe'],
mounted: mountPaymentForm
}
</script>

+ 17
- 0
resources/js/panel/payment-slider.vue Переглянути файл

@@ -0,0 +1,17 @@
<template>
<div class="services-menu">
<a href="#new-order" :class="{selected: page == 'new-order'}">Services</a>
<a href="#credits" :class="{selected: page == 'credits'}">Credits</a>
<div :class="page" class="menu-slider"><div></div></div>
</div>
</template>

<script>
export default {
data() {
return {
items: null
}
}
}
</script>

+ 1
- 1
resources/js/panel/services.vue Переглянути файл

@@ -1,6 +1,6 @@
<template>
<div>
<div class="services-menu">
<div class="sliding-menu">
<a href="#new-order" :class="{selected: page == 'new-order'}">Services</a>
<a href="#credits" :class="{selected: page == 'credits'}">Credits</a>
<div :class="page" class="menu-slider"><div></div></div>


+ 11
- 2
resources/scss/main.scss Переглянути файл

@@ -995,7 +995,7 @@ main.panel {
}
}

.services-menu {
.sliding-menu {
display: flex;
justify-content: center;
flex-basis: 50%;
@@ -1026,7 +1026,10 @@ main.panel {
}

.menu-slider.credits div {
// margin-left: auto;
transform: translateX(100%);
}

.menu-slider.right div {
transform: translateX(100%);
}

@@ -1233,3 +1236,9 @@ div#card-errors {
}

}

.loading-overlay {
position: absolute;
width: 100%;
height: 100%;
}

Завантаження…
Відмінити
Зберегти