From b37ece7d83a28359b4450910bdc9940ff6482106 Mon Sep 17 00:00:00 2001
From: Immanuel Onyeka <immanuel@onyeka.ca>
Date: Wed, 2 Jun 2021 10:16:31 -0400
Subject: [PATCH] Add transaction page transitioning

---
 .../Controllers/TransactionController.php     |   9 ++
 .../2014_10_12_000000_create_users_table.php  |   2 +-
 resources/js/panel/credits.vue                |   3 +
 resources/js/panel/orders.vue                 |   2 +-
 resources/js/panel/panel.vue                  |   7 +-
 resources/js/panel/services.vue               | 100 +++++++++++++-----
 resources/js/panel/sidebar.vue                |   2 +-
 resources/scss/main.scss                      |  11 +-
 8 files changed, 100 insertions(+), 36 deletions(-)
 create mode 100644 resources/js/panel/credits.vue

diff --git a/app/Http/Controllers/TransactionController.php b/app/Http/Controllers/TransactionController.php
index 582e790..c66f950 100644
--- a/app/Http/Controllers/TransactionController.php
+++ b/app/Http/Controllers/TransactionController.php
@@ -12,13 +12,22 @@ class TransactionController extends Controller
 {
 	//THis should also reduce user's available credits
 	public function newOrder(Request $request) {
+		$user = Auth::user();
 		$order = new Order;
+
 		$order->service_id = $request->service;
 		$order->user_id = Auth::user()->id;
 		$order->quantity = $request->quantity;
 		$order->url = $request->url;
 		$order->note = $request->note ?: '';
 		$order->status = 'processing';
+
+		$cost = ceil($order->quantity*$order->service->price/1000);
+		$user->credits = $user->credits - $cost;
+		if ($cost > $user->credits) {
+			abort(520, 'Insufficient Credits');
+		}
+		$user->save();
 		$order->save();
 	}
 }
diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php
index 045d00e..a234e76 100644
--- a/database/migrations/2014_10_12_000000_create_users_table.php
+++ b/database/migrations/2014_10_12_000000_create_users_table.php
@@ -21,7 +21,7 @@ class CreateUsersTable extends Migration
             $table->string('password');
             $table->string('role');
             $table->boolean('active')->default(true);
-            $table->bigInteger('credits')->default(0);
+            $table->unsignedBigInteger('credits')->default(0);
             $table->rememberToken();
             $table->timestamps();
         });
diff --git a/resources/js/panel/credits.vue b/resources/js/panel/credits.vue
new file mode 100644
index 0000000..9ffb918
--- /dev/null
+++ b/resources/js/panel/credits.vue
@@ -0,0 +1,3 @@
+<template>
+hello
+</template>
diff --git a/resources/js/panel/orders.vue b/resources/js/panel/orders.vue
index f5ca992..a0f19b4 100644
--- a/resources/js/panel/orders.vue
+++ b/resources/js/panel/orders.vue
@@ -1,7 +1,7 @@
 <template>
 <div>
 	<section class="pending-pane">
-	<div class="actions"><a class="new-order" href="#orders/new-order">New</a><a class="new-order" href="#orders/new">Add credits</a></div>
+	<div class="actions"><a class="new-order" href="#new-order">New</a><a class="new-order" href="#credits">Add credits</a></div>
 	<h4>Pending Orders</h4>
 	<ul>
 		<template v-bind:key='order.id' v-for="order in orders">
diff --git a/resources/js/panel/panel.vue b/resources/js/panel/panel.vue
index d5aca62..e245103 100644
--- a/resources/js/panel/panel.vue
+++ b/resources/js/panel/panel.vue
@@ -28,8 +28,8 @@
 </div>
 <PastOrders :orders="orders" v-else-if="active === '#orders'" id="main">
 </PastOrders>
-<NewOrder :token="token" :credits="user.credits" v-else-if="active ===
-'#new-order'" id="main" @updateUser='getUser'>
+<NewOrder :token="token" :active="active" :credits="user.credits" v-else-if="active ===
+'#new-order' || active === '#credits'" id="main" @update-user='getUser' @update-orders='getOrders'>
 </NewOrder>
 <div id="main" v-else-if="active === '#exit'">
 	<section class="logout-pane">
@@ -48,9 +48,6 @@ import Settings from './settings.vue'
 import PastOrders from './orders.vue'
 import NewOrder from './services.vue'
 
