Browse Source

Allow modifying and removing cards

tags/v0.1.0
Immanuel Onyeka 3 years ago
parent
commit
45a196de1f
9 changed files with 66 additions and 25 deletions
  1. +42
    -3
      app/Http/Controllers/BillingController.php
  2. +1
    -1
      database/migrations/2014_10_12_000000_create_users_table.php
  3. +2
    -2
      resources/js/panel/credits.vue
  4. +8
    -13
      resources/js/panel/edit-cards.vue
  5. +1
    -1
      resources/js/panel/panel.vue
  6. +2
    -2
      resources/js/panel/saved-cards.vue
  7. +2
    -2
      resources/js/panel/services.vue
  8. +1
    -1
      resources/js/panel/settings.vue
  9. +7
    -0
      routes/web.php

+ 42
- 3
app/Http/Controllers/BillingController.php View File

@@ -13,6 +13,16 @@ use App\Models\Transaction;


class BillingController extends Controller class BillingController extends Controller
{ {
protected $stripe;
protected $user;


public function __construct() {
$this->stripe = new \Stripe\StripeClient(env('STRIPE_SECRET'));
Stripe::setApiKey(env('STRIPE_SECRET'));
$this->user = Auth::user();
}

//Expects an array 'packs' representing the amount of each multiple of credits. //Expects an array 'packs' representing the amount of each multiple of credits.
//This controller should have a way of figuring out how much of each pack //This controller should have a way of figuring out how much of each pack
//was bought later. //was bought later.
@@ -20,6 +30,7 @@ class BillingController extends Controller
public function secret(Request $request) { public function secret(Request $request) {
Stripe::setApiKey(env('STRIPE_SECRET')); Stripe::setApiKey(env('STRIPE_SECRET'));


$user = Auth::user();
$amount = $request->packs[ 'credits10' ]*1099 + $amount = $request->packs[ 'credits10' ]*1099 +
$request->packs[ 'credits50' ]*5499 + $request->packs[ 'credits100' ]*10999 $request->packs[ 'credits50' ]*5499 + $request->packs[ 'credits100' ]*10999
+ $request->packs[ 'credits1000' ]*101000; + $request->packs[ 'credits1000' ]*101000;
@@ -34,7 +45,7 @@ class BillingController extends Controller
$request->packs['credits100']*10 + $request->packs['credits100']*10 +
$request->packs['credits1000']*150; $request->packs['credits1000']*150;


$transaction->user_id = Auth::user()->id; $transaction->user_id = $user->id;
$transaction->charge = $amount; $transaction->charge = $amount;
$transaction->status = 'processing'; $transaction->status = 'processing';
$transaction->completed = false; $transaction->completed = false;
@@ -43,13 +54,18 @@ class BillingController extends Controller
$intent = PaymentIntent::create([ $intent = PaymentIntent::create([
'amount' => $amount, 'amount' => $amount,
'currency' => 'usd', 'currency' => 'usd',
'customer' => Auth::user()->customer_id, 'customer' => $user->customer_id,
'description' => "You have received $total_credits credits.", 'description' => "You have received $total_credits credits.",
'receipt_email' => Auth::user()->email, 'receipt_email' => Auth::user()->email,
'metadata' => ['transaction_id' => $transaction->id] 'metadata' => ['transaction_id' => $transaction->id]
]); ]);
$transaction->intent_id = $intent->id; $transaction->intent_id = $intent->id;


//Save the card as a default if none is set and it was selected
if ($user->payment_method == null && $request->card) {
$this->changeDefaultCard($request->card);
}

$transaction->save(); $transaction->save();
return $intent->client_secret; return $intent->client_secret;
} }
@@ -71,7 +87,6 @@ class BillingController extends Controller
$user = $transaction->user; $user = $transaction->user;


if ($event->type == 'charge.succeeded') { if ($event->type == 'charge.succeeded') {
Log::debug($charge->metadata['transaction_id']);
$user->credits = $user->credits + $transaction->credits + $transaction->credits_extra; $user->credits = $user->credits + $transaction->credits + $transaction->credits_extra;
$transaction->status = 'completed'; $transaction->status = 'completed';
$transaction->completed = true; $transaction->completed = true;
@@ -83,4 +98,28 @@ class BillingController extends Controller
$transaction->save(); $transaction->save();
} }
} }

public function changeDefaultCard(String $card) {
$user = Auth::user();
$user->payment_method = $card;
$user->save();
$cards = $this->getCards();
Log::debug($this->user->customer_id);

return PaymentMethod::all([
'customer' => Auth::user()->customer_id,
'type' => 'card'
]);
}

