Browse Source

Add transaction page transitioning

tags/v0.1.0
Immanuel Onyeka 3 years ago
parent
commit
b37ece7d83
8 changed files with 100 additions and 36 deletions
  1. +9
    -0
      app/Http/Controllers/TransactionController.php
  2. +1
    -1
      database/migrations/2014_10_12_000000_create_users_table.php
  3. +3
    -0
      resources/js/panel/credits.vue
  4. +1
    -1
      resources/js/panel/orders.vue
  5. +2
    -5
      resources/js/panel/panel.vue
  6. +74
    -26
      resources/js/panel/services.vue
  7. +1
    -1
      resources/js/panel/sidebar.vue
  8. +9
    -2
      resources/scss/main.scss

+ 9
- 0
app/Http/Controllers/TransactionController.php View File

@@ -12,13 +12,22 @@ class TransactionController extends Controller
{ {
//THis should also reduce user's available credits //THis should also reduce user's available credits
public function newOrder(Request $request) { public function newOrder(Request $request) {
$user = Auth::user();
$order = new Order; $order = new Order;

$order->service_id = $request->service; $order->service_id = $request->service;
$order->user_id = Auth::user()->id; $order->user_id = Auth::user()->id;
$order->quantity = $request->quantity; $order->quantity = $request->quantity;
$order->url = $request->url; $order->url = $request->url;
$order->note = $request->note ?: ''; $order->note = $request->note ?: '';
$order->status = 'processing'; $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(); $order->save();
} }
} }

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

@@ -21,7 +21,7 @@ class CreateUsersTable extends Migration
$table->string('password'); $table->string('password');
$table->string('role'); $table->string('role');
$table->boolean('active')->default(true); $table->boolean('active')->default(true);
$table->bigInteger('credits')->default(0);
$table->unsignedBigInteger('credits')->default(0);
$table->rememberToken(); $table->rememberToken();
$table->timestamps(); $table->timestamps();
}); });


+ 3
- 0
resources/js/panel/credits.vue View File

@@ -0,0 +1,3 @@
<template>
hello
</template>

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

@@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<section class="pending-pane"> <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> <h4>Pending Orders</h4>
<ul> <ul>
<template v-bind:key='order.id' v-for="order in orders"> <template v-bind:key='order.id' v-for="order in orders">


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

@@ -28,8 +28,8 @@
</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" :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> </NewOrder>
<div id="main" v-else-if="active === '#exit'"> <div id="main" v-else-if="active === '#exit'">
<section class="logout-pane"> <section class="logout-pane">
@@ -48,9 +48,6 @@ import Settings from './settings.vue'
import PastOrders from './orders.vue' import PastOrders from './orders.vue'
import NewOrder from './services.vue' import NewOrder from './services.vue'