-/* function getServices() { */
-	
-/* } */
 function getServices() {
 	return fetch("/panel/services", {
 		method: 'GET',
diff --git a/resources/js/panel/services.vue b/resources/js/panel/services.vue
index 18e4225..7bafb8b 100644
--- a/resources/js/panel/services.vue
+++ b/resources/js/panel/services.vue
@@ -1,28 +1,44 @@
 <template>
 <div>
 	<div class="services-menu">
-	<button class="selected">Services</button>
-	<button>Credits</button>
-	<div class="menu-slider"><div></div></div>
+	<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>
-	<h4 class="credits-display">Credits: {{credits}}</h4>
-	<div class="services-legend"><h5>Name</h5>
-<h5>Credits per 1000</h5><h5>Min Qt.</h5><h5>Max Qt.</h5></div>
-<ServicePane :site="'youtube'" :services="services" @select="select"></ServicePane>
-<ServicePane :site="'instagram'" :services="services" @select="select"></ServicePane>
-<ServicePane :site="'twitter'" :services="services" @select="select"></ServicePane>
-<ServicePane :site="'tiktok'" :services="services" @select="select"></ServicePane>
-<div id="overlay" v-if="selected">
+	<h4 class="credits-display">Credits: {{credits.toLocaleString('en')}}</h4>
+
+	<template v-if="page == 'new-order'">
+
+	<div class="services-legend">
+	<h5>Name</h5><h5>Credits per 1000</h5><h5>Min Qt.</h5><h5>Max Qt.</h5>
+	</div>
+
+	<ServicePane :site="'youtube'" :services="services"
+	@select="select"></ServicePane> <ServicePane :site="'instagram'"
+	:services="services" @select="select"></ServicePane> <ServicePane
+	:site="'twitter'" :services="services" @select="select"></ServicePane>
+	<ServicePane :site="'tiktok'" :services="services"
+	@select="select"></ServicePane>
+
+	<div id="overlay" v-if="selected">
+
 	<div v-if="!completed" class="overlay-item">
-	<img @click="completed = false; selected = null" class="cancel icon" src="../../images/cancel-icon2.svg" alt=""/>
-		<img v-if="selected.site == 'youtube'" class="icon" src="../../images/youtube-icon.svg" alt="">
-		<img v-if="selected.site == 'instagram'" class="icon" src="../../images/instagram-icon.svg" alt="">
-		<img v-if="selected.site == 'twitter'" class="icon" src="../../images/twitter.svg" alt="">
-		<img v-if="selected.site == 'tiktok'" class="icon" src="../../images/tik-tok.svg" alt="">
+	<img @click="completed = false; selected = null" class="cancel icon"
+	src="../../images/cancel-icon2.svg" alt=""/>
+		<img v-if="selected.site == 'youtube'" class="icon"
+		src="../../images/youtube-icon.svg" alt=""/>
+		<img v-if="selected.site == 'instagram'" class="icon"
+		src="../../images/instagram-icon.svg" alt=""/>
+		<img v-if="selected.site == 'twitter'" class="icon"
+		src="../../images/twitter.svg" alt=""/>
+		<img v-if="selected.site == 'tiktok'" class="icon"
+		src="../../images/tik-tok.svg" alt=""/>
 		<h3>{{selected.name}}</h3>
 		<h4>Cost: {{cost.toLocaleString('en')}}</h4>
 		<h4>Quantity</h4>
-		<div><input required :min="selected.minimum" :max="selected.maximum" type="number" v-model="amount" id="selQty"><span> / {{selected.maximum.toLocaleString('en')}}</span></div> 
+		<div><input required :min="selected.minimum" :max="selected.maximum"
+		type="number" v-model="amount" id="selQty"><span> /
+		{{selected.maximum.toLocaleString('en')}}</span></div> 
 		<template v-if="selected.modifier == 'location'">
 		<h4>Location</h4>
 		<div><select required id="country" name="">
@@ -31,24 +47,36 @@
 		<option value="uk">United Kingdom</option>
 		<option value="germany">Germany</option>
 		<option value="france">France</option>
-		</select></div> 
+		</select>
+		</div> 
 		</template>
 		<h4>URL</h4>
 		<div><input required type="url" id="url" v-model="url"></div> 
-		<button @click="buyService" :disabled="paying">Submit<loading v-if="paying"></loading></button>
+		<button @click="buyService" :disabled="paying">Submit<loading
+		v-if="paying"></loading></button>
 		<p id="overlay-error"></p>
+
 	</div>
+
 	<div class="overlay-item" v-else-if="completed">
-	<img @click="completed = false; selected = null" class="cancel icon" src="../../images/cancel-icon2.svg" alt=""/>
-	<img class="icon" src="../../images/checked2.svg" alt="">
+	<img @click="completed = false; selected = null" class="cancel icon"
+	src="../../images/cancel-icon2.svg" alt=""/>
+	<img class="icon" src="../../images/checked2.svg" alt=""/>
 	<h3>Success!</h3>
 	</div>
-</div>
+
+	</div>
+
+	</template>
+
+	<credits v-if="page == 'credits'"></credits>
+
 </div>
 </template>
 
 <script>
 import ServicePane from './service-pane.vue'
+import Credits from './credits.vue'
 import Loading from '../icons/loading.vue'
 
 function select(service) {
@@ -64,7 +92,12 @@ function buyService() {
 	if (!this.url) {
 		document.getElementById('overlay-error').textContent = "You must provide a URL."	
 		return
+	} else if (Math.ceil(this.cost > this.credits)) {
+		document.getElementById('overlay-error').textContent =
+		'Insuficient Credits'
+		return
 	}
+
 	this.paying = true
 	let note = ''
 	let country = document.getElementById('country')
@@ -85,23 +118,38 @@ function buyService() {
 					document.getElementById('overlay-error').textContent = `Success!`
 					this.completed = true
 					this.$emit('updateUser')
+					this.$emit('updateOrders')
+				} else if (response.status == 520) {
+					document.getElementById('overlay-error').textContent =
+					'Insuficient Credits'
 				} else {
 					document.getElementById('overlay-error').textContent = `Error
 					${response.status}: ${response.statusText}`
 				}
+
 				this.paying = false
 			}
 		)
 
 }
 
+function page() {
+	switch (this.active) {
+		case '#new-order':
+			return 'new-order'
+		case '#credits':
+			return 'credits'
+	}
+	console.log(this.active)
+}
+
 export default {
 	data() {
 		return {servicePane: true, services: null, selected: null, amount: 0,
 		paying: false, url: '', completed: false}
 	},
-	components: {ServicePane, Loading},
-	props: ['token', 'credits'],
+	components: {ServicePane, Loading, Credits},
+	props: ['token', 'credits', 'active'],
 	created() {
 		fetch("/panel/services", {
 			method: 'GET',
@@ -113,7 +161,7 @@ export default {
 		})
 	},
 	methods: {select, buyService},
-	computed: {cost},
-	emits: ['updateUser']
+	computed: {cost, page},
+	emits: ['updateUser', 'updateOrders']
 }
 </script>
diff --git a/resources/js/panel/sidebar.vue b/resources/js/panel/sidebar.vue
index 946e7e2..850537f 100644
--- a/resources/js/panel/sidebar.vue
+++ b/resources/js/panel/sidebar.vue
@@ -8,7 +8,7 @@
 <a :class="{selected: active == '#orders'}" href="/panel#orders">
 <svg fill="currentColor" enable-background="new 0 0 24 24" height="512" viewBox="0 0 24 24" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m16.12 1.929-10.891 5.576-4.329-2.13 10.699-5.283c.24-.122.528-.122.78 0z"/><path d="m23.088 5.375-11.082 5.49-4.15-2.045-.6-.305 10.903-5.575.6.304z"/><path d="m11.118 12.447-.012 11.553-10.614-5.539c-.3-.158-.492-.475-.492-.816v-10.688l4.498 2.216v3.896c0 .499.408.913.9.913s.9-.414.9-.913v-2.995l.6.292z"/><path d="m23.988 6.969-11.07 5.466-.012 11.553 11.094-5.793z"/></svg>
 </a>
-<a :class="{selected: active == '#new-order'}" href="/panel#new-order">
+<a :class="{selected: active == '#new-order' || active == '#credits'}" href="/panel#new-order">
 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12,2C6.486,2,2,6.486,2,12s4.486,10,10,10c5.514,0,10-4.486,10-10S17.514,2,12,2z M17,13h-4v4h-2v-4H7v-2h4V7h2v4h4V13z"></path></svg>
 </a>
 <a :class="{selected: active == '#settings'}" href="/panel#settings">
diff --git a/resources/scss/main.scss b/resources/scss/main.scss
index 322e844..b8277bd 100644
--- a/resources/scss/main.scss
+++ b/resources/scss/main.scss
@@ -1003,12 +1003,13 @@ main.panel {
 	margin-top: 1em;
 	flex-flow: wrap;
 	gap: 10px;
-	button {
+	a {
 		width: 25%;
 		font-size: 1.1rem;
 		background: none;
 		border: none;
 		color: grey;
+		text-align: center;
 	}
 	.selected {
 		color: black;
@@ -1018,12 +1019,18 @@ main.panel {
 .menu-slider {
 	width: 55%;
 	div {
-		// margin-left: auto;
+		transition: all 0.2s;
 		width: 50%;
 		border-bottom: 2px solid black;
+		flex: 2;
 	}
 }
 
+.menu-slider.credits div {
+	// margin-left: auto;
+	transform: translateX(100%);
+}
+
 .services-pane {
 	li {
 		display: flex;