@@ -1,10 +0,0 @@ | |||||
<?php | |||||
namespace App\Http\Controllers; | |||||
use Illuminate\Http\Request; | |||||
class Transaction extends Controller | |||||
{ | |||||
// | |||||
} |
@@ -0,0 +1,24 @@ | |||||
<?php | |||||
namespace App\Http\Controllers; | |||||
use Illuminate\Http\Request; | |||||
use App\Models\Order; | |||||
use App\Models\Service; | |||||
use Illuminate\Support\Facades\Auth; | |||||
use Illuminate\Support\Facades\Log; | |||||
class TransactionController extends Controller | |||||
{ | |||||
//THis should also reduce user's available credits | |||||
public function newOrder(Request $request) { | |||||
$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'; | |||||
$order->save(); | |||||
} | |||||
} |
@@ -87,7 +87,7 @@ class UserController extends Controller | |||||
public function getOrders(Request $request) { | public function getOrders(Request $request) { | ||||
/* Log::debug(Auth::user()->orders()->service_name); */ | /* Log::debug(Auth::user()->orders()->service_name); */ | ||||
return Auth::user()->orders()->with('service')->withCasts(['updated_at' | return Auth::user()->orders()->with('service')->withCasts(['updated_at' | ||||
=> 'datetime:d-m-Y'])->get(); | |||||
=> 'datetime:d-m-Y'])->latest()->get(); | |||||
} | } | ||||
public function changeName(Request $request) { | public function changeName(Request $request) { | ||||
@@ -20,6 +20,8 @@ class CreateServicesTable extends Migration | |||||
$table->string('name'); | $table->string('name'); | ||||
$table->string('type')->nullable(); | $table->string('type')->nullable(); | ||||
$table->string('site'); | $table->string('site'); | ||||
$table->string('supplier')->nullable(); | |||||
$table->string('supplier_link')->nullable(); | |||||
$table->string('modifier')->default(''); | $table->string('modifier')->default(''); | ||||
$table->integer('maximum'); | $table->integer('maximum'); | ||||
$table->integer('minimum'); | $table->integer('minimum'); | ||||
@@ -28,7 +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" v-else-if="active === '#new-order'" id="main"> | |||||
<NewOrder :token="token" :credits="user.credits" v-else-if="active === | |||||
'#new-order'" id="main" @updateUser='updateUser'> | |||||
</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"> | ||||
@@ -61,15 +62,28 @@ import NewOrder from './services.vue' | |||||
/* }) */ | /* }) */ | ||||
/* } */ | /* } */ | ||||
function updateUser() { | |||||
fetch("/panel/user", { | |||||
method: 'GET', | |||||
headers: {'Content-Type': 'application/json', | |||||
'Accept': 'application/json', | |||||
'X-XSRF-TOKEN': this.token}, | |||||
}).then(response => { | |||||
return response.json() | |||||
}).then(data => { | |||||
this.user = data | |||||
}) | |||||
} | |||||
export default { | export default { | ||||
components: { | components: { | ||||
Sidebar, Settings, PastOrders, NewOrder | Sidebar, Settings, PastOrders, NewOrder | ||||
}, | }, | ||||
data() { | data() { | ||||
return {active: window.location.hash, user: '', | |||||
token: '', orders: '', loading: true} | |||||
return {active: window.location.hash, user: null, | |||||
token: null, orders: null, loading: true} | |||||
}, | }, | ||||
methods: {}, | |||||
methods: {updateUser}, | |||||
created() { | created() { | ||||
fetch("/panel/services", { | fetch("/panel/services", { | ||||
method: 'GET', | method: 'GET', | ||||
@@ -78,7 +92,15 @@ export default { | |||||
'X-XSRF-TOKEN': this.token} | 'X-XSRF-TOKEN': this.token} | ||||
}).then(response => { | }).then(response => { | ||||
response.json().then(data => {this.services = data; this.loading = false}) | response.json().then(data => {this.services = data; this.loading = false}) | ||||
}) | |||||
}).then( | |||||
fetch("/panel/services", { | |||||
method: 'GET', | |||||
headers: {'Content-Type': 'application/json', | |||||
'Accept': 'application/json', | |||||
'X-XSRF-TOKEN': this.token} | |||||
}).then(response => { | |||||
response.json().then(data => {this.services = data; this.loading = false}) | |||||
})) | |||||
} | } | ||||
} | } | ||||
</script> | </script> |
@@ -3,9 +3,9 @@ | |||||
<div class="services-menu"> | <div class="services-menu"> | ||||
<button class="selected">Services</button> | <button class="selected">Services</button> | ||||
<button>Credits</button> | <button>Credits</button> | ||||
<div class="menu-slider"> | |||||
<div></div></div> | |||||
<div class="menu-slider"><div></div></div> | |||||
</div> | </div> | ||||
<h4 class="credits-display">Credits: {{credits}}</h4> | |||||
<div class="services-legend"><h5>Name</h5> | <div class="services-legend"><h5>Name</h5> | ||||
<h5>Credits per 1000</h5><h5>Min Qt.</h5><h5>Max Qt.</h5></div> | <h5>Credits per 1000</h5><h5>Min Qt.</h5><h5>Max Qt.</h5></div> | ||||
<ServicePane :site="'youtube'" :services="services" @select="select"></ServicePane> | <ServicePane :site="'youtube'" :services="services" @select="select"></ServicePane> | ||||
@@ -13,8 +13,8 @@ | |||||
<ServicePane :site="'twitter'" :services="services" @select="select"></ServicePane> | <ServicePane :site="'twitter'" :services="services" @select="select"></ServicePane> | ||||
<ServicePane :site="'tiktok'" :services="services" @select="select"></ServicePane> | <ServicePane :site="'tiktok'" :services="services" @select="select"></ServicePane> | ||||
<div id="overlay" v-if="selected"> | <div id="overlay" v-if="selected"> | ||||
<div class="overlay-item"> | |||||
<img @click="selected = null" class="cancel icon" src="../../images/cancel-icon2.svg" alt=""/> | |||||
<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 == '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 == '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 == 'twitter'" class="icon" src="../../images/twitter.svg" alt=""> | ||||
@@ -34,9 +34,14 @@ | |||||
</select></div> | </select></div> | ||||
</template> | </template> | ||||
<h4>URL</h4> | <h4>URL</h4> | ||||
<div><input required type="url" id="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></p> | |||||
<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=""> | |||||
<h3>Success!</h3> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -47,6 +52,7 @@ import ServicePane from './service-pane.vue' | |||||
import Loading from '../icons/loading.vue' | import Loading from '../icons/loading.vue' | ||||
function select(service) { | function select(service) { | ||||
this.completed = false | |||||
this.selected = service | this.selected = service | ||||
} | } | ||||
@@ -55,17 +61,47 @@ function cost() { | |||||
} | } | ||||
function buyService() { | function buyService() { | ||||
if (!this.url) { | |||||
document.getElementById('overlay-error').textContent = "You must provide a URL." | |||||
return | |||||
} | |||||
this.paying = true | this.paying = true | ||||
return | |||||
let note = '' | |||||
let country = document.getElementById('country') | |||||
if (country) { | |||||
note = JSON.stringify({'location': country.value}) | |||||
} | |||||
fetch('/panel/orders', { | |||||
method: 'POST', | |||||
headers: {'Content-Type': 'application/json', | |||||
'Accept': 'application/json', | |||||
'X-XSRF-TOKEN': this.token}, | |||||
body: JSON.stringify({'service': this.selected.id, | |||||
'quantity': this.amount, 'url': this.url, 'note': note}), }).then( | |||||
response => { | |||||
if (response.ok) { | |||||
document.getElementById('overlay-error').textContent = `Success!` | |||||
this.completed = true | |||||
this.$emit('updateUser') | |||||
} else { | |||||
document.getElementById('overlay-error').textContent = `Error | |||||
${response.status}: ${response.statusText}` | |||||
} | |||||
this.paying = false | |||||
} | |||||
) | |||||
} | } | ||||
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 } | |||||
paying: false, url: '', completed: false} | |||||
}, | }, | ||||
components: {ServicePane, Loading}, | components: {ServicePane, Loading}, | ||||
props: ['token'], | |||||
props: ['token', 'credits'], | |||||
created() { | created() { | ||||
fetch("/panel/services", { | fetch("/panel/services", { | ||||
method: 'GET', | method: 'GET', | ||||
@@ -77,6 +113,7 @@ export default { | |||||
}) | }) | ||||
}, | }, | ||||
methods: {select, buyService}, | methods: {select, buyService}, | ||||
computed: {cost} | |||||
computed: {cost}, | |||||
emits: ['updateUser'] | |||||
} | } | ||||
</script> | </script> |
@@ -16,7 +16,7 @@ | |||||
<section class="change-password-pane"> | <section class="change-password-pane"> | ||||
<h4>Change Password</h4> | <h4>Change Password</h4> | ||||
<h5>Current Password</h5><input name="current_passowrd" id="current_password" type="password"> | <h5>Current Password</h5><input name="current_passowrd" id="current_password" type="password"> | ||||
<h5>New Password</h5><input id="new_password" name="passowrd" type="password"> | |||||
<h5>New Password</h5><input id="new_password" name="password" type="password"> | |||||
<h5>Confirm Password</h5><input id="confirm_password" name="confirm_passowrd" type="password"> | <h5>Confirm Password</h5><input id="confirm_password" name="confirm_passowrd" type="password"> | ||||
<button @click="changePassword">Save<img class="loading-icon" src="../../images/loading-white.svg" alt=""></button> | <button @click="changePassword">Save<img class="loading-icon" src="../../images/loading-white.svg" alt=""></button> | ||||
<span></span> | <span></span> | ||||
@@ -1132,9 +1132,20 @@ main.panel { | |||||
width: 100%; | width: 100%; | ||||
} | } | ||||
p { | |||||
margin-top: 2em; | |||||
text-align: center; | |||||
} | |||||
} | } | ||||
button .loading-icon { | button .loading-icon { | ||||
display: inline; | display: inline; | ||||
height: 1.5em; | height: 1.5em; | ||||
} | } | ||||
#panel #main .credits-display { | |||||
text-align: center; | |||||
margin: 1em; | |||||
color: vars.getColor('brand-orange'); | |||||
} |
@@ -3,6 +3,7 @@ | |||||
use Illuminate\Support\Facades\Route; | use Illuminate\Support\Facades\Route; | ||||
use App\Http\Controllers\UserController; | use App\Http\Controllers\UserController; | ||||
use App\Http\Controllers\ServiceController; | use App\Http\Controllers\ServiceController; | ||||
use App\Http\Controllers\TransactionController; | |||||
use Illuminate\Foundation\Auth\EmailVerificationRequest; | use Illuminate\Foundation\Auth\EmailVerificationRequest; | ||||
use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||
use Illuminate\Support\Facades\Auth; | use Illuminate\Support\Facades\Auth; | ||||
@@ -81,3 +82,7 @@ Route::post('/panel/change-password', [UserController::class, | |||||
Route::get('/reset-email', [UserController::class, | Route::get('/reset-email', [UserController::class, | ||||
'resetEmail'])->name('reset-email'); | 'resetEmail'])->name('reset-email'); | ||||
Route::post('/panel/orders', [TransactionController::class, | |||||
'newOrder'])->middleware([ 'auth', 'verified' ]); | |||||