/* function getServices() { */
/* } */
function getServices() { function getServices() {
return fetch("/panel/services", { return fetch("/panel/services", {
method: 'GET', method: 'GET',


+ 74
- 26
resources/js/panel/services.vue View File

@@ -1,28 +1,44 @@
<template> <template>
<div> <div>
<div class="services-menu"> <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> </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"> <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> <h3>{{selected.name}}</h3>
<h4>Cost: {{cost.toLocaleString('en')}}</h4> <h4>Cost: {{cost.toLocaleString('en')}}</h4>
<h4>Quantity</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'"> <template v-if="selected.modifier == 'location'">
<h4>Location</h4> <h4>Location</h4>
<div><select required id="country" name=""> <div><select required id="country" name="">
@@ -31,24 +47,36 @@
<option value="uk">United Kingdom</option> <option value="uk">United Kingdom</option>
<option value="germany">Germany</option> <option value="germany">Germany</option>
<option value="france">France</option> <option value="france">France</option>
</select></div>
</select>
</div>
</template> </template>
<h4>URL</h4> <h4>URL</h4>
<div><input required type="url" id="url" v-model="url"></div> <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> <p id="overlay-error"></p>

</div> </div>

<div class="overlay-item" v-else-if="completed"> <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> <h3>Success!</h3>
</div> </div>
</div>

</div>

</template>

<credits v-if="page == 'credits'"></credits>

</div> </div>
</template> </template>


<script> <script>
import ServicePane from './service-pane.vue' import ServicePane from './service-pane.vue'
import Credits from './credits.vue'
import Loading from '../icons/loading.vue' import Loading from '../icons/loading.vue'


function select(service) { function select(service) {
@@ -64,7 +92,12 @@ function buyService() {
if (!this.url) { if (!this.url) {
document.getElementById('overlay-error').textContent = "You must provide a URL." document.getElementById('overlay-error').textContent = "You must provide a URL."
return return
} else if (Math.ceil(this.cost > this.credits)) {
document.getElementById('overlay-error').textContent =
'Insuficient Credits'
return
} }

this.paying = true this.paying = true
let note = '' let note = ''
let country = document.getElementById('country') let country = document.getElementById('country')
@@ -85,23 +118,38 @@ function buyService() {
document.getElementById('overlay-error').textContent = `Success!` document.getElementById('overlay-error').textContent = `Success!`
this.completed = true this.completed = true
this.$emit('updateUser') this.$emit('updateUser')
this.$emit('updateOrders')
} else if (response.status == 520) {
document.getElementById('overlay-error').textContent =
'Insuficient Credits'
} else { } else {
document.getElementById('overlay-error').textContent = `Error document.getElementById('overlay-error').textContent = `Error
${response.status}: ${response.statusText}` ${response.status}: ${response.statusText}`
} }

this.paying = false this.paying = false
} }
) )


} }


function page() {
switch (this.active) {
case '#new-order':
return 'new-order'
case '#credits':
return 'credits'
}
console.log(this.active)
}

export default { export default {
data() { data() {
return {servicePane: true, services: null, selected: null, amount: 0, return {servicePane: true, services: null, selected: null, amount: 0,
paying: false, url: '', completed: false} paying: false, url: '', completed: false}
}, },
components: {ServicePane, Loading},
props: ['token', 'credits'],
components: {ServicePane, Loading, Credits},
props: ['token', 'credits', 'active'],
created() { created() {
fetch("/panel/services", { fetch("/panel/services", {
method: 'GET', method: 'GET',
@@ -113,7 +161,7 @@ export default {
}) })
}, },
methods: {select, buyService}, methods: {select, buyService},
computed: {cost},
emits: ['updateUser']
computed: {cost, page},
emits: ['updateUser', 'updateOrders']
} }
</script> </script>

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

@@ -8,7 +8,7 @@
<a :class="{selected: active == '#orders'}" href="/panel#orders"> <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> <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>
<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> <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>
<a :class="{selected: active == '#settings'}" href="/panel#settings"> <a :class="{selected: active == '#settings'}" href="/panel#settings">


+ 9
- 2
resources/scss/main.scss View File

@@ -1003,12 +1003,13 @@ main.panel {
margin-top: 1em; margin-top: 1em;
flex-flow: wrap; flex-flow: wrap;
gap: 10px; gap: 10px;
button {
a {
width: 25%; width: 25%;
font-size: 1.1rem; font-size: 1.1rem;
background: none; background: none;
border: none; border: none;
color: grey; color: grey;
text-align: center;
} }
.selected { .selected {
color: black; color: black;
@@ -1018,12 +1019,18 @@ main.panel {
.menu-slider { .menu-slider {
width: 55%; width: 55%;
div { div {
// margin-left: auto;
transition: all 0.2s;
width: 50%; width: 50%;
border-bottom: 2px solid black; border-bottom: 2px solid black;
flex: 2;
} }
} }


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

.services-pane { .services-pane {
li { li {
display: flex; display: flex;


Loading…
Cancel
Save