public function deleteCard(Request $request) {
$this->stripe->paymentMethods->detach($request->card);

$user = Auth::user();
if ($request->card == $user->payment_method) {
$user->payment_method = null;
$user->save();
}
return ($this->getCards());
}
} }

+ 1
- 1
database/migrations/2014_10_12_000000_create_users_table.php View File

@@ -21,7 +21,7 @@ class CreateUsersTable extends Migration
$table->timestamp('email_verified_at')->nullable(); $table->timestamp('email_verified_at')->nullable();
$table->string('password'); $table->string('password');
$table->enum('role', ['client', 'guest', 'admin']); $table->enum('role', ['client', 'guest', 'admin']);
$table->string('payment_method'); $table->string('payment_method')->default('');
$table->boolean('active')->default(true); $table->boolean('active')->default(true);
$table->unsignedBigInteger('credits')->default(0); $table->unsignedBigInteger('credits')->default(0);
$table->rememberToken(); $table->rememberToken();


+ 2
- 2
resources/js/panel/credits.vue View File

@@ -28,7 +28,7 @@
<div :class="{right: !selectSaved}" class="menu-slider"><div></div></div> <div :class="{right: !selectSaved}" class="menu-slider"><div></div></div>
</div> </div>


<saved-cards v-model:picked-card="picked" :cards="cards" <saved-cards :preferred="preferred" v-model:picked-card="picked" :cards="cards"
:token="token" v-if="selectSaved"></saved-cards> :token="token" v-if="selectSaved"></saved-cards>


<payment-card @set-card="(c) => {card = c}" @card-valid="(val) => {cardValid = val}" <payment-card @set-card="(c) => {card = c}" @card-valid="(val) => {cardValid = val}"
@@ -148,7 +148,7 @@ export default {
}, },
computed: {total, ready}, computed: {total, ready},
methods: {getSecret, pay, getCards}, methods: {getSecret, pay, getCards},
props: ['token'], props: ['preferred', 'token'],
emits: ['purchaseComplete'], emits: ['purchaseComplete'],
created() { created() {
this.getCards() this.getCards()


+ 8
- 13
resources/js/panel/edit-cards.vue View File

@@ -6,7 +6,7 @@
<div v-for="(card, index) in cards" :key="card.id" class="saved-card"> <div v-for="(card, index) in cards" :key="card.id" class="saved-card">
<span>{{card.card.brand[0].toUpperCase() + card.card.brand.substring(1)}} <span>{{card.card.brand[0].toUpperCase() + card.card.brand.substring(1)}}
(••••{{card.card.last4}})</span> (••••{{card.card.last4}})</span>
<span><input :checked="index === 0" :value="card.id" name="selected-card" type="radio" <span><input :checked="card.id == preferred" :value="card.id" name="selected-card" type="radio"
@change="change(card.id)"></span> @change="change(card.id)"></span>
<span><img @click="remove(card.id)" src="../../images/close-icon-black.svg"/></span> <span><img @click="remove(card.id)" src="../../images/close-icon-black.svg"/></span>
</div> </div>
@@ -35,22 +35,22 @@ function change(card) {
body: JSON.stringify({'card': card}) body: JSON.stringify({'card': card})
}).then((response) => { }).then((response) => {
if (response.ok) { if (response.ok) {
console.log('ok')
response.json().then((data) => { response.json().then((data) => {
this.cards = data this.cards = data.data
}) })
} else { } else {
console.log('bad') console.log('bad')
document.getElementById("billing-error").textContent = document.getElementById("billing-error").textContent =
`${response.status}: ${response.statusText}` `${response.status}: ${response.statusText}`
} }
response.json().then(data => {
console.log(data)}
)
}) })
} }


