dashboard include

This commit is contained in:
carodej
2020-07-05 09:14:17 +02:00
parent e1ebb70035
commit 5a5125967f
61 changed files with 1532 additions and 617 deletions

View File

@@ -25,13 +25,13 @@ REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_DRIVER=
MAIL_HOST=
MAIL_PORT=
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=
MAIL_FROM_ADDRESS="${MAIL_USERNAME}"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Http\Controllers\Admin;
use App\FileManagerFile;
use App\Http\Controllers\Controller;
use App\Http\Resources\UsersCollection;
use App\Services\StripeService;
use App\User;
use ByteUnits\Metric;
use Illuminate\Http\Request;
use Laravel\Cashier\Subscription;
class DashboardController extends Controller
{
/**
* DashboardController constructor.
*/
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
public function index()
{
// Get total users
$total_users = User::all()->count();
// Get total used space
$total_used_space = FileManagerFile::all()->map(function ($item) {
return (int)$item->getRawOriginal('filesize');
})->sum();
// Get total premium users
$total_premium_users = Subscription::where('stripe_status', 'active')->get()->count();
return [
'app_version' => config('vuefilemanager.version'),
'total_users' => $total_users,
'total_used_space' => Metric::bytes($total_used_space)->format(),
'total_premium_users' => $total_premium_users,
];
}
/**
* Get the newest users
*
* @return UsersCollection
*/
public function new_registrations()
{
return new UsersCollection(
User::take(5)->orderByDesc('created_at')->get()
);
}
}

View File

@@ -1,69 +0,0 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Resources\GatewayCollection;
use App\Http\Resources\GatewayResource;
use App\Http\Resources\InvoiceCollection;
use App\Invoice;
use App\PaymentGateway;
use Illuminate\Http\Request;
class GatewayController extends Controller
{
/**
* Get all payment gateways
*
* @return GatewayCollection
*/
public function index()
{
return new GatewayCollection(PaymentGateway::all());
}
/**
* Get single payment gateway by slug
*
* @param $slug
* @return GatewayResource
*/
public function show($slug)
{
$gateway = PaymentGateway::where('slug', $slug)->firstOrFail();
return new GatewayResource($gateway);
}
/**
* Get single payment gateway by slug
*
* @param $slug
* @return InvoiceCollection
*/
public function show_transactions($slug)
{
return new InvoiceCollection(
Invoice::where('provider', $slug)->get()
);
}
/**
* Update payment gateway options
*
* @param Request $request
* @param $slug
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function update(Request $request, $slug)
{
// TODO: validation request
$gateway = PaymentGateway::where('slug', $slug)->first();
// Update text data
$gateway->update(make_single_input($request));
return response('Saved!', 204);
}
}

View File

@@ -12,6 +12,7 @@ use App\Services\StripeService;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Laravel\Cashier\Subscription;
use Rinvex\Subscriptions\Models\PlanFeature;
class PlanController extends Controller
@@ -126,10 +127,7 @@ class PlanController extends Controller
*/
public function subscribers($id)
{
$subscribers = app('rinvex.subscriptions.plan')
->find($id)
->subscriptions
->pluck('user_id');
$subscribers = Subscription::where('stripe_plan', $id)->pluck('user_id');
return new UsersCollection(
User::findMany($subscribers)

View File

@@ -106,7 +106,7 @@ class SetupWizardController extends Controller
// Store database credentials
$database_credentials->each(function ($col) {
$this->setEnvironmentValue($col['name'], $col['value']);
setEnvironmentValue($col['name'], $col['value']);
});
// Set database connection
@@ -161,8 +161,8 @@ class SetupWizardController extends Controller
$client = \DB::table('oauth_clients')->where('name', '=', 'vuefilemanager')->first();
// Set passport client to .env
$this->setEnvironmentValue('PASSPORT_CLIENT_ID', $client->id);
$this->setEnvironmentValue('PASSPORT_CLIENT_SECRET', $client->secret);
setEnvironmentValue('PASSPORT_CLIENT_ID', $client->id);
setEnvironmentValue('PASSPORT_CLIENT_SECRET', $client->secret);
// Clear cache
Artisan::call('config:clear');
@@ -208,19 +208,13 @@ class SetupWizardController extends Controller
]);
// Set stripe credentials to .env
$this->setEnvironmentValue('CASHIER_CURRENCY', $request->currency);
$this->setEnvironmentValue('STRIPE_KEY', $request->key);
$this->setEnvironmentValue('STRIPE_SECRET', $request->secret);
$this->setEnvironmentValue('STRIPE_WEBHOOK_SECRET', $request->webhookSecret);
// Store options
$settings->each(function ($col) {
Setting::updateOrCreate(['name' => $col['name']], $col);
});
setEnvironmentValue('CASHIER_CURRENCY', $request->currency);
setEnvironmentValue('STRIPE_KEY', $request->key);
setEnvironmentValue('STRIPE_SECRET', $request->secret);
setEnvironmentValue('STRIPE_WEBHOOK_SECRET', $request->webhookSecret);
// Clear cache
Artisan::call('config:clear');
//Artisan::call('config:cache');
return response('Done', 200);
}
@@ -427,7 +421,7 @@ class SetupWizardController extends Controller
// Store storage driver options
$storage->each(function ($col) {
$this->setEnvironmentValue($col['name'], $col['value']);
setEnvironmentValue($col['name'], $col['value']);
});
// Get options
@@ -460,12 +454,11 @@ class SetupWizardController extends Controller
// Store mail options
$mail->each(function ($col) {
$this->setEnvironmentValue($col['name'], $col['value']);
setEnvironmentValue($col['name'], $col['value']);
});
// Clear cache
Artisan::call('config:clear');
//Artisan::call('config:cache');
return response('Done', 200);
}
@@ -545,10 +538,12 @@ class SetupWizardController extends Controller
{
// Validate request
$request->validate([
'email' => 'required|string|email|unique:users',
'password' => 'required|string|min:6|confirmed',
'name' => 'required|string',
'avatar' => 'sometimes|file',
'email' => 'required|string|email|unique:users',
'password' => 'required|string|min:6|confirmed',
'name' => 'required|string',
'purchase_code' => 'required|string',
'license' => 'required|string',
'avatar' => 'sometimes|file',
]);
// Store avatar
@@ -580,6 +575,18 @@ class SetupWizardController extends Controller
'value' => 1,
]);
// Store License
Setting::create([
'name' => 'license',
'value' => $request->license,
]);
// Store Purchase Code
Setting::create([
'name' => 'license',
'value' => $request->purchase_code,
]);
// Retrieve access token
$response = Route::dispatch(self::make_login_request($request));
@@ -613,23 +620,4 @@ class SetupWizardController extends Controller
return Request::create(url('/oauth/token'), 'POST', $request->all());
}
/**
* Set environment value
*
* @param $key
* @param $value
*/
public function setEnvironmentValue($key, $value)
{
$env_path = app()->environmentFilePath();
$escaped = preg_quote('=' . env($key), '/');
file_put_contents($env_path, preg_replace(
"/^{$key}{$escaped}/m",
$key . '=' . $value,
file_get_contents($env_path)
));
}
}

View File

