@@ -4,6 +4,8 @@ namespace App\Http\Controllers; | |||||
use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||
use App\Models\User; | use App\Models\User; | ||||
use App\Models\Order; | |||||
use App\Models\Service; | |||||
use Illuminate\Support\Facades\Log; | use Illuminate\Support\Facades\Log; | ||||
use Illuminate\Support\Facades\Hash; | use Illuminate\Support\Facades\Hash; | ||||
use Illuminate\Auth\Events\Registered; | use Illuminate\Auth\Events\Registered; | ||||
@@ -79,7 +81,12 @@ class UserController extends Controller | |||||
return redirect('/'); | return redirect('/'); | ||||
} | } | ||||
//It should have an orderBy clause to make sure the most recent are first | |||||
//This should limit non pending orders to 50. Should also return a json of all services | |||||
public function getOrders(Request $request) { | public function getOrders(Request $request) { | ||||
/* Log::debug(Auth::user()->orders()->service_name); */ | |||||
return Auth::user()->orders()->with('service')->withCasts(['updated_at' | |||||
=> 'datetime:d-m-Y'])->get(); | |||||
} | } | ||||
@@ -12,7 +12,7 @@ class Order extends Model | |||||
use HasFactory; | use HasFactory; | ||||
protected $fillable = [ | protected $fillable = [ | ||||
'quantity' | |||||
'quantity', 'url' | |||||
]; | ]; | ||||
public function service() { | public function service() { | ||||
@@ -22,4 +22,9 @@ class Order extends Model | |||||
public function user() { | public function user() { | ||||
return $this->belongsTo(User::class); | return $this->belongsTo(User::class); | ||||
} | } | ||||
public function getServiceNameAttribute() { | |||||
return $this->service()->name(); | |||||
} | |||||
} | } |
@@ -24,8 +24,13 @@ class OrderFactory extends Factory | |||||
*/ | */ | ||||
public function definition() | public function definition() | ||||
{ | { | ||||
$quantity = $this->faker->numberBetween(100, 10000); | |||||
return [ | return [ | ||||
'quantity' => $this->faker->randomNumber(4, false), | |||||
'quantity' => $quantity, | |||||
'status' => $this->faker->randomElement(['pending', 'completed', | |||||
'canceled', 'processing']), | |||||
'remaining' => $this->faker->numberBetween(0, $quantity), | |||||
'url' => $this->faker->url, | |||||
'service_id' => function() { | 'service_id' => function() { | ||||
return Service::inRandomOrder()->first()->id; | return Service::inRandomOrder()->first()->id; | ||||
}, | }, | ||||
@@ -25,6 +25,7 @@ class UserFactory extends Factory | |||||
return [ | return [ | ||||
'name' => $this->faker->name, | 'name' => $this->faker->name, | ||||
'email' => $this->faker->unique()->safeEmail, | 'email' => $this->faker->unique()->safeEmail, | ||||
'url' => $this->faker->unique()->safeEmail, | |||||
'email_verified_at' => now(), | 'email_verified_at' => now(), | ||||
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password | ||||
'remember_token' => Str::random(10), | 'remember_token' => Str::random(10), | ||||
@@ -20,6 +20,7 @@ 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('description')->default(''); | |||||
$table->boolean('available'); | $table->boolean('available'); | ||||
}); | }); | ||||
@@ -19,6 +19,10 @@ class CreateOrdersTable extends Migration | |||||
$table->foreignId('service_id')->constrained(); | $table->foreignId('service_id')->constrained(); | ||||
$table->foreignId('user_id')->constrained(); | $table->foreignId('user_id')->constrained(); | ||||
$table->bigInteger('quantity'); | $table->bigInteger('quantity'); | ||||
$table->string('note')->default(''); | |||||
$table->bigInteger('remaining')->default(0); | |||||
$table->string('status'); | |||||
$table->string('url'); | |||||
}); | }); | ||||
} | } | ||||
@@ -18,37 +18,37 @@ class DatabaseSeeder extends Seeder | |||||
public function run() | public function run() | ||||
{ | { | ||||
Service::create([ | Service::create([ | ||||
'name' => 'youtube_views', | |||||
'name' => 'Youtube Views', | |||||
'type' => 'views', | 'type' => 'views', | ||||
'site' => 'youtube', | 'site' => 'youtube', | ||||
'available' => true, | 'available' => true, | ||||
]); | ]); | ||||
Service::create([ | Service::create([ | ||||
'name' => 'instagram_views', | |||||
'name' => 'Instagram Views', | |||||
'type' => 'views', | 'type' => 'views', | ||||
'site' => 'instagram', | 'site' => 'instagram', | ||||
'available' => true, | 'available' => true, | ||||
]); | ]); | ||||
Service::create([ | Service::create([ | ||||
'name' => 'spotify_plays', | |||||
'name' => 'Spotify Views', | |||||
'type' => 'plays', | 'type' => 'plays', | ||||
'site' => 'spotify', | 'site' => 'spotify', | ||||
'available' => true, | 'available' => true, | ||||
]); | ]); | ||||
Service::create([ | Service::create([ | ||||
'name' => 'twitter_likes', | |||||
'name' => 'Twitter Likes', | |||||
'type' => 'likes', | 'type' => 'likes', | ||||
'site' => 'spotify', | 'site' => 'spotify', | ||||
'available' => false, | 'available' => false, | ||||
]); | ]); | ||||
$test_user = User::create([ | |||||
User::create([ | |||||
'name' => 'test_user_unverified', | 'name' => 'test_user_unverified', | ||||
'email' => 'unverified@example.com', | 'email' => 'unverified@example.com', | ||||
'role' => 'client', | 'role' => 'client', | ||||
'active' => true, | 'active' => true, | ||||
'password' => Hash::make("test123") | 'password' => Hash::make("test123") | ||||
]); | ]); | ||||
User::create([ | |||||
$test_user = User::create([ | |||||
'name' => 'test_user_verified', | 'name' => 'test_user_verified', | ||||
'email' => 'verified@example.com', | 'email' => 'verified@example.com', | ||||
'email_verified_at' => now(), | 'email_verified_at' => now(), | ||||
@@ -75,7 +75,6 @@ function getOrders(app) { | |||||
}).then(data => { | }).then(data => { | ||||
app.orders = data | app.orders = data | ||||
}) | }) | ||||
/* return this.user.name */ | |||||
} | } | ||||
//Attempt to resend the verification link | //Attempt to resend the verification link | ||||
@@ -142,5 +141,6 @@ if (window.location.pathname == '/') { | |||||
const app = createApp(Panel).mount('#panel') | const app = createApp(Panel).mount('#panel') | ||||
window.onhashchange = ()=>{app.active = location.hash} | window.onhashchange = ()=>{app.active = location.hash} | ||||
getUser(app) | getUser(app) | ||||
getOrders(app) | |||||
} | } | ||||
@@ -7,12 +7,33 @@ | |||||
<section class="alerts-pane"><h4>News and Announcements</h4> | <section class="alerts-pane"><h4>News and Announcements</h4> | ||||
<p>We've just launched. Thanks for joining us.</p> | <p>We've just launched. Thanks for joining us.</p> | ||||
</section> | </section> | ||||
<section class="recent-pane"><h4>Recent Activity</h4>Recent activity showing last 5 completed orders </section> | |||||
<section class="recent-pane"><h4>Recent Activity</h4> | |||||
<table> | |||||
<thead><th>Date</th><th>Name</th><th>Status</th> <th>Quantity</th></thead> | |||||
<tbody> | |||||
<tr v-bind:key='order.id' v-for='order in orders.slice(0, 10)'> | |||||
<template v-if="order.status != 'pending'"> | |||||
<td>{{order.updated_at}}</td> | |||||
<td>{{order.service.name}}</td> | |||||
<td :class="order.status" | |||||
class="status"><span>{{order.status.charAt(0).toUpperCase() + | |||||
order.status.slice(1)}}</span></td> | |||||
<td>{{order.quantity}}</td> | |||||
</template> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</section> | |||||
</div> | </div> | ||||
<div v-else-if="active === '#orders'" id="main"> | <div v-else-if="active === '#orders'" id="main"> | ||||
<div class="actions"><a href="#orders/new">New</a></div> | <div class="actions"><a href="#orders/new">New</a></div> | ||||
<section class="pending-pane"> | <section class="pending-pane"> | ||||
<h4>Pending Orders</h4> | <h4>Pending Orders</h4> | ||||
<ul> | |||||
<template v-bind:key='order.id' v-for="order in orders"> | |||||
<li v-if="order.status == 'pending'">{{order.service.name}} - {{order.updated_at}}</li> | |||||
</template> | |||||
</ul> | |||||
</section> | </section> | ||||
</div> | </div> | ||||
</transition> | </transition> | ||||
@@ -27,6 +48,6 @@ export default { | |||||
}, | }, | ||||
data() { | data() { | ||||
return {active: window.location.hash, user: '', | return {active: window.location.hash, user: '', | ||||
token: ''}}, | |||||
token: '', orders: ''}}, | |||||
} | } | ||||
</script> | </script> |
@@ -13,6 +13,8 @@ $theme-colors: ( | |||||
"brand-orange": #f67602, | "brand-orange": #f67602, | ||||
"grey": #e6ebf1, | "grey": #e6ebf1, | ||||
"light-grey": #e9e9e9, | "light-grey": #e9e9e9, | ||||
"light2-grey": rgb(190,190,190), | |||||
"light3-grey": rgb(245,245,245), | |||||
"dark-grey": #212121, | "dark-grey": #212121, | ||||
"faded-text": #425466, | "faded-text": #425466, | ||||
"faded-text2": #6c757d, | "faded-text2": #6c757d, | ||||
@@ -43,7 +43,7 @@ ul { | |||||
padding: 0; | padding: 0; | ||||
} | } | ||||
li { | |||||
.services-cards li { | |||||
padding-bottom: 8px; | padding-bottom: 8px; | ||||
&:before { | &:before { | ||||
width: 30px; | width: 30px; | ||||
@@ -721,6 +721,7 @@ main.panel { | |||||
@include vars.hovering3; | @include vars.hovering3; | ||||
transition: opacity 0.5s ease; | transition: opacity 0.5s ease; | ||||
vertical-align: middle; | vertical-align: middle; | ||||
overflow: scroll; | |||||
// text-align: center; | // text-align: center; | ||||
section { | section { | ||||
@@ -763,10 +764,47 @@ main.panel { | |||||
} | } | ||||
} | } | ||||
// .fade-enter-active, .fade-leave-active { | |||||
// transition: opacity 1s ease; | |||||
// } | |||||
.fade-enter-from, .fade-leave-to { | .fade-enter-from, .fade-leave-to { | ||||
opacity: 0; | opacity: 0; | ||||
} | } | ||||
.recent-pane { | |||||
table { | |||||
border-spacing: 4px; | |||||
margin: auto; | |||||
text-align: center; | |||||
} | |||||
th { | |||||
font-weight: normal; | |||||
color: vars.getColor("light2-grey"); | |||||
} | |||||
tr { | |||||
border-bottom: 3px solid black; | |||||
} | |||||
td { | |||||
border-bottom: 2px solid vars.getColor("grey"); | |||||
// color: vars.getColor("light3-grey"); | |||||
// font-size: 1rem; | |||||
font-size: 0.8rem; | |||||
} | |||||
td.completed span { | |||||
background: vars.getColor('green'); | |||||
color: vars.darkenColor('green'); | |||||
border-radius: 4px; | |||||
padding: 2px; | |||||
} | |||||
td.processing { | |||||
color: vars.getColor('light-blue'); | |||||
} | |||||
td.canceled { | |||||
color: vars.getColor('red-alert'); | |||||
} | |||||
} |
@@ -59,6 +59,6 @@ Route::get('/panel/user', function (Request $request) { | |||||
return $request->user(); | return $request->user(); | ||||
})->middleware('auth'); | })->middleware('auth'); | ||||
Route::post('/panel/orders', [UserController::class, | |||||
Route::get('/panel/orders', [UserController::class, | |||||
'getOrders'])->middleware('auth'); | 'getOrders'])->middleware('auth'); | ||||