function remove(card) { function remove(card) {
if (card.length == 1) {
return
}

fetch('/panel/delete-card', { fetch('/panel/delete-card', {
method: 'POST', method: 'POST',
headers: {'Content-Type': 'application/json', headers: {'Content-Type': 'application/json',
@@ -59,18 +59,13 @@ function remove(card) {
body: JSON.stringify({'card': card}) body: JSON.stringify({'card': card})
}).then((response) => { }).then((response) => {
if (response.ok) { if (response.ok) {
console.log('ok')
response.json().then((data) => { response.json().then((data) => {
this.cards = data this.cards = data.data
}) })
} else { } else {
console.log('bad')
document.getElementById("billing-error").textContent = document.getElementById("billing-error").textContent =
`${response.status}: ${response.statusText}` `${response.status}: ${response.statusText}`
} }
response.json().then(data => {
console.log(data)}
)
}) })
} }


@@ -82,6 +77,6 @@ export default {
created() { created() {
this.get() this.get()
}, },
props: ['token',], props: ['token', 'preferred'],
} }
</script> </script>

+ 1
- 1
resources/js/panel/panel.vue View File

@@ -28,7 +28,7 @@
</div> </div>
<PastOrders :orders="orders" v-else-if="active === '#orders'" id="main"> <PastOrders :orders="orders" v-else-if="active === '#orders'" id="main">
</PastOrders> </PastOrders>
<NewOrder :token="token" :active="active" :credits="user.credits" v-else-if="active === <NewOrder :preferred="user.payment_method" :token="token" :active="active" :credits="user.credits" v-else-if="active ===
'#new-order' || active === '#credits'" id="main" @update-user='getUser' @update-orders='getOrders'> '#new-order' || active === '#credits'" id="main" @update-user='getUser' @update-orders='getOrders'>
</NewOrder> </NewOrder>
<div id="main" v-else-if="active === '#exit'"> <div id="main" v-else-if="active === '#exit'">


+ 2
- 2
resources/js/panel/saved-cards.vue View File

@@ -3,7 +3,7 @@
<div v-for="(card, index) in cards" :key="card.id" class="saved-card"> <div v-for="(card, index) in cards" :key="card.id" class="saved-card">
<span>{{card.card.brand[0].toUpperCase() + card.card.brand.substring(1)}} <span>{{card.card.brand[0].toUpperCase() + card.card.brand.substring(1)}}
(••••{{card.card.last4}})</span> (••••{{card.card.last4}})</span>
<input :checked="index === 0" :value="card.id" name="selected-card" type="radio" <input :checked="index === 0 || card.id == preferred" :value="card.id" name="selected-card" type="radio"
@change="$emit('update:pickedCard', card.id)"> @change="$emit('update:pickedCard', card.id)">
</div> </div>
</div> </div>
@@ -22,7 +22,7 @@
unmounted() { unmounted() {
this.$emit('update:pickedCard', null) this.$emit('update:pickedCard', null)
}, },
props: ['token', 'cards'], props: ['token', 'cards', 'preferred'],
emits: ['update:pickedCard'] emits: ['update:pickedCard']
} }
</script> </script>

+ 2
- 2
resources/js/panel/services.vue View File

@@ -81,7 +81,7 @@


</template> </template>


<credits @purchase-complete="$emit('updateUser')" :token="token" v-if="page == 'credits'"></credits> <credits @purchase-complete="$emit('updateUser')" :preferred="preferred" :token="token" v-if="page == 'credits'"></credits>


</div> </div>
</template> </template>
@@ -163,7 +163,7 @@ export default {
paying: false, url: '', completed: false} paying: false, url: '', completed: false}
}, },
components: {ServicePane, Loading, Credits}, components: {ServicePane, Loading, Credits},
props: ['token', 'credits', 'active'], props: ['token', 'credits', 'active', 'preferred'],
created() { created() {
fetch("/panel/services", { fetch("/panel/services", {
method: 'GET', method: 'GET',


+ 1
- 1
resources/js/panel/settings.vue View File

@@ -3,7 +3,7 @@
<h3>Settings</h3> <h3>Settings</h3>
<section class="billing-pane"> <section class="billing-pane">
<h4>Billing</h4> <h4>Billing</h4>
<edit-cards :token="token"></edit-cards> <edit-cards :preferred="user.payment_method" :token="token"></edit-cards>
</section> </section>
<section class="change-name-pane"> <section class="change-name-pane">
<h4>Name</h4> <h4>Name</h4>


+ 7
- 0
routes/web.php View File

@@ -63,6 +63,13 @@ Route::get('/panel/user', function (Request $request) {
return $request->user(); return $request->user();
})->middleware([ 'auth', 'verified' ]); })->middleware([ 'auth', 'verified' ]);


Route::post('/panel/change-card', function (Request $request) {
return App::make(BillingController::class)->changeDefaultCard($request->card);
})->middleware([ 'auth', 'verified' ]);

Route::post('/panel/delete-card', [BillingController::class,
'deleteCard'])->middleware([ 'auth', 'verified' ]);

Route::get('/panel/orders', [UserController::class, Route::get('/panel/orders', [UserController::class,
'getOrders'])->middleware([ 'auth', 'verified' ]); 'getOrders'])->middleware([ 'auth', 'verified' ]);




||||||
x
 
000:0
Loading…
Cancel
Save