@@ -3,83 +3,105 @@
namespace App\Http\Controllers;
use App\Setting;
use Artisan;
use Illuminate\Http\Request;
class SettingController extends Controller
{
/**
* Display a listing of the resource.
* Get table content
*
* @return \Illuminate\Http\Response
* @param Request $request
* @return mixed
*/
public function index()
{
//
}
public function show(Request $request) {
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
$column = $request->get('column');
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
if (strpos($column, '|') !== false) {
/**
* Display the specified resource.
*
* @param \App\Setting $setting
* @return \Illuminate\Http\Response
*/
public function show(Setting $setting)
{
//
}
$columns = explode('|', $column);
/**
* Show the form for editing the specified resource.
*
* @param \App\Setting $setting
* @return \Illuminate\Http\Response
*/
public function edit(Setting $setting)
{
//
return Setting::whereIn('name', $columns)->pluck('value', 'name');
}
return Setting::where('name', $column)->pluck('value', 'name');
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Setting $setting
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Setting $setting)
public function update(Request $request)
{
//
// Store image if exist
if ($request->hasFile($request->name)) {
// Store image
$image_path = store_system_image($request->file($request->name), 'system');
// Find and update image path
Setting::updateOrCreate(['name' => $request->name], [
'value' => $image_path
]);
return response('Done', 204);
}
// Find and update variable
Setting::updateOrCreate(['name' => $request->name], [
'value' => $request->value
]);
return response('Done', 204);
}
/**
* Remove the specified resource from storage.
* Set new email credentials to .env file
*
* @param \App\Setting $setting
* @return \Illuminate\Http\Response
* @param Request $request
* @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
*/
public function destroy(Setting $setting)
{
//
public function set_email(Request $request) {
// Get options
$mail = collect([
[
'name' => 'MAIL_DRIVER',
'value' => $request->input('driver'),
],
[
'name' => 'MAIL_HOST',
'value' => $request->input('host'),
],
[
'name' => 'MAIL_PORT',
'value' => $request->input('port'),
],
[
'name' => 'MAIL_USERNAME',
'value' => $request->input('username'),
],
[
'name' => 'MAIL_PASSWORD',
'value' => $request->input('password'),
],
[
'name' => 'MAIL_ENCRYPTION',
'value' => $request->input('encryption'),
],
]);
// Store mail options
$mail->each(function ($col) {
setEnvironmentValue($col['name'], $col['value']);
});
// Clear cache
Artisan::call('config:clear');
return response('Done', 204);
}
}

View File

@@ -6,11 +6,29 @@ use App\Share;
use ByteUnits\Metric;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\ImageManagerStatic as Image;
/**
* Set environment value
*
* @param $key
* @param $value
*/
function setEnvironmentValue($key, $value)
{
$env_path = app()->environmentFilePath();
$escaped = preg_quote('=' . env($key), '/');
file_put_contents($env_path, preg_replace(
"/^{$key}{$escaped}/m",
$key . '=' . $value,
file_get_contents($env_path)
));
}
/**
* Get invoice number
*
@@ -27,6 +45,10 @@ function get_invoice_number()
}
}
/**
* Forget many cache keys at once
* @param $cache
*/
function cache_forget_many($cache)
{
foreach ($cache as $item) {

View File

@@ -52,8 +52,8 @@ class InvoiceAdminResource extends JsonResource
'id' => (string)$user->id,
'type' => 'user',
'attributes' => [
'name' => $user->name,
'avatar' => $user->avatar,
'name' => $user->name,
'avatar' => $user->avatar,
]
]
]

View File

@@ -26,7 +26,7 @@ class InvoiceResource extends JsonResource
'customer' => $this->customer,
'total' => $this->total(),
'currency' => $this->currency,
'created_at_formatted' => format_date($this->date()),
'created_at_formatted' => format_date($this->date(), '%d. %B. %Y'),
'created_at' => $this->created,
'order' => $this->number,
'user_id' => $user ? $user->id : null,

View File

@@ -3,6 +3,8 @@
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use Laravel\Cashier\Cashier;
use Laravel\Cashier\Subscription;
class PlanResource extends JsonResource
{
@@ -14,18 +16,22 @@ class PlanResource extends JsonResource
*/
public function toArray($request)
{
// Get subscribers
$subscriber_count = Subscription::where('stripe_plan', $this['plan']['id'])->get();
return [
'data' => [
'id' => $this['plan']['id'],
'type' => 'plans',
'attributes' => [
'subscribers' => $this['plan']['aggregate_usage'],
'status' => $this['plan']['active'],
'subscribers' => $subscriber_count->count(),
'status' => $this['plan']['active'] ? 1 : 0,
'name' => $this['product']['name'],
'description' => $this['product']['description'],
'price' => $this['plan']['amount'],
'price_formatted' => Cashier::formatAmount($this['plan']['amount']),
'capacity_formatted' => format_gigabytes($this['product']['metadata']['capacity']),
'capacity' => $this['product']['metadata']['capacity'],
'capacity' => (int) $this['product']['metadata']['capacity'],
'created_at_formatted' => format_date($this['plan']['created']),
'created_at' => $this['plan']['created'],
]

View File

@@ -2,17 +2,5 @@
return [
'version' => '1.6.3',
// Your app name
'app_name' => 'VueFileManager',
// Your app logo
'app_logo' => '/assets/images/hero.svg',
// Enable or disable user account registration
'registration' => true,
// Limit your storage size for every user if this option is enabled
'limit_storage_by_capacity' => true,
'version' => '1.7',
];

View File

@@ -228,5 +228,383 @@
"/js/main.0cf8831e92ff6f5a1027.hot-update.js": "/js/main.0cf8831e92ff6f5a1027.hot-update.js",
"/js/main.5cbee996e80957a738f2.hot-update.js": "/js/main.5cbee996e80957a738f2.hot-update.js",
"/js/main.9a24bd7a75a877705d40.hot-update.js": "/js/main.9a24bd7a75a877705d40.hot-update.js",
"/js/main.2ecd9a546308a5bb528a.hot-update.js": "/js/main.2ecd9a546308a5bb528a.hot-update.js"
"/js/main.2ecd9a546308a5bb528a.hot-update.js": "/js/main.2ecd9a546308a5bb528a.hot-update.js",
"/js/main.a9aeb4df0e09a70f4ec8.hot-update.js": "/js/main.a9aeb4df0e09a70f4ec8.hot-update.js",
"/js/main.9bf7aa6441ae107090d4.hot-update.js": "/js/main.9bf7aa6441ae107090d4.hot-update.js",
"/js/main.0daba0063cb5697dc767.hot-update.js": "/js/main.0daba0063cb5697dc767.hot-update.js",
"/js/main.31f05dfd2001129a8fc5.hot-update.js": "/js/main.31f05dfd2001129a8fc5.hot-update.js",
"/js/main.d2b72f113673d28f3c59.hot-update.js": "/js/main.d2b72f113673d28f3c59.hot-update.js",
"/js/main.073817fa2426387d3745.hot-update.js": "/js/main.073817fa2426387d3745.hot-update.js",
"/js/main.37ac8a311fc1087fcc2f.hot-update.js": "/js/main.37ac8a311fc1087fcc2f.hot-update.js",
"/js/main.2bde9f71b5d8131f5928.hot-update.js": "/js/main.2bde9f71b5d8131f5928.hot-update.js",
"/js/main.9df8ef628601cef7a6a5.hot-update.js": "/js/main.9df8ef628601cef7a6a5.hot-update.js",
"/js/main.ca4251328bc4169dd5f6.hot-update.js": "/js/main.ca4251328bc4169dd5f6.hot-update.js",
"/js/main.5761e22b5dc8194b04c7.hot-update.js": "/js/main.5761e22b5dc8194b04c7.hot-update.js",
"/js/main.cab7cbeb3d5d492f39ba.hot-update.js": "/js/main.cab7cbeb3d5d492f39ba.hot-update.js",
"/js/main.726f3d68977a95d4e90e.hot-update.js": "/js/main.726f3d68977a95d4e90e.hot-update.js",
"/js/main.243884a8a7e3a13794a7.hot-update.js": "/js/main.243884a8a7e3a13794a7.hot-update.js",
"/js/main.b363f9fe306c90d3bea9.hot-update.js": "/js/main.b363f9fe306c90d3bea9.hot-update.js",
"/js/main.df63396c1532271c6de1.hot-update.js": "/js/main.df63396c1532271c6de1.hot-update.js",
"/js/main.1f2f6ae9328a61a32c9b.hot-update.js": "/js/main.1f2f6ae9328a61a32c9b.hot-update.js",
"/js/main.0bd8c23a58693130fc17.hot-update.js": "/js/main.0bd8c23a58693130fc17.hot-update.js",
"/js/main.ee79e38ff92d0f742d6e.hot-update.js": "/js/main.ee79e38ff92d0f742d6e.hot-update.js",
"/js/main.517d46a9db04a7db47d3.hot-update.js": "/js/main.517d46a9db04a7db47d3.hot-update.js",
"/js/main.b441e4a6d755a50477a7.hot-update.js": "/js/main.b441e4a6d755a50477a7.hot-update.js",
"/js/main.63531cfb10cfff9d4271.hot-update.js": "/js/main.63531cfb10cfff9d4271.hot-update.js",
"/js/main.2df58097c81bcc54d255.hot-update.js": "/js/main.2df58097c81bcc54d255.hot-update.js",
"/js/main.9e088bfaa8eb3387988a.hot-update.js": "/js/main.9e088bfaa8eb3387988a.hot-update.js",
"/js/main.44a7ebb3f583b95cf504.hot-update.js": "/js/main.44a7ebb3f583b95cf504.hot-update.js",
"/js/main.b6d9dd61120dc4dd5137.hot-update.js": "/js/main.b6d9dd61120dc4dd5137.hot-update.js",
"/js/main.b47af3291ecd700d363a.hot-update.js": "/js/main.b47af3291ecd700d363a.hot-update.js",
"/js/main.731736cf111ded41ca59.hot-update.js": "/js/main.731736cf111ded41ca59.hot-update.js",
"/js/main.8821e3435181c45a4efe.hot-update.js": "/js/main.8821e3435181c45a4efe.hot-update.js",
"/js/main.20979fe3d1769ef98369.hot-update.js": "/js/main.20979fe3d1769ef98369.hot-update.js",
"/js/main.2ffc183bac24a4613d5b.hot-update.js": "/js/main.2ffc183bac24a4613d5b.hot-update.js",
"/js/main.1e6f3de193e1eb41e3f8.hot-update.js": "/js/main.1e6f3de193e1eb41e3f8.hot-update.js",
"/js/main.250e55b4bc88222cf2bd.hot-update.js": "/js/main.250e55b4bc88222cf2bd.hot-update.js",
"/js/main.05b9cad5fcae320220cf.hot-update.js": "/js/main.05b9cad5fcae320220cf.hot-update.js",
"/js/main.70fe96e65497d24ada87.hot-update.js": "/js/main.70fe96e65497d24ada87.hot-update.js",
"/js/main.2d0692b8d1b139678ea5.hot-update.js": "/js/main.2d0692b8d1b139678ea5.hot-update.js",
"/js/main.ccaed9fac1fa6686e62d.hot-update.js": "/js/main.ccaed9fac1fa6686e62d.hot-update.js",
"/js/main.59812fdf3d8df2071110.hot-update.js": "/js/main.59812fdf3d8df2071110.hot-update.js",
"/js/main.ede87598deed0a8c2062.hot-update.js": "/js/main.ede87598deed0a8c2062.hot-update.js",
"/js/main.58751759a25668b5b807.hot-update.js": "/js/main.58751759a25668b5b807.hot-update.js",
"/js/main.965475f49f9a23fc8920.hot-update.js": "/js/main.965475f49f9a23fc8920.hot-update.js",
"/js/main.fd25a0ff5e4fdedd17dd.hot-update.js": "/js/main.fd25a0ff5e4fdedd17dd.hot-update.js",
"/js/main.da72a2d3a9ec9eaad632.hot-update.js": "/js/main.da72a2d3a9ec9eaad632.hot-update.js",
"/js/main.39754f4a16f1a7c40ad3.hot-update.js": "/js/main.39754f4a16f1a7c40ad3.hot-update.js",
"/js/main.6108877fbeecf1a314d3.hot-update.js": "/js/main.6108877fbeecf1a314d3.hot-update.js",
"/js/main.a420126064791edbc6bd.hot-update.js": "/js/main.a420126064791edbc6bd.hot-update.js",
"/js/main.7dd34dcba41c61c93874.hot-update.js": "/js/main.7dd34dcba41c61c93874.hot-update.js",
"/js/main.ee22470c79de439cb17a.hot-update.js": "/js/main.ee22470c79de439cb17a.hot-update.js",
"/js/main.b20467e29f72f2c2a43a.hot-update.js": "/js/main.b20467e29f72f2c2a43a.hot-update.js",
"/js/main.74ed66a1e6e61a59c726.hot-update.js": "/js/main.74ed66a1e6e61a59c726.hot-update.js",
"/js/main.1b35cacb98ad335dc603.hot-update.js": "/js/main.1b35cacb98ad335dc603.hot-update.js",
"/js/main.e2d923caede2fd0e9ee9.hot-update.js": "/js/main.e2d923caede2fd0e9ee9.hot-update.js",
"/js/main.f053c756cb426a7f7f02.hot-update.js": "/js/main.f053c756cb426a7f7f02.hot-update.js",
"/js/main.0d9bc815c8955418e14d.hot-update.js": "/js/main.0d9bc815c8955418e14d.hot-update.js",
"/js/main.212f10ad9990506452bc.hot-update.js": "/js/main.212f10ad9990506452bc.hot-update.js",
"/js/main.13e6dae0d08658ab17da.hot-update.js": "/js/main.13e6dae0d08658ab17da.hot-update.js",
"/js/main.88b4ad3f37f9b1774047.hot-update.js": "/js/main.88b4ad3f37f9b1774047.hot-update.js",
"/js/main.c9b6d032281c78b8413f.hot-update.js": "/js/main.c9b6d032281c78b8413f.hot-update.js",
"/js/main.99443545526048f4cc53.hot-update.js": "/js/main.99443545526048f4cc53.hot-update.js",
"/js/main.a986fccabd91fafa8902.hot-update.js": "/js/main.a986fccabd91fafa8902.hot-update.js",
"/js/main.9c7aa8d3304c04a09c22.hot-update.js": "/js/main.9c7aa8d3304c04a09c22.hot-update.js",
"/js/main.d8a9103a7a6400055308.hot-update.js": "/js/main.d8a9103a7a6400055308.hot-update.js",
"/js/main.6adfb10ae4c11c2c4870.hot-update.js": "/js/main.6adfb10ae4c11c2c4870.hot-update.js",
"/js/main.a36325466e8b00e7b615.hot-update.js": "/js/main.a36325466e8b00e7b615.hot-update.js",
"/js/main.33d6d9af87dab520be16.hot-update.js": "/js/main.33d6d9af87dab520be16.hot-update.js",
"/js/main.df8a6030831d5c6fc7ed.hot-update.js": "/js/main.df8a6030831d5c6fc7ed.hot-update.js",
"/js/main.43e2677447332829f8cf.hot-update.js": "/js/main.43e2677447332829f8cf.hot-update.js",
"/js/main.c50fe1ffc43419a8e371.hot-update.js": "/js/main.c50fe1ffc43419a8e371.hot-update.js",
"/js/main.90bf9b653edbc8c036b4.hot-update.js": "/js/main.90bf9b653edbc8c036b4.hot-update.js",
"/js/main.f487dd6abb989d2be7f5.hot-update.js": "/js/main.f487dd6abb989d2be7f5.hot-update.js",
"/js/main.be807354d256e90aaa4a.hot-update.js": "/js/main.be807354d256e90aaa4a.hot-update.js",
"/js/main.6edb2b0bd968e3732628.hot-update.js": "/js/main.6edb2b0bd968e3732628.hot-update.js",
"/js/main.da00b20ca4885ff4ac09.hot-update.js": "/js/main.da00b20ca4885ff4ac09.hot-update.js",
"/js/main.7c05a3f75b8d0fd3d7a1.hot-update.js": "/js/main.7c05a3f75b8d0fd3d7a1.hot-update.js",
"/js/main.ab38426d3250e1622830.hot-update.js": "/js/main.ab38426d3250e1622830.hot-update.js",
"/js/main.9d0f2dbd79d7b103684d.hot-update.js": "/js/main.9d0f2dbd79d7b103684d.hot-update.js",
"/js/main.b76c61916ae29b6be638.hot-update.js": "/js/main.b76c61916ae29b6be638.hot-update.js",
"/js/main.0bd7da88f8de2ae7f5de.hot-update.js": "/js/main.0bd7da88f8de2ae7f5de.hot-update.js",
"/js/main.37d310f86266f8e2f8af.hot-update.js": "/js/main.37d310f86266f8e2f8af.hot-update.js",
"/js/main.3d92d7ffe2cb83e6438c.hot-update.js": "/js/main.3d92d7ffe2cb83e6438c.hot-update.js",
"/js/main.04244bb60dc1e20dc4c4.hot-update.js": "/js/main.04244bb60dc1e20dc4c4.hot-update.js",
"/js/main.0b94fa8596095bdee261.hot-update.js": "/js/main.0b94fa8596095bdee261.hot-update.js",
"/js/main.e57b173b91990862814a.hot-update.js": "/js/main.e57b173b91990862814a.hot-update.js",
"/js/main.1251088060e2a88fffc3.hot-update.js": "/js/main.1251088060e2a88fffc3.hot-update.js",
"/js/main.96fed4906621b3f94187.hot-update.js": "/js/main.96fed4906621b3f94187.hot-update.js",
"/js/main.fee3081c0b7fffc5f769.hot-update.js": "/js/main.fee3081c0b7fffc5f769.hot-update.js",
"/js/main.c3d6a61bb34165a6b384.hot-update.js": "/js/main.c3d6a61bb34165a6b384.hot-update.js",
"/js/main.df82c14cac779d7006fc.hot-update.js": "/js/main.df82c14cac779d7006fc.hot-update.js",
"/js/main.2d4a45fe1b581c9a7beb.hot-update.js": "/js/main.2d4a45fe1b581c9a7beb.hot-update.js",
"/js/main.6481aa4922d9b76d954c.hot-update.js": "/js/main.6481aa4922d9b76d954c.hot-update.js",
"/js/main.27079245b2bf0120760c.hot-update.js": "/js/main.27079245b2bf0120760c.hot-update.js",
"/js/main.29a09d3256e19a9ceb69.hot-update.js": "/js/main.29a09d3256e19a9ceb69.hot-update.js",
"/js/main.d74598876b29288d6407.hot-update.js": "/js/main.d74598876b29288d6407.hot-update.js",
"/js/main.9bb1e42907e84c4449be.hot-update.js": "/js/main.9bb1e42907e84c4449be.hot-update.js",
"/js/main.62b41bc71640b74b4aa8.hot-update.js": "/js/main.62b41bc71640b74b4aa8.hot-update.js",
"/js/main.17305704d03c324dd8a9.hot-update.js": "/js/main.17305704d03c324dd8a9.hot-update.js",
"/js/main.6e2eff04c81d033b5900.hot-update.js": "/js/main.6e2eff04c81d033b5900.hot-update.js",
"/js/main.fde14e611bd080c04359.hot-update.js": "/js/main.fde14e611bd080c04359.hot-update.js",
"/js/main.f3d1b5f18cb8b280c8a8.hot-update.js": "/js/main.f3d1b5f18cb8b280c8a8.hot-update.js",
"/js/main.ee62b7df7093e451084d.hot-update.js": "/js/main.ee62b7df7093e451084d.hot-update.js",
"/js/main.cdb73ff90d532b4912c7.hot-update.js": "/js/main.cdb73ff90d532b4912c7.hot-update.js",
"/js/main.bf9c690516f80e14267a.hot-update.js": "/js/main.bf9c690516f80e14267a.hot-update.js",
"/js/main.a781a04264a7c7ee8662.hot-update.js": "/js/main.a781a04264a7c7ee8662.hot-update.js",
"/js/main.c32ae81891394df8966c.hot-update.js": "/js/main.c32ae81891394df8966c.hot-update.js",
"/js/main.87376cc90c6422487ef5.hot-update.js": "/js/main.87376cc90c6422487ef5.hot-update.js",
"/js/main.9c15ba958d6f151718e5.hot-update.js": "/js/main.9c15ba958d6f151718e5.hot-update.js",
"/js/main.ca11d0d3e7e6548db463.hot-update.js": "/js/main.ca11d0d3e7e6548db463.hot-update.js",
"/js/main.c0ebe1c24d0f3b200d14.hot-update.js": "/js/main.c0ebe1c24d0f3b200d14.hot-update.js",
"/js/main.2f74177767e6040ca80b.hot-update.js": "/js/main.2f74177767e6040ca80b.hot-update.js",
"/js/main.55d7ec43b99bba0bfcd3.hot-update.js": "/js/main.55d7ec43b99bba0bfcd3.hot-update.js",
"/js/main.d128d1383b2c1a38ce93.hot-update.js": "/js/main.d128d1383b2c1a38ce93.hot-update.js",
"/js/main.5540a8eeb4b79f986c32.hot-update.js": "/js/main.5540a8eeb4b79f986c32.hot-update.js",
"/js/main.ea864bbc020706b3771c.hot-update.js": "/js/main.ea864bbc020706b3771c.hot-update.js",
"/js/main.def370fcc6f9538dbbda.hot-update.js": "/js/main.def370fcc6f9538dbbda.hot-update.js",
"/js/main.2d3cf541ccb2fc9e0e85.hot-update.js": "/js/main.2d3cf541ccb2fc9e0e85.hot-update.js",
"/js/main.afd20da200abbc8c6a08.hot-update.js": "/js/main.afd20da200abbc8c6a08.hot-update.js",
"/js/main.4804fb86e21f548250aa.hot-update.js": "/js/main.4804fb86e21f548250aa.hot-update.js",
"/js/main.6d5b3e87bc0b7e673517.hot-update.js": "/js/main.6d5b3e87bc0b7e673517.hot-update.js",
"/js/main.9a017e2922144c301988.hot-update.js": "/js/main.9a017e2922144c301988.hot-update.js",
"/js/main.5a106890cb5905af701a.hot-update.js": "/js/main.5a106890cb5905af701a.hot-update.js",
"/js/main.dea9c33e910b52cead09.hot-update.js": "/js/main.dea9c33e910b52cead09.hot-update.js",
"/js/main.4224f9a6ac1fe049fd37.hot-update.js": "/js/main.4224f9a6ac1fe049fd37.hot-update.js",
"/js/main.38f268c3a71eab9ce5bc.hot-update.js": "/js/main.38f268c3a71eab9ce5bc.hot-update.js",
"/js/main.0d4e180970ec3c4d45ec.hot-update.js": "/js/main.0d4e180970ec3c4d45ec.hot-update.js",
"/js/main.693e4a862910aaed3aac.hot-update.js": "/js/main.693e4a862910aaed3aac.hot-update.js",
"/js/main.7804b447fa1b91b1a80a.hot-update.js": "/js/main.7804b447fa1b91b1a80a.hot-update.js",
"/js/main.5f90346563b3ff5220fb.hot-update.js": "/js/main.5f90346563b3ff5220fb.hot-update.js",
"/js/main.d656e96b2908c4f503ee.hot-update.js": "/js/main.d656e96b2908c4f503ee.hot-update.js",
"/js/main.2e8f76f47f727a693d5b.hot-update.js": "/js/main.2e8f76f47f727a693d5b.hot-update.js",
"/js/main.37480ef5f8e61c14783d.hot-update.js": "/js/main.37480ef5f8e61c14783d.hot-update.js",
"/js/main.193421983c10faf9d145.hot-update.js": "/js/main.193421983c10faf9d145.hot-update.js",
"/js/main.8fd708f023b6acf486d3.hot-update.js": "/js/main.8fd708f023b6acf486d3.hot-update.js",
"/js/main.5bd9a89dc494d93da831.hot-update.js": "/js/main.5bd9a89dc494d93da831.hot-update.js",
"/js/main.6847a02e533ad6446e5c.hot-update.js": "/js/main.6847a02e533ad6446e5c.hot-update.js",
"/js/main.5790aab9e27dc5b99581.hot-update.js": "/js/main.5790aab9e27dc5b99581.hot-update.js",
"/js/main.9cbed327a373f7d8d699.hot-update.js": "/js/main.9cbed327a373f7d8d699.hot-update.js",
"/js/main.3cb0bdf506f18b7160f7.hot-update.js": "/js/main.3cb0bdf506f18b7160f7.hot-update.js",
"/js/main.9bd00e48a8662f61e1e4.hot-update.js": "/js/main.9bd00e48a8662f61e1e4.hot-update.js",
"/js/main.b3f92e8fb2e0634a415b.hot-update.js": "/js/main.b3f92e8fb2e0634a415b.hot-update.js",
"/js/main.0c2ae430c9e9794d30b1.hot-update.js": "/js/main.0c2ae430c9e9794d30b1.hot-update.js",
"/js/main.cae8e58f9def02d6856e.hot-update.js": "/js/main.cae8e58f9def02d6856e.hot-update.js",
"/js/main.1e975719c8e6293673c7.hot-update.js": "/js/main.1e975719c8e6293673c7.hot-update.js",
"/js/main.f2766ac3b40405939464.hot-update.js": "/js/main.f2766ac3b40405939464.hot-update.js",
"/js/main.9112a25dbcbbb65def79.hot-update.js": "/js/main.9112a25dbcbbb65def79.hot-update.js",
"/js/main.a1a839083b9b0af30fcb.hot-update.js": "/js/main.a1a839083b9b0af30fcb.hot-update.js",
"/js/main.39e716c80acd5a7264b8.hot-update.js": "/js/main.39e716c80acd5a7264b8.hot-update.js",
"/js/main.50270c3093d1b3ca22b0.hot-update.js": "/js/main.50270c3093d1b3ca22b0.hot-update.js",
"/js/main.ef196bbfccb5f8b66167.hot-update.js": "/js/main.ef196bbfccb5f8b66167.hot-update.js",
"/js/main.5ca3431d17a903e5dae4.hot-update.js": "/js/main.5ca3431d17a903e5dae4.hot-update.js",
"/js/main.ac8b2be1c1abcc0327dc.hot-update.js": "/js/main.ac8b2be1c1abcc0327dc.hot-update.js",
"/js/main.06e4b8a06af109921c82.hot-update.js": "/js/main.06e4b8a06af109921c82.hot-update.js",
"/js/main.9baa3c23f69a94e0b5ad.hot-update.js": "/js/main.9baa3c23f69a94e0b5ad.hot-update.js",
"/js/main.5822ef64e54b9209de83.hot-update.js": "/js/main.5822ef64e54b9209de83.hot-update.js",
"/js/main.213d947cbcc3f0ddabe2.hot-update.js": "/js/main.213d947cbcc3f0ddabe2.hot-update.js",
"/js/main.e6eb49612e52d6f68fa5.hot-update.js": "/js/main.e6eb49612e52d6f68fa5.hot-update.js",
"/js/main.06a6d9087f92ba28396f.hot-update.js": "/js/main.06a6d9087f92ba28396f.hot-update.js",
"/js/main.5ab6617ebf4ac899b12a.hot-update.js": "/js/main.5ab6617ebf4ac899b12a.hot-update.js",
"/js/main.6ad11678d55922bb484d.hot-update.js": "/js/main.6ad11678d55922bb484d.hot-update.js",
"/js/main.a3f8b0e0ceef8ef3b710.hot-update.js": "/js/main.a3f8b0e0ceef8ef3b710.hot-update.js",
"/js/main.1cc5c4295c61f0856f9d.hot-update.js": "/js/main.1cc5c4295c61f0856f9d.hot-update.js",
"/js/main.c665b5fc70a69f41abe4.hot-update.js": "/js/main.c665b5fc70a69f41abe4.hot-update.js",
"/js/main.293834e2b76a7f705b38.hot-update.js": "/js/main.293834e2b76a7f705b38.hot-update.js",
"/js/main.0a1c66ffda84f6244db2.hot-update.js": "/js/main.0a1c66ffda84f6244db2.hot-update.js",
"/js/main.9da787fd6d37b9cf6b0d.hot-update.js": "/js/main.9da787fd6d37b9cf6b0d.hot-update.js",
"/js/main.865f8c7aa478fdc0403c.hot-update.js": "/js/main.865f8c7aa478fdc0403c.hot-update.js",
"/js/main.847c9bc6bbf4ad7dfa13.hot-update.js": "/js/main.847c9bc6bbf4ad7dfa13.hot-update.js",
"/js/main.357e30500e48699429ff.hot-update.js": "/js/main.357e30500e48699429ff.hot-update.js",
"/js/main.a25e763451c1a4436288.hot-update.js": "/js/main.a25e763451c1a4436288.hot-update.js",
"/js/main.32e7df5e1300cd27fd38.hot-update.js": "/js/main.32e7df5e1300cd27fd38.hot-update.js",
"/js/main.32ea6e6436c28641e78b.hot-update.js": "/js/main.32ea6e6436c28641e78b.hot-update.js",
"/js/main.08e0c0adedd226a4eedb.hot-update.js": "/js/main.08e0c0adedd226a4eedb.hot-update.js",
"/js/main.78664d675fff7ea43452.hot-update.js": "/js/main.78664d675fff7ea43452.hot-update.js",
"/js/main.eaed9db22000c5d16fec.hot-update.js": "/js/main.eaed9db22000c5d16fec.hot-update.js",
"/js/main.0e05f46777d4a99fe594.hot-update.js": "/js/main.0e05f46777d4a99fe594.hot-update.js",
"/js/main.3cf4c81de9c1ed3d009b.hot-update.js": "/js/main.3cf4c81de9c1ed3d009b.hot-update.js",
"/js/main.3b1bdc22c339357c813f.hot-update.js": "/js/main.3b1bdc22c339357c813f.hot-update.js",
"/js/main.2139e17ae489f5a0ec09.hot-update.js": "/js/main.2139e17ae489f5a0ec09.hot-update.js",
"/js/main.bc5d4d6ceeefe6bf49dc.hot-update.js": "/js/main.bc5d4d6ceeefe6bf49dc.hot-update.js",
"/js/main.3a860712dcfd80c34a59.hot-update.js": "/js/main.3a860712dcfd80c34a59.hot-update.js",
"/js/main.033529d501b9a9e2ca25.hot-update.js": "/js/main.033529d501b9a9e2ca25.hot-update.js",
"/js/main.e870de84740494ac895b.hot-update.js": "/js/main.e870de84740494ac895b.hot-update.js",
"/js/main.918c797daa15df9fded1.hot-update.js": "/js/main.918c797daa15df9fded1.hot-update.js",
"/js/main.22c4dbc3a443023318da.hot-update.js": "/js/main.22c4dbc3a443023318da.hot-update.js",
"/js/main.005cfff54dbee629f505.hot-update.js": "/js/main.005cfff54dbee629f505.hot-update.js",
"/js/main.6f7967a34dc8a961b327.hot-update.js": "/js/main.6f7967a34dc8a961b327.hot-update.js",
"/js/main.479ceaebee83e41a5ade.hot-update.js": "/js/main.479ceaebee83e41a5ade.hot-update.js",
"/js/main.a20acf70f18ebdd66447.hot-update.js": "/js/main.a20acf70f18ebdd66447.hot-update.js",
"/js/main.ee332693faa2218fb662.hot-update.js": "/js/main.ee332693faa2218fb662.hot-update.js",
"/js/main.9d2b4b00f63f83496122.hot-update.js": "/js/main.9d2b4b00f63f83496122.hot-update.js",
"/js/main.14055957de8219277cf2.hot-update.js": "/js/main.14055957de8219277cf2.hot-update.js",
"/js/main.1d042c41bb9132120809.hot-update.js": "/js/main.1d042c41bb9132120809.hot-update.js",
"/js/main.33cde9abbbdf337fa042.hot-update.js": "/js/main.33cde9abbbdf337fa042.hot-update.js",
"/js/main.a7162761be0f4213da47.hot-update.js": "/js/main.a7162761be0f4213da47.hot-update.js",
"/js/main.6e0e492148c23360c4ad.hot-update.js": "/js/main.6e0e492148c23360c4ad.hot-update.js",
"/js/main.0627042acb7ded093af9.hot-update.js": "/js/main.0627042acb7ded093af9.hot-update.js",
"/js/main.c8379f58424b233f021e.hot-update.js": "/js/main.c8379f58424b233f021e.hot-update.js",
"/js/main.ee495d19d310fd76d796.hot-update.js": "/js/main.ee495d19d310fd76d796.hot-update.js",
"/js/main.443446feba272089fbe5.hot-update.js": "/js/main.443446feba272089fbe5.hot-update.js",
"/js/main.0a8e2d5c71cd84bcafa5.hot-update.js": "/js/main.0a8e2d5c71cd84bcafa5.hot-update.js",
"/js/main.ae62fecbaca54f248911.hot-update.js": "/js/main.ae62fecbaca54f248911.hot-update.js",
"/js/main.ac2be1471f24e4d4ba24.hot-update.js": "/js/main.ac2be1471f24e4d4ba24.hot-update.js",
"/js/main.6fe33464860d885096e0.hot-update.js": "/js/main.6fe33464860d885096e0.hot-update.js",
"/js/main.cd23d51469b76577cd44.hot-update.js": "/js/main.cd23d51469b76577cd44.hot-update.js",
"/js/main.597db468fc7721bde000.hot-update.js": "/js/main.597db468fc7721bde000.hot-update.js",
"/js/main.deb9e4b4f44cda4e874c.hot-update.js": "/js/main.deb9e4b4f44cda4e874c.hot-update.js",
"/js/main.4eca7117450e797fb033.hot-update.js": "/js/main.4eca7117450e797fb033.hot-update.js",
"/js/main.836b40243606ace4caf7.hot-update.js": "/js/main.836b40243606ace4caf7.hot-update.js",
"/js/main.b3bc3a73412a51ef454a.hot-update.js": "/js/main.b3bc3a73412a51ef454a.hot-update.js",
"/js/main.92750ee5fc3e1003361c.hot-update.js": "/js/main.92750ee5fc3e1003361c.hot-update.js",
"/js/main.35dd99c6164ae958964e.hot-update.js": "/js/main.35dd99c6164ae958964e.hot-update.js",
"/js/main.721ccf8c6f1a9f27f7e6.hot-update.js": "/js/main.721ccf8c6f1a9f27f7e6.hot-update.js",
"/js/main.1f2c1f70a54b1f4a9c30.hot-update.js": "/js/main.1f2c1f70a54b1f4a9c30.hot-update.js",
"/js/main.8281e75f5ab1a6823519.hot-update.js": "/js/main.8281e75f5ab1a6823519.hot-update.js",
"/js/main.0768e908f1f2c29e02e3.hot-update.js": "/js/main.0768e908f1f2c29e02e3.hot-update.js",
"/js/main.9225c3f05bc4dc4ee3f7.hot-update.js": "/js/main.9225c3f05bc4dc4ee3f7.hot-update.js",
"/js/main.fcc822857e917b9de3c5.hot-update.js": "/js/main.fcc822857e917b9de3c5.hot-update.js",
"/js/main.9e6cc2423230d3bad63a.hot-update.js": "/js/main.9e6cc2423230d3bad63a.hot-update.js",
"/js/main.92d5d0453b3362391ba1.hot-update.js": "/js/main.92d5d0453b3362391ba1.hot-update.js",
"/js/main.df2161c49a65f59cc814.hot-update.js": "/js/main.df2161c49a65f59cc814.hot-update.js",
"/js/main.8e2c35d2851b9f6e093e.hot-update.js": "/js/main.8e2c35d2851b9f6e093e.hot-update.js",
"/js/main.ee6ea14ade1aa0517972.hot-update.js": "/js/main.ee6ea14ade1aa0517972.hot-update.js",
"/js/main.beed37bf065c800da07c.hot-update.js": "/js/main.beed37bf065c800da07c.hot-update.js",
"/js/main.af2f39ea90ae11a196ce.hot-update.js": "/js/main.af2f39ea90ae11a196ce.hot-update.js",
"/js/main.c6164a4f084321d65d93.hot-update.js": "/js/main.c6164a4f084321d65d93.hot-update.js",
"/js/main.c2e596f91cdb037dbfa3.hot-update.js": "/js/main.c2e596f91cdb037dbfa3.hot-update.js",
"/js/main.1049fc5f8a8c9a2f73f1.hot-update.js": "/js/main.1049fc5f8a8c9a2f73f1.hot-update.js",
"/js/main.ea031f841752fa33de34.hot-update.js": "/js/main.ea031f841752fa33de34.hot-update.js",
"/js/main.8ca99c2bdc4900b71d75.hot-update.js": "/js/main.8ca99c2bdc4900b71d75.hot-update.js",
"/js/main.e2c88b3ebc170d555ab3.hot-update.js": "/js/main.e2c88b3ebc170d555ab3.hot-update.js",
"/js/main.df4f07672b66f5362b6c.hot-update.js": "/js/main.df4f07672b66f5362b6c.hot-update.js",
"/js/main.52bd67b62e3b204ff75f.hot-update.js": "/js/main.52bd67b62e3b204ff75f.hot-update.js",
"/js/main.9df3c750abbdf710fdf6.hot-update.js": "/js/main.9df3c750abbdf710fdf6.hot-update.js",
"/js/main.6a799e06681bac8a9936.hot-update.js": "/js/main.6a799e06681bac8a9936.hot-update.js",
"/js/main.33171569b8a14f3177c5.hot-update.js": "/js/main.33171569b8a14f3177c5.hot-update.js",
"/js/main.3b24e8ee819c583b4711.hot-update.js": "/js/main.3b24e8ee819c583b4711.hot-update.js",
"/js/main.19658b188ad9b89b1291.hot-update.js": "/js/main.19658b188ad9b89b1291.hot-update.js",
"/js/main.0f33df348a32c0b85b51.hot-update.js": "/js/main.0f33df348a32c0b85b51.hot-update.js",
"/js/main.dcd9fa74a9b8fb50721c.hot-update.js": "/js/main.dcd9fa74a9b8fb50721c.hot-update.js",
"/js/main.c95068df5ce07b66fea1.hot-update.js": "/js/main.c95068df5ce07b66fea1.hot-update.js",
"/js/main.a3458d59bdadd34e7332.hot-update.js": "/js/main.a3458d59bdadd34e7332.hot-update.js",
"/js/main.64f59bbf5718479f5c1a.hot-update.js": "/js/main.64f59bbf5718479f5c1a.hot-update.js",
"/js/main.85e70811c03956265a4a.hot-update.js": "/js/main.85e70811c03956265a4a.hot-update.js",
"/js/main.18117fa6c58f27fa1550.hot-update.js": "/js/main.18117fa6c58f27fa1550.hot-update.js",
"/js/main.8dbb00ce91497aebf928.hot-update.js": "/js/main.8dbb00ce91497aebf928.hot-update.js",
"/js/main.cbaf2d1fdd9887442320.hot-update.js": "/js/main.cbaf2d1fdd9887442320.hot-update.js",
"/js/main.97d8dbec3784ef41b8de.hot-update.js": "/js/main.97d8dbec3784ef41b8de.hot-update.js",
"/js/main.3bb9e845b47af251d98c.hot-update.js": "/js/main.3bb9e845b47af251d98c.hot-update.js",
"/js/main.92b3e383e6f53242ad8f.hot-update.js": "/js/main.92b3e383e6f53242ad8f.hot-update.js",
"/js/main.224e8c595ad8212532dc.hot-update.js": "/js/main.224e8c595ad8212532dc.hot-update.js",
"/js/main.d5d306a7fb721e5b568b.hot-update.js": "/js/main.d5d306a7fb721e5b568b.hot-update.js",
"/js/main.fd75a70cdfee4df31e3d.hot-update.js": "/js/main.fd75a70cdfee4df31e3d.hot-update.js",
"/js/main.0e90c7c25050b0901e22.hot-update.js": "/js/main.0e90c7c25050b0901e22.hot-update.js",
"/js/main.e5f0c4a2d082e6ed582a.hot-update.js": "/js/main.e5f0c4a2d082e6ed582a.hot-update.js",
"/js/main.ec4b3cf54c23e7a67fdf.hot-update.js": "/js/main.ec4b3cf54c23e7a67fdf.hot-update.js",
"/js/main.6ec5aa28087299c4e856.hot-update.js": "/js/main.6ec5aa28087299c4e856.hot-update.js",
"/js/main.a38904ba2f1080ce202d.hot-update.js": "/js/main.a38904ba2f1080ce202d.hot-update.js",
"/js/main.7db0b0759803351fa5a8.hot-update.js": "/js/main.7db0b0759803351fa5a8.hot-update.js",
"/js/main.304a51e1c9a5dd60ef1f.hot-update.js": "/js/main.304a51e1c9a5dd60ef1f.hot-update.js",
"/js/main.901b82d4317258ea1c53.hot-update.js": "/js/main.901b82d4317258ea1c53.hot-update.js",
"/js/main.497e4e7fb9d33a44d93e.hot-update.js": "/js/main.497e4e7fb9d33a44d93e.hot-update.js",
"/js/main.57b63d01d97fa279f5b5.hot-update.js": "/js/main.57b63d01d97fa279f5b5.hot-update.js",
"/js/main.b7ff67de50c1df9bb09d.hot-update.js": "/js/main.b7ff67de50c1df9bb09d.hot-update.js",
"/js/main.aa8688f0e56f8b3e23f9.hot-update.js": "/js/main.aa8688f0e56f8b3e23f9.hot-update.js",
"/js/main.61483e331d7628ffea3c.hot-update.js": "/js/main.61483e331d7628ffea3c.hot-update.js",
"/js/main.2d5aa09f0165d80526fd.hot-update.js": "/js/main.2d5aa09f0165d80526fd.hot-update.js",
"/js/main.2ebd8f430597b13b630a.hot-update.js": "/js/main.2ebd8f430597b13b630a.hot-update.js",
"/js/main.f6c19a18e72765f9a229.hot-update.js": "/js/main.f6c19a18e72765f9a229.hot-update.js",
"/js/main.d3bfbed0ec0028cb0428.hot-update.js": "/js/main.d3bfbed0ec0028cb0428.hot-update.js",
"/js/main.d47df9461115ef02036f.hot-update.js": "/js/main.d47df9461115ef02036f.hot-update.js",
"/js/main.73cd57634d0f137050ca.hot-update.js": "/js/main.73cd57634d0f137050ca.hot-update.js",
"/js/main.ea50f373ba7287f8fcec.hot-update.js": "/js/main.ea50f373ba7287f8fcec.hot-update.js",
"/js/main.780bd95f63fdce648807.hot-update.js": "/js/main.780bd95f63fdce648807.hot-update.js",
"/js/main.2511471d932786e69741.hot-update.js": "/js/main.2511471d932786e69741.hot-update.js",
"/js/main.e6fe9ef69de6247618e4.hot-update.js": "/js/main.e6fe9ef69de6247618e4.hot-update.js",
"/js/main.a059aae251c2a60e35fa.hot-update.js": "/js/main.a059aae251c2a60e35fa.hot-update.js",
"/js/main.7d2c4d9d7ede9b195ad6.hot-update.js": "/js/main.7d2c4d9d7ede9b195ad6.hot-update.js",
"/js/main.3b27e3dfc95158d78f41.hot-update.js": "/js/main.3b27e3dfc95158d78f41.hot-update.js",
"/js/main.3db5bb5180473c4f9981.hot-update.js": "/js/main.3db5bb5180473c4f9981.hot-update.js",
"/js/main.e3064029ae8fff3e24e0.hot-update.js": "/js/main.e3064029ae8fff3e24e0.hot-update.js",
"/js/main.724b4ccde32156d48650.hot-update.js": "/js/main.724b4ccde32156d48650.hot-update.js",
"/js/main.b669b01458144dedf1ed.hot-update.js": "/js/main.b669b01458144dedf1ed.hot-update.js",
"/js/main.3ebc6636e9b6580176ef.hot-update.js": "/js/main.3ebc6636e9b6580176ef.hot-update.js",
"/js/main.af6ced35684c6ad3a53c.hot-update.js": "/js/main.af6ced35684c6ad3a53c.hot-update.js",
"/js/main.5147fb055a4e390b206c.hot-update.js": "/js/main.5147fb055a4e390b206c.hot-update.js",
"/js/main.52bcb577491bdee1e509.hot-update.js": "/js/main.52bcb577491bdee1e509.hot-update.js",
"/js/main.af9a25403871667c883e.hot-update.js": "/js/main.af9a25403871667c883e.hot-update.js",
"/js/main.dbd2c30f3868860def45.hot-update.js": "/js/main.dbd2c30f3868860def45.hot-update.js",
"/js/main.1ac32029b0ef21cb8d44.hot-update.js": "/js/main.1ac32029b0ef21cb8d44.hot-update.js",
"/js/main.0bcbc8497cb962299815.hot-update.js": "/js/main.0bcbc8497cb962299815.hot-update.js",
"/js/main.177edbc74755c0b26289.hot-update.js": "/js/main.177edbc74755c0b26289.hot-update.js",
"/js/main.16b565aad7c618074b80.hot-update.js": "/js/main.16b565aad7c618074b80.hot-update.js",
"/js/main.50226ddbf0e191df338b.hot-update.js": "/js/main.50226ddbf0e191df338b.hot-update.js",
"/js/main.b85f0c073a0becc8950e.hot-update.js": "/js/main.b85f0c073a0becc8950e.hot-update.js",
"/js/main.88f96a34e9921d36d9b1.hot-update.js": "/js/main.88f96a34e9921d36d9b1.hot-update.js",
"/js/main.758c6b91d4be63105d03.hot-update.js": "/js/main.758c6b91d4be63105d03.hot-update.js",
"/js/main.0cea0f2ec0077ec93401.hot-update.js": "/js/main.0cea0f2ec0077ec93401.hot-update.js",
"/js/main.92e39411babd7e72c72a.hot-update.js": "/js/main.92e39411babd7e72c72a.hot-update.js",
"/js/main.4e386766ef0c2d277b6b.hot-update.js": "/js/main.4e386766ef0c2d277b6b.hot-update.js",
"/js/main.7917fee1daaffbc31e35.hot-update.js": "/js/main.7917fee1daaffbc31e35.hot-update.js",
"/js/main.fe1618b8df6ec204cab2.hot-update.js": "/js/main.fe1618b8df6ec204cab2.hot-update.js",
"/js/main.2cd9f63bf0d43e7148d2.hot-update.js": "/js/main.2cd9f63bf0d43e7148d2.hot-update.js",
"/js/main.518074fbc907d4017f70.hot-update.js": "/js/main.518074fbc907d4017f70.hot-update.js",
"/js/main.7dd9fe7c54dbee4520c9.hot-update.js": "/js/main.7dd9fe7c54dbee4520c9.hot-update.js",
"/js/main.c50c2bdab81c3e8dadd3.hot-update.js": "/js/main.c50c2bdab81c3e8dadd3.hot-update.js",
"/js/main.8c77b46f07ae9c304b33.hot-update.js": "/js/main.8c77b46f07ae9c304b33.hot-update.js",
"/js/main.3c3128c4aca4cb5a2658.hot-update.js": "/js/main.3c3128c4aca4cb5a2658.hot-update.js",
"/js/main.a7707a95ba691d4db803.hot-update.js": "/js/main.a7707a95ba691d4db803.hot-update.js",
"/js/main.c10d7c511b782f5ac55a.hot-update.js": "/js/main.c10d7c511b782f5ac55a.hot-update.js",
"/js/main.0f2c49b1045bd0a436e4.hot-update.js": "/js/main.0f2c49b1045bd0a436e4.hot-update.js",
"/js/main.dba3d626a3c5055e72c7.hot-update.js": "/js/main.dba3d626a3c5055e72c7.hot-update.js",
"/js/main.124319628e4d177a457e.hot-update.js": "/js/main.124319628e4d177a457e.hot-update.js",
"/js/main.0ee8ac9d83933c29f45d.hot-update.js": "/js/main.0ee8ac9d83933c29f45d.hot-update.js",
"/js/main.1861aa984800939f39d9.hot-update.js": "/js/main.1861aa984800939f39d9.hot-update.js",
"/js/main.d4142c7600c1e5b23765.hot-update.js": "/js/main.d4142c7600c1e5b23765.hot-update.js",
"/js/main.4b876ab726f63941830e.hot-update.js": "/js/main.4b876ab726f63941830e.hot-update.js",
"/js/main.ce1298b64c553bce5147.hot-update.js": "/js/main.ce1298b64c553bce5147.hot-update.js",
"/js/main.126669fa69f23f4b2e1e.hot-update.js": "/js/main.126669fa69f23f4b2e1e.hot-update.js",
"/js/main.1dc3aad59b010c3ecfaa.hot-update.js": "/js/main.1dc3aad59b010c3ecfaa.hot-update.js",
"/js/main.b6861e2411d696fc18f7.hot-update.js": "/js/main.b6861e2411d696fc18f7.hot-update.js",
"/js/main.3b9519c66ea3ae751920.hot-update.js": "/js/main.3b9519c66ea3ae751920.hot-update.js",
"/js/main.293d111adda10d8cf051.hot-update.js": "/js/main.293d111adda10d8cf051.hot-update.js",
"/js/main.d834fdf285e5259e659f.hot-update.js": "/js/main.d834fdf285e5259e659f.hot-update.js",
"/js/main.25320ecaa68f65cf39d8.hot-update.js": "/js/main.25320ecaa68f65cf39d8.hot-update.js",
"/js/main.b345766be64fdbd77fad.hot-update.js": "/js/main.b345766be64fdbd77fad.hot-update.js",
"/js/main.73a62d68c6aa716d4442.hot-update.js": "/js/main.73a62d68c6aa716d4442.hot-update.js",
"/js/main.a20280dd94ace4dfe791.hot-update.js": "/js/main.a20280dd94ace4dfe791.hot-update.js",
"/js/main.7cb118acb9c4531576bf.hot-update.js": "/js/main.7cb118acb9c4531576bf.hot-update.js",
"/js/main.94721e0268654221490d.hot-update.js": "/js/main.94721e0268654221490d.hot-update.js",
"/js/main.d188ccf0643fd0323c99.hot-update.js": "/js/main.d188ccf0643fd0323c99.hot-update.js",
"/js/main.79c779b79d5fdc43cb7a.hot-update.js": "/js/main.79c779b79d5fdc43cb7a.hot-update.js",
"/js/main.751b2d66fcc7795387b8.hot-update.js": "/js/main.751b2d66fcc7795387b8.hot-update.js",
"/js/main.f865ed47daf098ce851b.hot-update.js": "/js/main.f865ed47daf098ce851b.hot-update.js",
"/js/main.fde8c29fa890fafb6918.hot-update.js": "/js/main.fde8c29fa890fafb6918.hot-update.js",
"/js/main.fc020c4b1a85703ba2fd.hot-update.js": "/js/main.fc020c4b1a85703ba2fd.hot-update.js",
"/js/main.12e914b5398fed5263c3.hot-update.js": "/js/main.12e914b5398fed5263c3.hot-update.js",
"/js/main.a9e85de5f20a914d9792.hot-update.js": "/js/main.a9e85de5f20a914d9792.hot-update.js",
"/js/main.6b7625a214c48be0e8fe.hot-update.js": "/js/main.6b7625a214c48be0e8fe.hot-update.js",
"/js/main.081425b1a319a39ba57d.hot-update.js": "/js/main.081425b1a319a39ba57d.hot-update.js",
"/js/main.83b69a601e558b4c66dd.hot-update.js": "/js/main.83b69a601e558b4c66dd.hot-update.js",
"/js/main.cd56ccae0a8d70d9fbb5.hot-update.js": "/js/main.cd56ccae0a8d70d9fbb5.hot-update.js",
"/js/main.fddc2d35c7100276599f.hot-update.js": "/js/main.fddc2d35c7100276599f.hot-update.js",
"/js/main.545aae91e9ba07a7fd33.hot-update.js": "/js/main.545aae91e9ba07a7fd33.hot-update.js",
"/js/main.73b0d6729b2068f1605e.hot-update.js": "/js/main.73b0d6729b2068f1605e.hot-update.js",
"/js/main.80906e773a38b7d3a2d7.hot-update.js": "/js/main.80906e773a38b7d3a2d7.hot-update.js",
"/js/main.3e6fac83667df2a5aa9a.hot-update.js": "/js/main.3e6fac83667df2a5aa9a.hot-update.js",
"/js/main.06d8baefc20e76dc93ae.hot-update.js": "/js/main.06d8baefc20e76dc93ae.hot-update.js",
"/js/main.63019f721aff16c32040.hot-update.js": "/js/main.63019f721aff16c32040.hot-update.js",
"/js/main.2668706d7ae6ba7e57d7.hot-update.js": "/js/main.2668706d7ae6ba7e57d7.hot-update.js",
"/js/main.7c95c0035cf9ef725975.hot-update.js": "/js/main.7c95c0035cf9ef725975.hot-update.js",
"/js/main.25e6f3570af5d6997c3b.hot-update.js": "/js/main.25e6f3570af5d6997c3b.hot-update.js",
"/js/main.833de212f7174cf943d0.hot-update.js": "/js/main.833de212f7174cf943d0.hot-update.js",
"/js/main.42f1f72fc008c3d55328.hot-update.js": "/js/main.42f1f72fc008c3d55328.hot-update.js",
"/js/main.c30865644e19484ffdb2.hot-update.js": "/js/main.c30865644e19484ffdb2.hot-update.js",
"/js/main.093932c5788754777120.hot-update.js": "/js/main.093932c5788754777120.hot-update.js",
"/js/main.68a0f6d8fb9a63f25a63.hot-update.js": "/js/main.68a0f6d8fb9a63f25a63.hot-update.js",
"/js/main.dde11d552c1431c3c013.hot-update.js": "/js/main.dde11d552c1431c3c013.hot-update.js",
"/js/main.751b0c260d1129f5fdd0.hot-update.js": "/js/main.751b0c260d1129f5fdd0.hot-update.js",
"/js/main.29d30192df173c07196b.hot-update.js": "/js/main.29d30192df173c07196b.hot-update.js",
"/js/main.60764aab6c1adc329237.hot-update.js": "/js/main.60764aab6c1adc329237.hot-update.js",
"/js/main.3ba38878f8e0401a6622.hot-update.js": "/js/main.3ba38878f8e0401a6622.hot-update.js",
"/js/main.0ac7209eec896afa5fd7.hot-update.js": "/js/main.0ac7209eec896afa5fd7.hot-update.js",
"/js/main.7c43b93309d76b9c689e.hot-update.js": "/js/main.7c43b93309d76b9c689e.hot-update.js",
"/js/main.6b0d4d6682db03e57a7e.hot-update.js": "/js/main.6b0d4d6682db03e57a7e.hot-update.js",
"/js/main.bae2bbea92c87bbe9b6e.hot-update.js": "/js/main.bae2bbea92c87bbe9b6e.hot-update.js",
"/js/main.15d07623969b0491f4a0.hot-update.js": "/js/main.15d07623969b0491f4a0.hot-update.js",
"/js/main.a0152fd5be092487b17a.hot-update.js": "/js/main.a0152fd5be092487b17a.hot-update.js",
"/js/main.4c881d50bd3c151afc7e.hot-update.js": "/js/main.4c881d50bd3c151afc7e.hot-update.js",
"/js/main.4a24e98b1e515772aba1.hot-update.js": "/js/main.4a24e98b1e515772aba1.hot-update.js",
"/js/main.79741fe597e91dc1543e.hot-update.js": "/js/main.79741fe597e91dc1543e.hot-update.js",
"/js/main.cef63d6a6cac0a6f6a11.hot-update.js": "/js/main.cef63d6a6cac0a6f6a11.hot-update.js",
"/js/main.cbfd2196668397b14480.hot-update.js": "/js/main.cbfd2196668397b14480.hot-update.js",
"/js/main.4ddd8429fdd59155d1c3.hot-update.js": "/js/main.4ddd8429fdd59155d1c3.hot-update.js",
"/js/main.bf31b90c9bef9eacbfc6.hot-update.js": "/js/main.bf31b90c9bef9eacbfc6.hot-update.js",
"/js/main.84d101ec6f861c3727d7.hot-update.js": "/js/main.84d101ec6f861c3727d7.hot-update.js",
"/js/main.0dc92a7ac7bacc039422.hot-update.js": "/js/main.0dc92a7ac7bacc039422.hot-update.js",
"/js/main.821175555d08638e00e9.hot-update.js": "/js/main.821175555d08638e00e9.hot-update.js",
"/js/main.150365f52e29e60ad89e.hot-update.js": "/js/main.150365f52e29e60ad89e.hot-update.js",
"/js/main.018aa3ac776b804d86f6.hot-update.js": "/js/main.018aa3ac776b804d86f6.hot-update.js"
}

View File

@@ -122,7 +122,7 @@
</script>
<style lang="scss">
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@200;300;400;600;700;900&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@200;300;400;600;700;800;900&display=swap');
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';

View File

@@ -0,0 +1,127 @@
<template>
<WidgetWrapper :icon="icon" :title="title">
<DatatableWrapper v-if="users" :paginator="false" :columns="columns" :data="users" class="table table-users">
<template scope="{ row }">
<tr>
<td style="width: 300px">
<router-link :to="{name: 'UserDetail', params: {id: row.data.id}}">
<DatatableCellImage
:image="row.data.attributes.avatar"
:title="row.data.attributes.name"
:description="row.data.attributes.email"
/>
</router-link>
</td>
<td>
<ColorLabel :color="getRoleColor(row.data.attributes.role)">
{{ row.data.attributes.role }}
</ColorLabel>
</td>
<td>
<span class="cell-item">
{{ row.relationships.storage.data.attributes.used }}%
</span>
</td>
<td>
<span class="cell-item">
{{ row.data.attributes.created_at_formatted }}
</span>
</td>
<td>
<div class="action-icons">
<router-link :to="{name: 'UserDetail', params: {id: row.data.id}}">
<edit-2-icon size="15" class="icon icon-edit"></edit-2-icon>
</router-link>
<router-link :to="{name: 'UserDelete', params: {id: row.data.id}}">
<trash2-icon size="15" class="icon icon-trash"></trash2-icon>
</router-link>
</div>
</td>
</tr>
</template>
</DatatableWrapper>
</WidgetWrapper>
</template>
<script>
import DatatableCellImage from '@/components/Others/Tables/DatatableCellImage'
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import WidgetWrapper from '@/components/Admin/WidgetWrapper'
import {Trash2Icon, Edit2Icon} from "vue-feather-icons"
import ColorLabel from '@/components/Others/ColorLabel'
import axios from 'axios'
export default {
name: 'WidgetLatestRegistrations',
props: ['icon', 'title'],
components: {
DatatableCellImage,
DatatableWrapper,
WidgetWrapper,
Trash2Icon,
ColorLabel,
Edit2Icon,
},
data() {
return {
isLoading: false,
users: undefined,
columns: [
{
label: this.$t('admin_page_user.table.name'),
field: 'data.attributes.name',
sortable: true
},
{
label: this.$t('admin_page_user.table.role'),
field: 'data.attributes.role',
sortable: true
},
{
label: this.$t('admin_page_user.table.storage_used'),
field: 'data.attributes.storage.used',
sortable: true
},
{
label: this.$t('admin_page_user.table.created_at'),
field: 'data.attributes.created_at_formatted',
sortable: true
},
{
label: this.$t('admin_page_user.table.action'),
field: 'data.action',
sortable: false
},
]
}
},
methods: {
getRoleColor(role) {
switch(role) {
case 'admin':
return 'purple'
break;
case 'user':
return 'yellow'
break;
}
}
},
created() {
axios.get('/api/dashboard/new-users')
.then(response => {
this.users = response.data.data
this.isLoading = false
})
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
@media (prefers-color-scheme: dark) {
}
</style>

View File

@@ -0,0 +1,62 @@
<template>
<WidgetWrapper :icon="icon" :title="title">
<div class="widget-value">
<span>{{ value }}</span>
</div>
<router-link :to="{name: linkRoute}" class="footer-link">
<span class="content">{{ linkName }}</span>
<chevron-right-icon size="16"></chevron-right-icon>
</router-link>
</WidgetWrapper>
</template>
<script>
import WidgetWrapper from '@/components/Admin/WidgetWrapper'
import { UsersIcon, StarIcon, HardDriveIcon, ChevronRightIcon } from 'vue-feather-icons'
export default {
name: 'WidgetTotals',
props: ['icon', 'title', 'value', 'linkRoute', 'linkName'],
components: {
ChevronRightIcon,
WidgetWrapper,
HardDriveIcon,
StarIcon,
UsersIcon
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.widget-value {
margin-top: 10px;
margin-bottom: 30px;
span {
@include font-size(38);
font-weight: 800;
}
}
.footer-link {
display: flex;
align-items: center;
polyline {
stroke: $theme;
}
.content {
@include font-size(12);
font-weight: 700;
margin-right: 5px;
}
}
@media (prefers-color-scheme: dark) {
}
</style>

View File

@@ -0,0 +1,55 @@
<template>
<div class="widget">
<div class="widget-content">
<div class="headline">
<div class="icon">
<users-icon v-if="icon === 'users'" size="19"></users-icon>
<star-icon v-if="icon === 'star'" size="19"></star-icon>
<hard-drive-icon v-if="icon === 'hard-drive'" size="19"></hard-drive-icon>
</div>
<b class="title">{{ title }}</b>
</div>
<slot></slot>
</div>
</div>
</template>
<script>
import { UsersIcon, StarIcon, HardDriveIcon, ChevronRightIcon } from 'vue-feather-icons'
export default {
name: 'WidgetWrapper',
props: ['icon', 'title'],
components: {
ChevronRightIcon,
HardDriveIcon,
StarIcon,
UsersIcon
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.widget-content {
@include widget-card;
}
.headline {
display: flex;
.icon {
margin-right: 10px;
path, circle, line, polygon {
stroke: $theme;
}
}
.title {
color: $theme;
}
}
</style>

View File

@@ -1,16 +1,23 @@
<template>
<button class="button-base" :class="buttonStyle" type="button">
<span v-if="loading" class="icon">
<FontAwesomeIcon icon="sync-alt" class="sync-alt"/>
</span>
<slot v-if="! loading"></slot>
<div v-if="loading" class="icon">
<refresh-cw-icon size="16" class="sync-alt"></refresh-cw-icon>
</div>
<div class="content">
<slot v-if="! loading"></slot>
</div>
</button>
</template>
<script>
import { RefreshCwIcon } from 'vue-feather-icons'
export default {
name: 'ButtonBase',
props: ['buttonStyle', 'loading']
props: ['buttonStyle', 'loading'],
components: {
RefreshCwIcon,
}
}
</script>
@@ -26,40 +33,81 @@
border-radius: 8px;
border: 0;
padding: 10px 28px;
display: inline-block;
white-space: nowrap;
display: flex;
align-items: center;
.icon {
line-height: 1;
margin-right: 10px;
}
.content {
width: 100%;
}
&:active {
transform: scale(0.95);
}
&.theme {
color: $theme;
background: rgba($theme, .1);
.content {
color: $theme;
}
polyline, path {
stroke: $theme;
}
}
&.theme-solid {
color: white;
background: $theme;
path {
fill: white;
.content {
color: white;
}
polyline, path {
stroke: white;
}
}
&.danger {
color: $danger;
background: rgba($danger, .1);
.content {
color: $danger;
}
polyline, path {
stroke: $danger;
}
}
&.danger-solid {
color: white;
background: $danger;
.content {
color: white;
}
polyline, path {
stroke: white;
}
}
&.secondary {
color: $text;
background: $light_background;
.content {
color: $text;
}
polyline, path {
stroke: $text;
}
}
}

View File

@@ -0,0 +1,68 @@
<template>
<div class="empty-page-content">
<div class="content">
<div class="icon">
<file-icon v-if="icon === 'file'" size="38"></file-icon>
<file-text-icon v-if="icon === 'file-text'" size="38"></file-text-icon>
</div>
<div class="header">
<h1 class="title">{{ title }}</h1>
<h2 class="description">{{ description }}</h2>
</div>
<slot></slot>
</div>
</div>
</template>
<script>
import { FileIcon, FileTextIcon } from 'vue-feather-icons'
export default {
name: 'EmptyPageContent',
props: ['icon','title','description'],
components: {
FileTextIcon,
FileIcon,
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.empty-page-content {
width: 100%;
height: 100%;
display: flex;
align-items: center;
text-align: center;
.content {
margin: 0 auto;
max-width: 360px;
}
.icon {
path, polyline, line {
stroke: $theme;
}
}
.header {
margin-top: 15px;
margin-bottom: 25px;
}
.title {
@include font-size(23);
font-weight: 700;
padding-bottom: 5px;
}
.description {
@include font-size(16);
font-weight: 500;
}
}
</style>

View File

@@ -120,7 +120,7 @@
height: 100%;
object-fit: contain;
left: 0;
padding: 7px;
padding: 25px;
display: block;
&.fit-image {

View File

@@ -34,6 +34,12 @@
@include font-size(15);
line-height: 1.6;
word-break: break-all;
font-weight: 600;
}
b {
font-weight: 700;
color: $theme;
}
a {

View File

@@ -120,6 +120,7 @@
.sign-in-button {
width: 100%;
text-align: center;
}
.price {

View File

@@ -32,7 +32,7 @@
</div>
</router-link>
<router-link v-if="user.data.attributes.role === 'admin'" :to="{name: 'Users'}" :class="{'is-active': $isThisRoute($route, adminRoutes)}" class="icon-navigation-item users">
<router-link v-if="user.data.attributes.role === 'admin'" :to="{name: 'Dashboard'}" :class="{'is-active': $isThisRoute($route, adminRoutes)}" class="icon-navigation-item users">
<div class="button-icon">
<settings-icon size="19"></settings-icon>
</div>
@@ -82,16 +82,21 @@
data() {
return {
adminRoutes: [
'AppSettings',
'AppAppearance',
'AppBillings',
'AppEmail',
'AppOthers',
'Dashboard',
'PlanSubscribers',
'PlanCreate',
'PlanSettings',
'PlanDelete',
'GatewayTransactions',
'GatewaySettings',
'UserInvoices',
'UserSubscription',
'UserInvoices',
'UserPassword',
'UserStorage',
'UserDelete',
'PlanCreate',
'UserCreate',
'UserDelete',

View File

@@ -20,16 +20,13 @@ const Helpers = {
})
}, 300)
Vue.prototype.$getCreditCardBrand = function (brand) {
return `/assets/icons/${brand}.svg`
}
Vue.prototype.$updateImage = function (route, name, image) {
// Create form
let formData = new FormData()
// Add image to form
formData.append('name', name)
formData.append(name, image)
formData.append('_method', 'PATCH')
@@ -46,6 +43,14 @@ const Helpers = {
})
}
Vue.prototype.$getCreditCardBrand = function (brand) {
return `/assets/icons/${brand}.svg`
}
Vue.prototype.$getInvoiceLink = function (customer, id) {
return '/invoice/' + customer + '/' + id
}
Vue.prototype.$openImageOnNewTab = function (source) {
let win = window.open(source, '_blank')

View File

@@ -29,6 +29,7 @@ import UserProfileMobileMenu from './views/Mobile/UserProfileMobileMenu'
import Admin from './views/Admin'
import Invoices from './views/Admin/Invoices'
import Dashboard from './views/Admin/Dashboard'
import AppSettings from './views/Admin/AppSettings/AppSettings'
// App Settings
@@ -81,6 +82,15 @@ const routesAdmin = [
title: 'Admin'
},
children: [
{
name: 'Dashboard',
path: '/admin/dashboard',
component: Dashboard,
meta: {
requiresAuth: true,
title: 'Dashboard'
},
},
{
name: 'Invoices',
path: '/admin/invoices',

View File

@@ -6,6 +6,14 @@
<!--Admin-->
<ContentGroup :title="$t('admin_menu.admin_label')" class="navigator">
<div class="menu-list-wrapper vertical">
<router-link :to="{name: 'Dashboard'}" class="menu-list-item link">
<div class="icon">
<box-icon size="17"></box-icon>
</div>
<div class="label">
Dashboard
</div>
</router-link>
<router-link :to="{name: 'Users'}" class="menu-list-item link">
<div class="icon">
<users-icon size="17"></users-icon>
@@ -53,10 +61,10 @@
</template>
<script>
import { UsersIcon, SettingsIcon, FileTextIcon, CreditCardIcon, DatabaseIcon, BoxIcon } from 'vue-feather-icons'
import ContentSidebar from '@/components/Sidebar/ContentSidebar'
import ContentGroup from '@/components/Sidebar/ContentGroup'
import { mapGetters } from 'vuex'
import { UsersIcon, SettingsIcon, FileTextIcon, CreditCardIcon, DatabaseIcon } from 'vue-feather-icons'
export default {
name: 'Settings',
@@ -64,6 +72,7 @@
...mapGetters(['config']),
},
components: {
BoxIcon,
DatabaseIcon,
CreditCardIcon,
FileTextIcon,

View File

@@ -1,5 +1,5 @@
<template>
<PageTab class="form-fixed-width">
<PageTab :is-loading="isLoading" class="form-fixed-width">
<!--Personal Information-->
<PageTabGroup>
@@ -9,7 +9,7 @@
<div class="block-wrapper">
<label>App Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<input v-model="app.title" placeholder="Type your app title" type="text" :class="{'is-error': errors[0]}"/>
<input @input="$updateText('/settings', 'app_title', app.title)" v-model="app.title" placeholder="Type your app title" type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -17,22 +17,24 @@
<div class="block-wrapper">
<label>App Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
<input v-model="app.description" placeholder="Type your app description" type="text" :class="{'is-error': errors[0]}"/>
<input @input="$updateText('/settings', 'app_description', app.description)" v-model="app.description" placeholder="Type your app description" type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<FormLabel class="mt-70">Appearance</FormLabel>
<div class="block-wrapper">
<label>App Logo (optional):</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Logo" v-slot="{ errors }">
<ImageInput v-model="app.logo" :error="errors[0]"/>
<ImageInput @input="$updateImage('/settings', 'app_logo', app.logo)" :image="'/' + app.logo" v-model="app.logo" :error="errors[0]"/>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>App Favicon (optional):</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Favicon" v-slot="{ errors }">
<ImageInput v-model="app.favicon" :error="errors[0]"/>
<ImageInput @input="$updateImage('/settings', 'app_favicon', app.favicon)" :image="'/' + app.favicon" v-model="app.favicon" :error="errors[0]"/>
</ValidationProvider>
</div>
</div>
@@ -72,7 +74,7 @@
},
data() {
return {
isLoading: false,
isLoading: true,
app: {
title: '',
description: '',
@@ -80,6 +82,21 @@
favicon: undefined,
},
}
},
mounted() {
axios.get('/api/settings', {
params: {
column: 'app_title|app_description|app_logo|app_favicon'
}
})
.then(response => {
this.isLoading = false
this.app.title = response.data.app_title
this.app.description = response.data.app_description
this.app.logo = response.data.app_logo
this.app.favicon = response.data.app_favicon
})
}
}
</script>

View File

@@ -1,5 +1,5 @@
<template>
<PageTab class="form-fixed-width">
<PageTab :is-loading="isLoading" class="form-fixed-width">
<!--Personal Information-->
<PageTabGroup>
@@ -10,7 +10,7 @@
<label>Company Name:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Name"
rules="required" v-slot="{ errors }">
<input v-model="billingInformation.billing_name" placeholder="Type your company name"
<input @input="$updateText('/settings', 'billing_name', billingInformation.billing_name)" v-model="billingInformation.billing_name" placeholder="Type your company name"
type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
@@ -20,7 +20,7 @@
<label>VAT Number:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Vat Number"
rules="required" v-slot="{ errors }">
<input v-model="billingInformation.billing_vat_number" placeholder="Type your VAT number"
<input @input="$updateText('/settings', 'billing_vat_number', billingInformation.billing_vat_number)" v-model="billingInformation.billing_vat_number" placeholder="Type your VAT number"
type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
@@ -32,7 +32,7 @@
<label>Billing Country:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Country"
rules="required" v-slot="{ errors }">
<SelectInput v-model="billingInformation.billing_country" :options="countries" placeholder="Select your billing country" :isError="errors[0]"/>
<SelectInput @input="$updateText('/settings', 'billing_country', billingInformation.billing_country)" v-model="billingInformation.billing_country" :default="billingInformation.billing_country" :options="countries" placeholder="Select your billing country" :isError="errors[0]"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -41,7 +41,7 @@
<label>Billing Address:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Address"
rules="required" v-slot="{ errors }">
<input v-model="billingInformation.billing_address" placeholder="Type your billing address"
<input @input="$updateText('/settings', 'billing_address', billingInformation.billing_address)" v-model="billingInformation.billing_address" placeholder="Type your billing address"
type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
@@ -52,7 +52,7 @@
<label>Billing City:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing City"
rules="required" v-slot="{ errors }">
<input v-model="billingInformation.billing_city" placeholder="Type your billing city"
<input @input="$updateText('/settings', 'billing_city', billingInformation.billing_city)" v-model="billingInformation.billing_city" placeholder="Type your billing city"
type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
@@ -61,7 +61,7 @@
<label>Billing Postal Code:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Postal Code"
rules="required" v-slot="{ errors }">
<input v-model="billingInformation.billing_postal_code"
<input @input="$updateText('/settings', 'billing_postal_code', billingInformation.billing_postal_code)" v-model="billingInformation.billing_postal_code"
placeholder="Type your billing postal code" type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
@@ -72,7 +72,7 @@
<label>Billing State:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing State"
rules="required" v-slot="{ errors }">
<input v-model="billingInformation.billing_state" placeholder="Type your billing state"
<input @input="$updateText('/settings', 'billing_state', billingInformation.billing_state)" v-model="billingInformation.billing_state" placeholder="Type your billing state"
type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
@@ -82,7 +82,7 @@
<label>Billing Phone Number (optional):</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Phone Number"
v-slot="{ errors }">
<input v-model="billingInformation.billing_phone_number" placeholder="Type your billing phone number"
<input @input="$updateText('/settings', 'billing_phone_number', billingInformation.billing_phone_number)" v-model="billingInformation.billing_phone_number" placeholder="Type your billing phone number"
type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
@@ -124,7 +124,7 @@
},
data() {
return {
isLoading: false,
isLoading: true,
countries: [
{label: 'Afghanistan', value: 'AF'},
{label: 'Åland Islands', value: 'AX'},
@@ -381,6 +381,25 @@
billing_name: '',
}
}
},
mounted() {
axios.get('/api/settings', {
params: {
column: 'billing_phone_number|billing_postal_code|billing_vat_number|billing_address|billing_country|billing_state|billing_city|billing_name'
}
})
.then(response => {
this.isLoading = false
this.billingInformation.billing_phone_number = response.data.billing_phone_number
this.billingInformation.billing_postal_code = response.data.billing_postal_code
this.billingInformation.billing_vat_number = response.data.billing_vat_number
this.billingInformation.billing_address = response.data.billing_address
this.billingInformation.billing_country = response.data.billing_country
this.billingInformation.billing_state = response.data.billing_state
this.billingInformation.billing_city = response.data.billing_city
this.billingInformation.billing_name = response.data.billing_name
})
}
}
</script>

View File

@@ -1,11 +1,15 @@
<template>
<PageTab class="form-fixed-width">
<PageTab :is-loading="isLoading" class="form-fixed-width">
<!--Personal Information-->
<PageTabGroup>
<div class="form block-form">
<ValidationObserver @submit.prevent="EmailSetupSubmit" ref="EmailSetup" v-slot="{ invalid }" tag="form" class="form block-form">
<FormLabel>Email Setup</FormLabel>
<InfoBox>
<p>This form is not fully pre-filled for security reasons. Your email settings is available in your <b>.env</b> file. For apply new Email settings, please confirm your options by button at the end of formular.</p>
</InfoBox>
<div class="block-wrapper">
<label>Mail Driver:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Driver" rules="required" v-slot="{ errors }">
@@ -53,7 +57,12 @@
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit"
button-style="theme" class="submit-button">
Save Email Settings
</ButtonBase>
</ValidationObserver>
</PageTabGroup>
</PageTab>
</template>
@@ -70,6 +79,7 @@
import PageTab from '@/components/Others/Layout/PageTab'
import InfoBox from '@/components/Others/Forms/InfoBox'
import {required} from 'vee-validate/dist/rules'
import {events} from "@/bus"
import axios from 'axios'
export default {
@@ -90,7 +100,8 @@
},
data() {
return {
isLoading: false,
isLoading: true,
isSendingRequest: false,
encryptionList: [
{
label: 'TLS',
@@ -110,6 +121,49 @@
encryption: '',
}
}
},
methods: {
async EmailSetupSubmit() {
// Validate fields
const isValid = await this.$refs.EmailSetup.validate();
if (!isValid) return;
// Start loading
this.isSendingRequest = true
// Send request to get verify account
axios
.put('/api/settings/email', this.mail)
.then(response => {
// End loading
this.isSendingRequest = false
events.$emit('toaster', {
type: 'success',
message: 'Your email settings was updated successfully',
})
})
.catch(error => {
// End loading
this.isSendingRequest = false
})
},
},
mounted() {
axios.get('/api/settings', {
params: {
column: 'app_title|app_description|app_logo|app_favicon'
}
})
.then(response => {
this.isLoading = false
this.app.title = response.data.app_title
})
}
}
</script>

View File

@@ -1,56 +1,25 @@
<template>
<PageTab class="form-fixed-width">
<PageTab :is-loading="isLoading" class="form-fixed-width">
<!--Personal Information-->
<PageTabGroup>
<div class="form block-form">
<FormLabel>Others Settings</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">Allow User Registration:</label>
</div>
<SwitchInput v-model="app.userRegistration" class="switch" :state="app.userRegistration"/>
</div>
</div>
</div>
<div class="block-wrapper">
<label>Contact Email:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Contact Email"
rules="required" v-slot="{ errors }">
<input v-model="app.contactMail" placeholder="Type your contact email" type="email" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Google Analytics Code (optional):</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Google Analytics Code"
v-slot="{ errors }">
<input v-model="app.googleAnalytics" placeholder="Paste your Google Analytics Code"
type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<FormLabel>Users and Storage</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">Storage Limitation:</label>
</div>
<SwitchInput v-model="app.storageLimitation" class="switch" :state="app.storageLimitation"/>
<SwitchInput @input="$updateText('/settings', 'storage_limitation', app.storageLimitation)" v-model="app.storageLimitation" class="switch" :state="app.storageLimitation"/>
</div>
</div>
</div>
<div class="block-wrapper" v-if="app.storageLimitation">
<label>Default Storage Space for Accounts:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Default Storage Space" rules="required" v-slot="{ errors }">
<input v-model="app.defaultStorage"
<input @input="$updateText('/settings', 'storage_default', app.defaultStorage)"
v-model="app.defaultStorage"
min="1"
max="999999999"
placeholder="Set default storage space in GB"
@@ -60,6 +29,37 @@
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">Allow User Registration:</label>
</div>
<SwitchInput @input="$updateText('/settings', 'registration', app.userRegistration)" v-model="app.userRegistration" class="switch" :state="app.userRegistration"/>
</div>
</div>
</div>
<FormLabel class="mt-70">Others Settings</FormLabel>
<div class="block-wrapper">
<label>Contact Email:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Contact Email"
rules="required" v-slot="{ errors }">
<input @input="$updateText('/settings', 'contact_email', app.contactMail)" v-model="app.contactMail"
placeholder="Type your contact email" type="email" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Google Analytics Code (optional):</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Google Analytics Code"
v-slot="{ errors }">
<input @input="$updateText('/settings', 'google_analytics', app.googleAnalytics)" v-model="app.googleAnalytics"
placeholder="Paste your Google Analytics Code"
type="text" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
</PageTabGroup>
</PageTab>
@@ -99,7 +99,7 @@
},
data() {
return {
isLoading: false,
isLoading: true,
app: {
contactMail: '',
googleAnalytics: '',
@@ -108,6 +108,22 @@
storageLimitation: 1,
},
}
},
mounted() {
axios.get('/api/settings', {
params: {
column: 'contact_email|google_analytics|storage_default|registration|storage_limitation'
}
})
.then(response => {
this.isLoading = false
this.app.contactMail = response.data.contact_email
this.app.googleAnalytics = response.data.google_analytics
this.app.defaultStorage = response.data.storage_default
this.app.userRegistration = parseInt(response.data.registration)
this.app.storageLimitation = parseInt(response.data.storage_limitation)
})
}
}
</script>

View File

@@ -0,0 +1,198 @@
<template>
<div id="single-page">
<div id="page-content" v-if="! isLoading">
<div class="dashboard-headline">
<div class="logo">
<a href="https://vuefilemanager.com" target="_blank">
<img src="/assets/images/vuefilemanager-horizontal-logo.svg" alt="VueFileManager">
</a>
</div>
<div class="metadata">
<a href="https://vuefilemanager.com/changelog" target="_blank" class="meta">
<span class="meta-title">Version:</span>
<ColorLabel color="purple">
{{ data.app_version }}
</ColorLabel>
</a>
<a href="https://codecanyon.net/item/vue-file-manager-with-laravel-backend/25815986" target="_blank" class="meta">
<span class="meta-title">License:</span>
<ColorLabel color="purple">
Extended
</ColorLabel>
</a>
<a href="https://vuefilemanager.com" target="_blank" class="became-backer">
<div class="icon">
<credit-card-icon size="15"></credit-card-icon>
</div>
<span class="content">
Become a Backer
</span>
</a>
</div>
</div>
<div class="widgets-total">
<WidgetTotals
class="widget"
icon="users"
title="Total Users"
:value="data.total_users"
link-route="Users"
link-name="Show All Users"
></WidgetTotals>
<WidgetTotals
class="widget"
icon="hard-drive"
title="Total Space Used"
:value="data.total_used_space"
link-route="Users"
link-name="Show All Users"
></WidgetTotals>
<WidgetTotals
class="widget"
icon="star"
title="Total Premium Users"
:value="data.total_premium_users"
link-route="Plans"
link-name="Show All Plans"
></WidgetTotals>
</div>
<div class="widget-users">
<WidgetLatestRegistrations
class="widget"
icon="users"
title="Latest Registrations"
/>
</div>
</div>
<div id="loader" v-if="isLoading">
<Spinner></Spinner>
</div>
</div>
</template>
<script>
import WidgetLatestRegistrations from '@/components/Admin/WidgetLatestRegistrations'
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import MobileActionButton from '@/components/FilesView/MobileActionButton'
import EmptyPageContent from '@/components/Others/EmptyPageContent'
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import MobileHeader from '@/components/Mobile/MobileHeader'
import SectionTitle from '@/components/Others/SectionTitle'
import WidgetTotals from '@/components/Admin/WidgetTotals'
import ButtonBase from '@/components/FilesView/ButtonBase'
import PageHeader from '@/components/Others/PageHeader'
import ColorLabel from '@/components/Others/ColorLabel'
import Spinner from '@/components/FilesView/Spinner'
import {CreditCardIcon} from "vue-feather-icons"
import axios from 'axios'
export default {
name: 'Dashboard',
components: {
WidgetLatestRegistrations,
MobileActionButton,
EmptyPageContent,
DatatableWrapper,
WidgetTotals,
CreditCardIcon,
SectionTitle,
MobileHeader,
SwitchInput,
PageHeader,
ButtonBase,
ColorLabel,
Spinner,
},
data() {
return {
isLoading: false,
data: undefined,
}
},
methods: {
changeStatus(val, id) {
this.$updateText('/plans/' + id + '/update', 'is_active', val)
}
},
created() {
axios.get('/api/dashboard')
.then(response => {
this.data = response.data
this.isLoading = false
})
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.widgets-total {
display: flex;
flex: 0 0 33%;
margin: 0 -20px 20px;
.widget {
width: 100%;
padding: 20px;
}
}
.dashboard-headline {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.became-backer {
background: rgba($yellow, 0.1);
display: inline-block;
padding: 5px 10px;
border-radius: 6px;
margin-left: 40px;
cursor: pointer;
.icon, .content {
display: inline-block;
vertical-align: middle;
}
.icon {
margin-right: 10px;
line-height: 0;
rect, line {
stroke: $yellow;
}
}
.content {
color: $yellow;
font-weight: 700;
@include font-size(14);
}
}
.metadata {
.meta {
display: inline-block;
margin-left: 20px;
}
.meta-title {
@include font-size(14);
font-weight: 700;
}
}
@media only screen and (max-width: 690px) {
}
@media (prefers-color-scheme: dark) {
}
</style>

View File

@@ -1,219 +0,0 @@
<template>
<div id="single-page">
<div id="page-content" v-if="! isLoading">
<MobileHeader :title="$router.currentRoute.meta.title"/>
<PageHeader :title="$router.currentRoute.meta.title"/>
<div class="content-page">
<DatatableWrapper :paginator="false" :columns="columns" :data="gateways" class="table table-users">
<template scope="{ row }">
<tr>
<td style="min-width: 200px;">
<router-link :to="{name: 'GatewaySettings', params: {slug: row.data.attributes.slug}}">
<DatatableCellImage
:image="row.data.attributes.logo"
:title="row.data.attributes.name"
/>
</router-link>
</td>
<td>
<span class="cell-item">
<SwitchInput
@input="changeStatus($event, row.data.attributes.slug)"
:state="row.data.attributes.status"
class="switch"
/>
</span>
</td>
<td>
<span class="cell-item">
{{ row.data.attributes.payment_processed }}
</span>
</td>
<td>
<div class="action-icons">
<router-link :to="{name: 'GatewaySettings', params: {slug: row.data.attributes.slug}}">
<edit-2-icon size="15" class="icon icon-edit"></edit-2-icon>
</router-link>
</div>
</td>
</tr>
</template>
</DatatableWrapper>
</div>
</div>
<div id="loader" v-if="isLoading">
<Spinner></Spinner>
</div>
</div>
</template>
<script>
import DatatableCellImage from '@/components/Others/Tables/DatatableCellImage'
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import MobileActionButton from '@/components/FilesView/MobileActionButton'
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import MobileHeader from '@/components/Mobile/MobileHeader'
import SectionTitle from '@/components/Others/SectionTitle'
import ButtonBase from '@/components/FilesView/ButtonBase'
import {Trash2Icon, Edit2Icon} from "vue-feather-icons";
import PageHeader from '@/components/Others/PageHeader'
import ColorLabel from '@/components/Others/ColorLabel'
import Spinner from '@/components/FilesView/Spinner'
import axios from 'axios'
export default {
name: 'Plans',
components: {
DatatableCellImage,
MobileActionButton,
DatatableWrapper,
SectionTitle,
MobileHeader,
SwitchInput,
Trash2Icon,
PageHeader,
ButtonBase,
ColorLabel,
Edit2Icon,
Spinner,
},
data() {
return {
isLoading: true,
gateways: undefined,
columns: [
{
label: 'Payment Gateway',
field: 'data.attributes.gateway',
sortable: true
},
{
label: 'Status',
field: 'data.attributes.status',
sortable: true
},
{
label: 'Payments Processed',
field: 'data.attributes.payment_processed',
sortable: true
},
{
label: this.$t('admin_page_user.table.action'),
field: 'data.action',
sortable: false
},
],
}
},
methods: {
changeStatus(val, type) {
this.$updateText('/gateways/' + type, 'status', val)
}
},
created() {
axios.get('/api/gateways')
.then(response => {
this.gateways = response.data.data
this.isLoading = false
})
}
}
</script>
<style lang="scss" scoped>
@import '@assets/vue-file-manager/_variables';
@import '@assets/vue-file-manager/_mixins';
.user-thumbnail {
display: flex;
align-items: center;
cursor: pointer;
.avatar {
margin-right: 20px;
line-height: 0;
img {
line-height: 0;
width: 48px;
height: 48px;
border-radius: 8px;
}
}
.info {
.name {
max-width: 150px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
}
.name {
@include font-size(15);
line-height: 1;
}
}
}
.table-tools {
background: white;
display: flex;
justify-content: space-between;
padding: 15px 0 10px;
position: sticky;
top: 40px;
z-index: 9;
}
.table {
.cell-item {
@include font-size(15);
white-space: nowrap;
}
.name {
font-weight: 700;
cursor: pointer;
}
}
@media only screen and (max-width: 690px) {
.table-tools {
padding: 0 0 5px;
}
}
@media (prefers-color-scheme: dark) {
.table-tools {
background: $dark_mode_background;
}
.action-icons {
.icon {
cursor: pointer;
circle, path, line, polyline {
stroke: $dark_mode_text_primary;
}
}
}
.user-thumbnail {
.info {
.email {
color: $dark_mode_text_secondary;
}
}
}
}
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div id="single-page">
<div id="page-content" v-if="! isLoading">
<div id="page-content" v-if="! isLoading && invoices.length > 0">
<MobileHeader :title="$router.currentRoute.meta.title"/>
<PageHeader :title="$router.currentRoute.meta.title"/>
@@ -9,7 +9,7 @@
<template scope="{ row }">
<tr>
<td>
<a :href="'/invoice/' + row.data.id" target="_blank" class="cell-item">
<a :href="$getInvoiceLink(row.data.attributes.customer, row.data.id)" target="_blank" class="cell-item">
{{ row.data.attributes.order }}
</a>
</td>
@@ -42,7 +42,7 @@
</td>
<td>
<div class="action-icons">
<a :href="'/invoice/' + row.data.id" target="_blank">
<a :href="$getInvoiceLink(row.data.attributes.customer, row.data.id)" target="_blank">
<external-link-icon size="15" class="icon"></external-link-icon>
</a>
</div>
@@ -52,6 +52,13 @@
</DatatableWrapper>
</div>
</div>
<EmptyPageContent
v-if="! isLoading && invoices.length === 0"
icon="file-text"
title="You dont have any invoices yet"
description="All customers invoices will be showed here."
>
</EmptyPageContent>
<div id="loader" v-if="isLoading">
<Spinner></Spinner>
</div>
@@ -62,22 +69,24 @@
import DatatableCellImage from '@/components/Others/Tables/DatatableCellImage'
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import MobileActionButton from '@/components/FilesView/MobileActionButton'
import EmptyPageContent from '@/components/Others/EmptyPageContent'
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import MobileHeader from '@/components/Mobile/MobileHeader'
import SectionTitle from '@/components/Others/SectionTitle'
import ButtonBase from '@/components/FilesView/ButtonBase'
import {ExternalLinkIcon} from "vue-feather-icons";
import PageHeader from '@/components/Others/PageHeader'
import ColorLabel from '@/components/Others/ColorLabel'
import Spinner from '@/components/FilesView/Spinner'
import {ExternalLinkIcon} from "vue-feather-icons";
import axios from 'axios'
export default {
name: 'Invoices',
components: {
ExternalLinkIcon,
DatatableCellImage,
MobileActionButton,
ExternalLinkIcon,
EmptyPageContent,
DatatableWrapper,
SectionTitle,
MobileHeader,
@@ -94,32 +103,31 @@
columns: [
{
label: 'Invoice Number',
field: 'attributes.total',
field: 'data.attributes.order',
sortable: true
},
{
label: 'Total',
field: 'attributes.total',
field: 'data.attributes.bag.amount',
sortable: true
},
{
label: 'Plan',
field: 'attributes.plan',
field: 'data.attributes.bag.amount',
sortable: true
},
{
label: 'Payed',
field: 'attributes.created_at',
field: 'data.attributes.created_at',
sortable: true
},
{
label: 'User',
field: 'relationships.user.data.id',
field: 'relationships.user.data.attributes.name',
sortable: true
},
{
label: this.$t('admin_page_user.table.action'),
field: 'data.action',
sortable: false
},
],

View File

@@ -1,6 +1,6 @@
<template>
<div id="single-page">
<div id="page-content" v-if="! isLoading">
<div id="page-content" v-if="! isLoading && plans.length > 0">
<MobileHeader :title="$router.currentRoute.meta.title"/>
<PageHeader :title="$router.currentRoute.meta.title"/>
@@ -37,7 +37,7 @@
</td>
<td>
<span class="cell-item">
${{ row.data.attributes.price }}
{{ row.data.attributes.price_formatted }}
</span>
</td>
<td>
@@ -60,6 +60,18 @@
</DatatableWrapper>
</div>
</div>
<EmptyPageContent
v-if="! isLoading && plans.length === 0"
icon="file"
title="You dont have any plan yet"
description="For create new plan, click on button below."
>
<router-link :to="{name: 'PlanCreate'}">
<ButtonBase button-style="theme">Create New Plan</ButtonBase>
</router-link>
</EmptyPageContent>
<div id="loader" v-if="isLoading">
<Spinner></Spinner>
</div>
@@ -69,6 +81,7 @@
<script>
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import MobileActionButton from '@/components/FilesView/MobileActionButton'
import EmptyPageContent from '@/components/Others/EmptyPageContent'
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import MobileHeader from '@/components/Mobile/MobileHeader'
import SectionTitle from '@/components/Others/SectionTitle'
@@ -83,6 +96,7 @@
name: 'Plans',
components: {
MobileActionButton,
EmptyPageContent,
DatatableWrapper,
SectionTitle,
MobileHeader,
@@ -101,32 +115,31 @@
columns: [
{
label: 'Plan',
field: 'attributes.name',
field: 'data.attributes.name',
sortable: true
},
{
label: 'Status',
field: 'attributes.status',
field: 'data.attributes.status',
sortable: true
},
{
label: 'Subscribers',
field: 'attributes.subscribers',
field: 'data.attributes.subscribers',
sortable: true
},
{
label: 'Price',
field: 'attributes.price',
field: 'data.attributes.price',
sortable: true
},
{
label: 'Storage Capacity',
field: 'attributes.capacity',
field: 'data.attributes.capacity',
sortable: true
},
{
label: this.$t('admin_page_user.table.action'),
field: 'data.action',
sortable: false
},
],

View File

@@ -10,7 +10,7 @@
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">Status:</label>
<small class="input-help">Status of your payment gateway on website.</small>
<small class="input-help">Status of your plan availability on website.</small>
</div>
<SwitchInput @input="changeStatus" class="switch" :state="plan.attributes.status"/>
</div>
@@ -37,28 +37,33 @@
<!--Storage Capacity-->
<div class="block-wrapper">
<label>Storage Capacity:</label>
<label>Storage Capacity in GB:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Storage capacity" rules="required" v-slot="{ errors }">
<input @input="$updateText('/plans/' + $route.params.id + '/update', 'capacity', plan.attributes.capacity)" v-model="plan.attributes.capacity" placeholder="Storage capacity" type="number" min="1" max="999999999" :class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
<small class="input-help">You have to type only number e.g. value '5' means, user will have 5GB of storage capacity.</small>
</div>
<InfoBox>
<p>Price change for your plan is not available due to Stripe service design. If you wish change your price plan, please, create new plan.</p>
</InfoBox>
</PageTabGroup>
</ValidationObserver>
</PageTab>
</template>
<script>
import FormLabel from '@/components/Others/Forms/FormLabel'
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import PageTab from '@/components/Others/Layout/PageTab'
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
import StorageItemDetail from '@/components/Others/StorageItemDetail'
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import SelectInput from '@/components/Others/Forms/SelectInput'
import FormLabel from '@/components/Others/Forms/FormLabel'
import ButtonBase from '@/components/FilesView/ButtonBase'
import SetupBox from '@/components/Others/Forms/SetupBox'
import PageTab from '@/components/Others/Layout/PageTab'
import InfoBox from '@/components/Others/Forms/InfoBox'
import {required} from 'vee-validate/dist/rules'
export default {
@@ -67,17 +72,18 @@
'plan'
],
components: {
FormLabel,
SwitchInput,
PageTabGroup,
PageTab,
ValidationProvider,
ValidationObserver,
StorageItemDetail,
PageTabGroup,
SwitchInput,
SelectInput,
ButtonBase,
FormLabel,
SetupBox,
required,
InfoBox,
PageTab,
},
data() {
return {

View File

@@ -1,6 +1,6 @@
<template>
<PageTab v-if="subscribers">
<PageTabGroup>
<PageTab :is-loading="isLoading">
<PageTabGroup v-if="subscribers && subscribers.length > 0">
<DatatableWrapper :paginator="true" :columns="columns" :data="subscribers" class="table">
<template scope="{ row }">
<tr>
@@ -18,11 +18,6 @@
{{ row.relationships.storage.data.attributes.used }}%
</span>
</td>
<td>
<span class="cell-item">
{{ row.relationships.subscription.data.attributes.ends_at }}
</span>
</td>
<td>
<div class="action-icons">
<router-link :to="{name: 'UserDetail', params: {id: row.data.id}}">
@@ -37,15 +32,19 @@
</template>
</DatatableWrapper>
</PageTabGroup>
<InfoBox v-else>
<p>There is no any subscriber yet.</p>
</InfoBox>
</PageTab>
</template>
<script>
import DatatableCellImage from '@/components/Others/Tables/DatatableCellImage'
import {DownloadCloudIcon, Edit2Icon, Trash2Icon} from "vue-feather-icons"
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import PageTab from '@/components/Others/Layout/PageTab'
import {DownloadCloudIcon, Edit2Icon, Trash2Icon} from "vue-feather-icons";
import InfoBox from '@/components/Others/Forms/InfoBox'
import axios from 'axios'
export default {
@@ -55,33 +54,28 @@
DownloadCloudIcon,
DatatableWrapper,
PageTabGroup,
PageTab,
Edit2Icon,
Trash2Icon,
Edit2Icon,
PageTab,
InfoBox,
},
data() {
return {
isLoading: false,
subscribers: undefined,
isLoading: false,
columns: [
{
label: 'User',
field: 'data.attributes.plan',
field: 'data.attributes.name',
sortable: true
},
{
label: this.$t('admin_page_user.table.storage_used'),
field: 'data.storage.attributes.storage.used',
sortable: true
},
{
label: 'Expire At',
field: 'data.subscription.data.attributes.ends_at',
field: 'data.relationships.storage.data.attributes.used',
sortable: true
},
{
label: this.$t('admin_page_user.table.action'),
field: 'data.action',
sortable: false
},
],

View File

@@ -3,7 +3,6 @@
<div id="page-content" v-if="! isLoading">
<MobileHeader :title="$router.currentRoute.meta.title"/>
<PageHeader :can-back="true" :title="$router.currentRoute.meta.title"/>
<div class="content-page">
<!--User thumbnail-->

View File

@@ -32,30 +32,27 @@
<div class="form block-form">
<FormLabel>{{ $t('admin_page_user.label_person_info') }}</FormLabel>
<div class="wrapper-inline">
<!--Email-->
<div class="block-wrapper">
<label>{{ $t('page_registration.label_email') }}</label>
<div class="input-wrapper">
<input :value="user.data.attributes.email"
:placeholder="$t('page_registration.placeholder_email')"
type="email"
disabled
/>
</div>
<!--Email-->
<div class="block-wrapper">
<label>{{ $t('page_registration.label_email') }}</label>
<div class="input-wrapper">
<input :value="user.data.attributes.email"
:placeholder="$t('page_registration.placeholder_email')"
type="email"
disabled
/>
</div>
</div>
<!--Name-->
<div class="block-wrapper">
<label>{{ $t('page_registration.label_name') }}</label>
<div class="input-wrapper">
<input :value="user.data.attributes.name"
:placeholder="$t('page_registration.placeholder_name')"
type="text"
disabled
/>
</div>
<!--Name-->
<div class="block-wrapper">
<label>{{ $t('page_registration.label_name') }}</label>
<div class="input-wrapper">
<input :value="user.data.attributes.name"
:placeholder="$t('page_registration.placeholder_name')"
type="text"
disabled
/>
</div>
</div>
</div>

View File

@@ -1,11 +1,11 @@
<template>
<PageTab :is-loading="isLoading">
<PageTab :is-loading="isLoading" :class="{'form-fixed-width': ! isLoading && invoices.length === 0}">
<PageTabGroup v-if="invoices && invoices.length > 0">
<DatatableWrapper :paginator="true" :columns="columns" :data="invoices" class="table">
<template scope="{ row }">
<tr>
<td>
<a :href="'/invoice/' + row.data.id" target="_blank" class="cell-item">
<a :href="$getInvoiceLink(row.data.attributes.customer, row.data.id)" target="_blank" class="cell-item">
{{ row.data.attributes.order }}
</a>
</td>
@@ -26,7 +26,7 @@
</td>
<td>
<div class="action-icons">
<a :href="'/invoice/' + row.data.id" target="_blank">
<a :href="$getInvoiceLink(row.data.attributes.customer, row.data.id)" target="_blank">
<external-link-icon size="15" class="icon"></external-link-icon>
</a>
</div>
@@ -35,26 +35,30 @@
</template>
</DatatableWrapper>
</PageTabGroup>
<PageTabGroup v-else>
User don't have any invoices yet.
</PageTabGroup>
<InfoBox v-else>
<p>User don't have any invoices yet.</p>
</InfoBox>
</PageTab>
</template>
<script>
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import EmptyPageContent from '@/components/Others/EmptyPageContent'
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import PageTab from '@/components/Others/Layout/PageTab'
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import InfoBox from '@/components/Others/Forms/InfoBox'
import {ExternalLinkIcon} from "vue-feather-icons";
import axios from 'axios'
export default {
name: 'UserInvoices',
components: {
PageTabGroup,
PageTab,
EmptyPageContent,
DatatableWrapper,
ExternalLinkIcon,
PageTabGroup,
InfoBox,
PageTab,
},
data() {
return {
@@ -63,17 +67,17 @@
columns: [
{
label: 'Invoice Number',
field: 'data.attributes.total',
field: 'data.attributes.order',
sortable: true
},
{
label: 'Total',
field: 'data.attributes.total',
field: 'data.attributes.bag.amount',
sortable: true
},
{
label: 'Plan',
field: 'data.attributes.plan',
field: 'data.attributes.bag.amount',
sortable: true
},
{
@@ -83,7 +87,6 @@
},
{
label: this.$t('admin_page_user.table.action'),
field: 'data.action',
sortable: false
},
],

View File

@@ -1,5 +1,5 @@
<template>
<PageTab class="form-fixed-width" v-if="storage">
<PageTab :is-loading="isLoading" class="form-fixed-width" v-if="storage">
<PageTabGroup v-if="! config.isSaaS || ! user.data.attributes.subscription">
<FormLabel>{{ $t('user_box_storage.title') }}</FormLabel>
<InfoBox>

View File

@@ -1,6 +1,7 @@
<template>
<PageTab class="form-fixed-width" :is-loading="isLoading">
<PageTab :is-loading="isLoading" class="form-fixed-width">
<PageTabGroup v-if="subscription">
<FormLabel>Subscription Plan</FormLabel>
<!--Info about active subscription-->
<div v-if="! subscription.canceled" class="state active">
@@ -24,7 +25,9 @@
</div>
</PageTabGroup>
<PageTabGroup v-if="! subscription">
User don't have any subscription yet.
<InfoBox>
<p>User don't have any subscription yet.</p>
</InfoBox>
</PageTabGroup>
</PageTab>
</template>
@@ -33,8 +36,10 @@
import DatatableWrapper from '@/components/Others/Tables/DatatableWrapper'
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import ListInfoItem from '@/components/Others/ListInfoItem'
import FormLabel from '@/components/Others/Forms/FormLabel'
import ButtonBase from '@/components/FilesView/ButtonBase'
import PageTab from '@/components/Others/Layout/PageTab'
import InfoBox from '@/components/Others/Forms/InfoBox'
import ListInfo from '@/components/Others/ListInfo'
import {ExternalLinkIcon} from "vue-feather-icons"
import {mapGetters} from 'vuex'
@@ -49,7 +54,9 @@
ListInfoItem,
PageTabGroup,
ButtonBase,
FormLabel,
ListInfo,
InfoBox,
PageTab,
},
computed: {

View File

@@ -123,6 +123,9 @@
formData.append('password', this.admin.password)
formData.append('password_confirmation', this.admin.password_confirmation)
formData.append('license', localStorage.getItem('license'))
formData.append('purchase_code', localStorage.getItem('purchase_code'))
if (this.admin.avatar)
formData.append('avatar', this.admin.avatar)
@@ -141,7 +144,11 @@
this.$store.commit('SET_AUTHORIZED', true)
// Go to files page
this.$router.push({name: 'Files'})
this.$router.push({name: 'Dashboard'})
// Remove license from localStorage
localStorage.removeItem('purchase_code')
localStorage.removeItem('license')
})
.catch(error => {

View File

@@ -126,18 +126,6 @@
label: 'MySQL',
value: 'mysql',
},
/*{
label: 'SQLite',
value: 'sqlite',
},
{
label: 'PqSQL',
value: 'pgsql',
},
{
label: 'SQLSry',
value: 'sqlsrv',
},*/
],
databaseCredentials: {
connection: 'mysql',

View File

@@ -119,8 +119,10 @@
if (response.data === 'b6896a44017217c36f4a6fdc56699728') {
this.isExtended = true
localStorage.setItem('license', 'Extended')
} else {
this.isExtended = false
localStorage.setItem('license', 'Regular')
}
})
.catch(error => {

View File

@@ -27,7 +27,7 @@
</td>
<td>
<div class="action-icons">
<a :href="'/invoice/' + row.data.attributes.customer + '/' + row.data.id" target="_blank">
<a :href="$getInvoiceLink(row.data.attributes.customer, row.data.id)" target="_blank">
<external-link-icon size="15" class="icon"></external-link-icon>
</a>
</div>
@@ -36,9 +36,9 @@
</template>
</DatatableWrapper>
</PageTabGroup>
<PageTabGroup v-else>
You don't have any invoices yet.
</PageTabGroup>
<InfoBox v-else>
<p>You don't have any invoices yet.</p>
</InfoBox>
</PageTab>
</template>
@@ -47,6 +47,7 @@
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import FormLabel from '@/components/Others/Forms/FormLabel'
import PageTab from '@/components/Others/Layout/PageTab'
import InfoBox from '@/components/Others/Forms/InfoBox'
import {ExternalLinkIcon} from "vue-feather-icons";
import axios from 'axios'
@@ -57,6 +58,7 @@
ExternalLinkIcon,
PageTabGroup,
FormLabel,
InfoBox,
PageTab,
},
data() {
@@ -66,17 +68,17 @@
columns: [
{
label: 'Invoice Number',
field: 'data.attributes.total',
field: 'data.attributes.order',
sortable: true
},
{
label: 'Total',
field: 'data.attributes.total',
field: 'data.attributes.bag.amount',
sortable: true
},
{
label: 'Plan',
field: 'data.attributes.plan',
field: 'data.attributes.bag.amount',
sortable: true
},
{
@@ -86,7 +88,6 @@
},
{
label: this.$t('admin_page_user.table.action'),
field: 'data.action',
sortable: false
},
],

View File

@@ -37,9 +37,9 @@
</template>
</DatatableWrapper>
</PageTabGroup>
<PageTabGroup v-else>
You don't have any payment cards yet.
</PageTabGroup>
<InfoBox v-else>
<p>You don't have any payment cards yet.</p>
</InfoBox>
</PageTab>
</template>
@@ -50,6 +50,7 @@
import FormLabel from '@/components/Others/Forms/FormLabel'
import PageTab from '@/components/Others/Layout/PageTab'
import ColorLabel from '@/components/Others/ColorLabel'
import InfoBox from '@/components/Others/Forms/InfoBox'
import {events} from "@/bus"
import axios from 'axios'
@@ -62,6 +63,7 @@
Trash2Icon,
ColorLabel,
FormLabel,
InfoBox,
PageTab,
},
data() {

View File

@@ -42,9 +42,9 @@
</div>
</div>
</PageTabGroup>
<PageTabGroup v-else>
You don't have any subscription yet.
</PageTabGroup>
<InfoBox v-else>
<p>You don't have any subscription yet.</p>
</InfoBox>
</PageTab>
</template>
@@ -55,6 +55,7 @@
import FormLabel from '@/components/Others/Forms/FormLabel'
import ButtonBase from '@/components/FilesView/ButtonBase'
import PageTab from '@/components/Others/Layout/PageTab'
import InfoBox from '@/components/Others/Forms/InfoBox'
import ListInfo from '@/components/Others/ListInfo'
import {ExternalLinkIcon} from "vue-feather-icons"
import { mapGetters } from 'vuex'
@@ -71,6 +72,7 @@
ButtonBase,
FormLabel,
ListInfo,
InfoBox,
PageTab,
},
computed: {

View File

@@ -23,3 +23,10 @@
-webkit-box-shadow: 0 0 0 30px white inset;
}
}
@mixin widget-card {
padding: 20px;
border-radius: 8px;
box-shadow: 0 3px 15px 2px hsla(220, 36%, 16%, 0.05);
background: white;
}

View File

@@ -116,6 +116,10 @@ Route::group(['middleware' => ['auth:api', 'auth.master', 'scope:master']], func
// Admin
Route::group(['middleware' => ['auth:api', 'auth.master', 'auth.admin', 'scope:master']], function () {
// Admin
Route::get('/dashboard', 'Admin\DashboardController@index');
Route::get('/dashboard/new-users', 'Admin\DashboardController@new_registrations');
// Get users info
Route::get('/users/{id}/subscription', 'Admin\UserController@subscription');
Route::get('/users/{id}/storage', 'Admin\UserController@storage');
@@ -130,12 +134,6 @@ Route::group(['middleware' => ['auth:api', 'auth.master', 'auth.admin', 'scope:m
Route::get('/users/{id}/invoices', 'Admin\UserController@invoices');
Route::post('/users/create', 'Admin\UserController@create_user');
// Gateways
Route::get('/gateways/{type}/transactions', 'Admin\GatewayController@show_transactions');
Route::patch('/gateways/{type}', 'Admin\GatewayController@update');
Route::get('/gateways/{type}', 'Admin\GatewayController@show');
Route::get('/gateways', 'Admin\GatewayController@index');
// Plans
Route::get('/plans/{id}/subscribers', 'Admin\PlanController@subscribers');
Route::patch('/plans/{id}/update', 'Admin\PlanController@update');
@@ -147,6 +145,11 @@ Route::group(['middleware' => ['auth:api', 'auth.master', 'auth.admin', 'scope:m
// Invoices
Route::get('/invoices/{token}', 'Admin\InvoiceController@show');
Route::get('/invoices', 'Admin\InvoiceController@index');
// Settings
Route::put('/settings/email', 'SettingController@set_email');
Route::patch('/settings', 'SettingController@update');
Route::get('/settings', 'SettingController@show');
});
// Protected sharing routes for authenticated user

View File

@@ -0,0 +1 @@
9999999999a:3:{i:0;a:2:{s:4:"plan";a:20:{s:2:"id";s:13:"business-pack";s:6:"object";s:4:"plan";s:6:"active";b:1;s:15:"aggregate_usage";N;s:6:"amount";i:4990;s:14:"amount_decimal";s:4:"4990";s:14:"billing_scheme";s:8:"per_unit";s:7:"created";i:1593792006;s:8:"currency";s:3:"usd";s:8:"interval";s:5:"month";s:14:"interval_count";i:1;s:8:"livemode";b:0;s:8:"metadata";a:0:{}s:8:"nickname";N;s:7:"product";s:19:"prod_Ha1LO6Ji2JLKYI";s:5:"tiers";N;s:10:"tiers_mode";N;s:15:"transform_usage";N;s:17:"trial_period_days";N;s:10:"usage_type";s:8:"licensed";}s:7:"product";a:14:{s:2:"id";s:19:"prod_Ha1LO6Ji2JLKYI";s:6:"object";s:7:"product";s:6:"active";b:1;s:10:"attributes";a:0:{}s:7:"created";i:1593792005;s:11:"description";s:29:"Best for your business growth";s:6:"images";a:0:{}s:8:"livemode";b:0;s:8:"metadata";a:1:{s:8:"capacity";s:4:"1000";}s:4:"name";s:13:"Business Pack";s:20:"statement_descriptor";N;s:4:"type";s:7:"service";s:10:"unit_label";N;s:7:"updated";i:1593792006;}}i:1;a:2:{s:4:"plan";a:20:{s:2:"id";s:17:"professional-pack";s:6:"object";s:4:"plan";s:6:"active";b:1;s:15:"aggregate_usage";N;s:6:"amount";i:1999;s:14:"amount_decimal";s:4:"1999";s:14:"billing_scheme";s:8:"per_unit";s:7:"created";i:1593791361;s:8:"currency";s:3:"usd";s:8:"interval";s:5:"month";s:14:"interval_count";i:1;s:8:"livemode";b:0;s:8:"metadata";a:0:{}s:8:"nickname";N;s:7:"product";s:19:"prod_Ha1AMwcPYAuxrU";s:5:"tiers";N;s:10:"tiers_mode";N;s:15:"transform_usage";N;s:17:"trial_period_days";N;s:10:"usage_type";s:8:"licensed";}s:7:"product";a:14:{s:2:"id";s:19:"prod_Ha1AMwcPYAuxrU";s:6:"object";s:7:"product";s:6:"active";b:1;s:10:"attributes";a:0:{}s:7:"created";i:1593791359;s:11:"description";s:26:"The best for professionals";s:6:"images";a:0:{}s:8:"livemode";b:0;s:8:"metadata";a:1:{s:8:"capacity";s:3:"500";}s:4:"name";s:17:"Professional Pack";s:20:"statement_descriptor";N;s:4:"type";s:7:"service";s:10:"unit_label";N;s:7:"updated";i:1593791361;}}i:2;a:2:{s:4:"plan";a:20:{s:2:"id";s:12:"starter-pack";s:6:"object";s:4:"plan";s:6:"active";b:1;s:15:"aggregate_usage";N;s:6:"amount";i:999;s:14:"amount_decimal";s:3:"999";s:14:"billing_scheme";s:8:"per_unit";s:7:"created";i:1593769244;s:8:"currency";s:3:"usd";s:8:"interval";s:5:"month";s:14:"interval_count";i:1;s:8:"livemode";b:0;s:8:"metadata";a:0:{}s:8:"nickname";N;s:7:"product";s:19:"prod_HZvEp2UNNs7zYx";s:5:"tiers";N;s:10:"tiers_mode";N;s:15:"transform_usage";N;s:17:"trial_period_days";N;s:10:"usage_type";s:8:"licensed";}s:7:"product";a:14:{s:2:"id";s:19:"prod_HZvEp2UNNs7zYx";s:6:"object";s:7:"product";s:6:"active";b:1;s:10:"attributes";a:0:{}s:7:"created";i:1593769243;s:11:"description";s:24:"The best for starting up";s:6:"images";a:0:{}s:8:"livemode";b:0;s:8:"metadata";a:1:{s:8:"capacity";s:3:"200";}s:4:"name";s:12:"Starter Pack";s:20:"statement_descriptor";N;s:4:"type";s:7:"service";s:10:"unit_label";N;s:7:"updated";i:1593769244;}}}

View File

@@ -0,0 +1 @@
9999999999a:2:{s:4:"plan";a:20:{s:2:"id";s:12:"starter-pack";s:6:"object";s:4:"plan";s:6:"active";b:1;s:15:"aggregate_usage";N;s:6:"amount";i:999;s:14:"amount_decimal";s:3:"999";s:14:"billing_scheme";s:8:"per_unit";s:7:"created";i:1593769244;s:8:"currency";s:3:"usd";s:8:"interval";s:5:"month";s:14:"interval_count";i:1;s:8:"livemode";b:0;s:8:"metadata";a:0:{}s:8:"nickname";N;s:7:"product";s:19:"prod_HZvEp2UNNs7zYx";s:5:"tiers";N;s:10:"tiers_mode";N;s:15:"transform_usage";N;s:17:"trial_period_days";N;s:10:"usage_type";s:8:"licensed";}s:7:"product";a:14:{s:2:"id";s:19:"prod_HZvEp2UNNs7zYx";s:6:"object";s:7:"product";s:6:"active";b:1;s:10:"attributes";a:0:{}s:7:"created";i:1593769243;s:11:"description";s:24:"The best for starting up";s:6:"images";a:0:{}s:8:"livemode";b:0;s:8:"metadata";a:1:{s:8:"capacity";s:3:"200";}s:4:"name";s:12:"Starter Pack";s:20:"statement_descriptor";N;s:4:"type";s:7:"service";s:10:"unit_label";N;s:7:"updated";i:1593769244;}}

View File

@@ -0,0 +1 @@
9999999999a:3:{i:0;a:2:{s:4:"plan";a:20:{s:2:"id";s:13:"business-pack";s:6:"object";s:4:"plan";s:6:"active";b:1;s:15:"aggregate_usage";N;s:6:"amount";i:4990;s:14:"amount_decimal";s:4:"4990";s:14:"billing_scheme";s:8:"per_unit";s:7:"created";i:1593792006;s:8:"currency";s:3:"usd";s:8:"interval";s:5:"month";s:14:"interval_count";i:1;s:8:"livemode";b:0;s:8:"metadata";a:0:{}s:8:"nickname";N;s:7:"product";s:19:"prod_Ha1LO6Ji2JLKYI";s:5:"tiers";N;s:10:"tiers_mode";N;s:15:"transform_usage";N;s:17:"trial_period_days";N;s:10:"usage_type";s:8:"licensed";}s:7:"product";a:14:{s:2:"id";s:19:"prod_Ha1LO6Ji2JLKYI";s:6:"object";s:7:"product";s:6:"active";b:1;s:10:"attributes";a:0:{}s:7:"created";i:1593792005;s:11:"description";s:29:"Best for your business growth";s:6:"images";a:0:{}s:8:"livemode";b:0;s:8:"metadata";a:1:{s:8:"capacity";s:4:"1000";}s:4:"name";s:13:"Business Pack";s:20:"statement_descriptor";N;s:4:"type";s:7:"service";s:10:"unit_label";N;s:7:"updated";i:1593792006;}}i:1;a:2:{s:4:"plan";a:20:{s:2:"id";s:17:"professional-pack";s:6:"object";s:4:"plan";s:6:"active";b:1;s:15:"aggregate_usage";N;s:6:"amount";i:1999;s:14:"amount_decimal";s:4:"1999";s:14:"billing_scheme";s:8:"per_unit";s:7:"created";i:1593791361;s:8:"currency";s:3:"usd";s:8:"interval";s:5:"month";s:14:"interval_count";i:1;s:8:"livemode";b:0;s:8:"metadata";a:0:{}s:8:"nickname";N;s:7:"product";s:19:"prod_Ha1AMwcPYAuxrU";s:5:"tiers";N;s:10:"tiers_mode";N;s:15:"transform_usage";N;s:17:"trial_period_days";N;s:10:"usage_type";s:8:"licensed";}s:7:"product";a:14:{s:2:"id";s:19:"prod_Ha1AMwcPYAuxrU";s:6:"object";s:7:"product";s:6:"active";b:1;s:10:"attributes";a:0:{}s:7:"created";i:1593791359;s:11:"description";s:26:"The best for professionals";s:6:"images";a:0:{}s:8:"livemode";b:0;s:8:"metadata";a:1:{s:8:"capacity";s:3:"500";}s:4:"name";s:17:"Professional Pack";s:20:"statement_descriptor";N;s:4:"type";s:7:"service";s:10:"unit_label";N;s:7:"updated";i:1593791361;}}i:2;a:2:{s:4:"plan";a:20:{s:2:"id";s:12:"starter-pack";s:6:"object";s:4:"plan";s:6:"active";b:1;s:15:"aggregate_usage";N;s:6:"amount";i:999;s:14:"amount_decimal";s:3:"999";s:14:"billing_scheme";s:8:"per_unit";s:7:"created";i:1593769244;s:8:"currency";s:3:"usd";s:8:"interval";s:5:"month";s:14:"interval_count";i:1;s:8:"livemode";b:0;s:8:"metadata";a:0:{}s:8:"nickname";N;s:7:"product";s:19:"prod_HZvEp2UNNs7zYx";s:5:"tiers";N;s:10:"tiers_mode";N;s:15:"transform_usage";N;s:17:"trial_period_days";N;s:10:"usage_type";s:8:"licensed";}s:7:"product";a:14:{s:2:"id";s:19:"prod_HZvEp2UNNs7zYx";s:6:"object";s:7:"product";s:6:"active";b:1;s:10:"attributes";a:0:{}s:7:"created";i:1593769243;s:11:"description";s:24:"The best for starting up";s:6:"images";a:0:{}s:8:"livemode";b:0;s:8:"metadata";a:1:{s:8:"capacity";s:3:"200";}s:4:"name";s:12:"Starter Pack";s:20:"statement_descriptor";N;s:4:"type";s:7:"service";s:10:"unit_label";N;s:7:"updated";i:1593769244;}}}

View File

@@ -1 +1 @@
1593758028i:1593758028;
1593881222i:1593881222;

View File

@@ -0,0 +1 @@
9999999999a:0:{}

View File

@@ -1 +1 @@
1593758028i:2;
1593881222i:2;

View File

@@ -0,0 +1 @@
9999999999a:0:{}

View File

@@ -0,0 +1 @@
9999999999a:2:{s:4:"plan";a:20:{s:2:"id";s:13:"business-pack";s:6:"object";s:4:"plan";s:6:"active";b:1;s:15:"aggregate_usage";N;s:6:"amount";i:4990;s:14:"amount_decimal";s:4:"4990";s:14:"billing_scheme";s:8:"per_unit";s:7:"created";i:1593792006;s:8:"currency";s:3:"usd";s:8:"interval";s:5:"month";s:14:"interval_count";i:1;s:8:"livemode";b:0;s:8:"metadata";a:0:{}s:8:"nickname";N;s:7:"product";s:19:"prod_Ha1LO6Ji2JLKYI";s:5:"tiers";N;s:10:"tiers_mode";N;s:15:"transform_usage";N;s:17:"trial_period_days";N;s:10:"usage_type";s:8:"licensed";}s:7:"product";a:14:{s:2:"id";s:19:"prod_Ha1LO6Ji2JLKYI";s:6:"object";s:7:"product";s:6:"active";b:1;s:10:"attributes";a:0:{}s:7:"created";i:1593792005;s:11:"description";s:29:"Best for your business growth";s:6:"images";a:0:{}s:8:"livemode";b:0;s:8:"metadata";a:1:{s:8:"capacity";s:4:"1000";}s:4:"name";s:13:"Business Pack";s:20:"statement_descriptor";N;s:4:"type";s:7:"service";s:10:"unit_label";N;s:7:"updated";i:1593792006;}}