mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-06 18:53:48 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88315e4a91 | ||
|
|
25bb186c89 | ||
|
|
cca832a1c1 | ||
|
|
6dd0b4f026 |
37
README.md
37
README.md
@@ -21,8 +21,10 @@ But, it can't be done without you, development is more and more complicated and
|
||||
- [Nginx Configuration](#nginx-configuration)
|
||||
- [Apache Configuration](#apache-configuration)
|
||||
- [Recover Failed Installation](#installation-failed)
|
||||
- [Regular Update](#regular-update)
|
||||
- [Update from 1.6.x to 1.7 ](#update-from-16x-to-17)
|
||||
- [Update Guide](#update-guide)
|
||||
- [Instructions](#instructions)
|
||||
- [Update from 1.7.x to 1.7.7](#update-from-17x-to-177)
|
||||
- [Update from 1.6.x to 1.7](#update-from-16x-to-17)
|
||||
- [Payments](#payments)
|
||||
- [Get your active plans](#get-your-active-plans)
|
||||
- [Manage Failed Payments](#manage-failed-payments)
|
||||
@@ -188,17 +190,23 @@ At worst scenarios, to reset Setup Wizard, delete all tables in your previously
|
||||
|
||||
After these steps, installation will be reseted.
|
||||
|
||||
## Regular Update
|
||||
- `Don't forget create backup of your database and storage before make any changes in your production application.`
|
||||
- `If you serve your files in local storage driver pay attention and don't delete your /storage folder`
|
||||
## Update Guide
|
||||
|
||||
### Instructions
|
||||
`Don't forget create backup of your database and storage before make any changes in your production application.`
|
||||
|
||||
`If you serve your files in local storage driver pay attention and don't delete your /storage folder`
|
||||
|
||||
Follow this steps:
|
||||
|
||||
- Make a backup of the .env config file located on your server.
|
||||
- Upload and replace all the files on your server with what's inside the app folder.
|
||||
- Restore your `.env` config file on your server.
|
||||
|
||||
## Update VueFileManager from 1.6.x to 1.7
|
||||
`Don't forget create backup of your database and storage before make any changes in your production application.`
|
||||
## Update from 1.7.x to 1.7.7
|
||||
If you are upgrading app to 1.7.7 from 1.7.x, make sure you have copied new /vendor folder or if you are using terminal or git, run `composer update` command to update your vendors.
|
||||
|
||||
## Update from 1.6.x to 1.7
|
||||
|
||||
For those, who purchase extended licence, place these lines at the end of your `/.env` file:
|
||||
```
|
||||
@@ -210,13 +218,7 @@ STRIPE_WEBHOOK_SECRET=
|
||||
CASHIER_PAYMENT_NOTIFICATION=App\Notifications\ConfirmPayment
|
||||
```
|
||||
|
||||
Then follow this steps:
|
||||
|
||||
- Make sure you have PHP >= 7.2.5 version
|
||||
- Make a backup of the .env config file located on your server.
|
||||
- Upload and replace all the files on your server with what's inside the app folder.
|
||||
- Restore your `.env` config file on your server.
|
||||
- Go to https://your-domain.com/upgrade and follow the setup wizard instructions.
|
||||
Then go to https://your-domain.com/upgrade and follow the setup wizard instructions.
|
||||
|
||||
# Payments
|
||||
VueFileManager is packed with **Stripe** payment options. To configure Stripe, you will be asked in Setup Wizard to set up. Or, if you skip this installation process, you will find stripe set up in you admin `Dashboard / Settings / Payments`.
|
||||
@@ -258,6 +260,13 @@ To start server on your localhost, run command below. Then go to your generated
|
||||
php artisan serve
|
||||
```
|
||||
|
||||
After successfully installation via Setup Wizard, stop your artisan server, clear config cache and run your artisan server again:
|
||||
```
|
||||
php artisan config:clear
|
||||
php artisan serve
|
||||
```
|
||||
*After any change in your .env you have to restart your artisan server to reload your config cache.*
|
||||
|
||||
To develop your Vue front-end, you have to install npm modules by this command:
|
||||
```
|
||||
npm install
|
||||
|
||||
@@ -60,7 +60,7 @@ class DashboardController extends Controller
|
||||
public function new_registrations()
|
||||
{
|
||||
return new UsersCollection(
|
||||
User::take(7)->orderByDesc('created_at')->get()
|
||||
User::sortable(['created_at' => 'desc'])->paginate(10)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class PagesController extends Controller
|
||||
public function index()
|
||||
{
|
||||
return new PageCollection(
|
||||
Page::all()
|
||||
Page::sortable()->paginate(10)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ class PlanController extends Controller
|
||||
$subscribers = Subscription::where('stripe_plan', $id)->pluck('user_id');
|
||||
|
||||
return new UsersCollection(
|
||||
User::findMany($subscribers)
|
||||
User::sortable()->findMany($subscribers)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ class UserController extends Controller
|
||||
public function users()
|
||||
{
|
||||
return new UsersCollection(
|
||||
User::all()
|
||||
User::sortable()->paginate('20')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -149,6 +149,8 @@ class SettingController extends Controller
|
||||
]);
|
||||
|
||||
// Clear cache
|
||||
Artisan::call('cache:clear');
|
||||
Artisan::call('config:clear');
|
||||
Artisan::call('config:cache');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,12 +244,12 @@ function is_editor($shared)
|
||||
function get_unique_id(): int
|
||||
{
|
||||
// Get files and folders
|
||||
$folders = FileManagerFolder::withTrashed()->latest();
|
||||
$files = FileManagerFile::withTrashed()->latest();
|
||||
$folders = FileManagerFolder::withTrashed()->get();
|
||||
$files = FileManagerFile::withTrashed()->get();
|
||||
|
||||
// Get last ids
|
||||
$folders_unique = ! $folders->first() ? 0 : (int) $folders->first()->unique_id;
|
||||
$files_unique = ! $files->first() ? 0 : (int) $files->first()->unique_id;
|
||||
$folders_unique = $folders->isEmpty() ? 0 : $folders->last()->unique_id;
|
||||
$files_unique = $files->isEmpty() ? 0 : $files->last()->unique_id;
|
||||
|
||||
// Count new unique id
|
||||
$unique_id = $folders_unique > $files_unique ? $folders_unique + 1 : $files_unique + 1;
|
||||
|
||||
@@ -23,17 +23,17 @@ class UserResource extends JsonResource
|
||||
'id' => (string)$this->id,
|
||||
'type' => 'user',
|
||||
'attributes' => [
|
||||
'storage_capacity' => $this->settings->storage_capacity,
|
||||
'subscription' => $this->subscribed('main'),
|
||||
'incomplete_payment' => $this->hasIncompletePayment('main') ? route('cashier.payment', $this->subscription('main')->latestPayment()->id) : null,
|
||||
'stripe_customer' => is_null($this->stripe_id) ? false : true,
|
||||
'name' => $this->name,
|
||||
'email' => env('APP_DEMO') ? obfuscate_email($this->email) : $this->email,
|
||||
'avatar' => $this->avatar,
|
||||
'role' => $this->role,
|
||||
'created_at_formatted' => format_date($this->created_at, '%d. %B. %Y'),
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
'storage_capacity' => $this->settings->storage_capacity,
|
||||
'subscription' => $this->subscribed('main'),
|
||||
'incomplete_payment' => $this->hasIncompletePayment('main') ? route('cashier.payment', $this->subscription('main')->latestPayment()->id) : null,
|
||||
'stripe_customer' => is_null($this->stripe_id) ? false : true,
|
||||
'name' => $this->name,
|
||||
'email' => env('APP_DEMO') ? obfuscate_email($this->email) : $this->email,
|
||||
'avatar' => $this->avatar,
|
||||
'role' => $this->role,
|
||||
'created_at_formatted' => format_date($this->created_at, '%d. %B. %Y'),
|
||||
'created_at' => $this->created_at,
|
||||
'updated_at' => $this->updated_at,
|
||||
]
|
||||
],
|
||||
'relationships' => [
|
||||
|
||||
14
app/Page.php
14
app/Page.php
@@ -3,9 +3,23 @@
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Kyslik\ColumnSortable\Sortable;
|
||||
|
||||
class Page extends Model
|
||||
{
|
||||
use Sortable;
|
||||
|
||||
/**
|
||||
* Sortable columns
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $sortable = [
|
||||
'title',
|
||||
'slug',
|
||||
'visibility',
|
||||
];
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
protected $guarded = ['id'];
|
||||
|
||||
@@ -380,6 +380,8 @@ class StripeService
|
||||
*/
|
||||
public function getInvoices()
|
||||
{
|
||||
return $this->stripe->invoices()->all();
|
||||
return $this->stripe->invoices()->all([
|
||||
'limit' => 20
|
||||
]);
|
||||
}
|
||||
}
|
||||
20
app/User.php
20
app/User.php
@@ -5,14 +5,12 @@ namespace App;
|
||||
use App\Notifications\ResetPassword;
|
||||
use App\Notifications\ResetUserPasswordNotification;
|
||||
use ByteUnits\Metric;
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Laravel\Cashier\Billable;
|
||||
use Laravel\Passport\HasApiTokens;
|
||||
use Kyslik\ColumnSortable\Sortable;
|
||||
use Rinvex\Subscriptions\Traits\HasSubscriptions;
|
||||
|
||||
/**
|
||||
@@ -78,7 +76,7 @@ use Rinvex\Subscriptions\Traits\HasSubscriptions;
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens, Notifiable, Billable;
|
||||
use HasApiTokens, Notifiable, Billable, Sortable;
|
||||
|
||||
protected $guarded = ['id', 'role'];
|
||||
|
||||
@@ -113,6 +111,19 @@ class User extends Authenticatable
|
||||
'used_capacity', 'storage'
|
||||
];
|
||||
|
||||
/**
|
||||
* Sortable columns
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $sortable = [
|
||||
'id',
|
||||
'name',
|
||||
'role',
|
||||
'created_at',
|
||||
'storage_capacity',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get tax rate id for user
|
||||
*
|
||||
@@ -197,7 +208,6 @@ class User extends Authenticatable
|
||||
{
|
||||
// Get avatar from external storage
|
||||
if ($this->attributes['avatar'] && is_storage_driver(['s3', 'spaces', 'wasabi', 'backblaze'])) {
|
||||
|
||||
return Storage::temporaryUrl($this->attributes['avatar'], now()->addDay());
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"fruitcake/laravel-cors": "^1.0",
|
||||
"gabrielelana/byte-units": "^0.5.0",
|
||||
"intervention/image": "^2.5",
|
||||
"kyslik/column-sortable": "^6.3",
|
||||
"laravel/cashier": "^12.0",
|
||||
"laravel/framework": "^7.0",
|
||||
"laravel/passport": "^8.4",
|
||||
|
||||
60
composer.lock
generated
60
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "c2e0a4adcc267140dcc5f4b1ee31ae2f",
|
||||
"content-hash": "0d1b10acc2a996969b828cc7f51cdee6",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asm89/stack-cors",
|
||||
@@ -1467,6 +1467,63 @@
|
||||
],
|
||||
"time": "2019-11-02T09:15:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "kyslik/column-sortable",
|
||||
"version": "6.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Kyslik/column-sortable.git",
|
||||
"reference": "9f2ddfabe5cfd9cfd67b15805e2d0de48429c995"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Kyslik/column-sortable/zipball/9f2ddfabe5cfd9cfd67b15805e2d0de48429c995",
|
||||
"reference": "9f2ddfabe5cfd9cfd67b15805e2d0de48429c995",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/database": "5.8.*|^6.0|^7.0",
|
||||
"illuminate/support": "5.8.*|^6.0|^7.0",
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^5.0",
|
||||
"phpunit/phpunit": "^8.5"
|
||||
},
|
||||
"type": "package",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Kyslik\\ColumnSortable\\ColumnSortableServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Kyslik\\ColumnSortable\\": "src/ColumnSortable/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Martin Kiesel",
|
||||
"email": "martin.kiesel@gmail.com",
|
||||
"role": "Developer and maintainer"
|
||||
}
|
||||
],
|
||||
"description": "Package for handling column sorting in Laravel 6.x",
|
||||
"keywords": [
|
||||
"column",
|
||||
"laravel",
|
||||
"sort",
|
||||
"sortable",
|
||||
"sorting"
|
||||
],
|
||||
"time": "2020-03-08T12:26:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-diactoros",
|
||||
"version": "2.3.1",
|
||||
@@ -8501,6 +8558,7 @@
|
||||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2019-09-17T06:23:10+00:00"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -44,7 +44,7 @@ return [
|
||||
],
|
||||
[
|
||||
'name' => 'header_description',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
|
||||
],
|
||||
[
|
||||
'name' => 'features_title',
|
||||
@@ -52,7 +52,7 @@ return [
|
||||
],
|
||||
[
|
||||
'name' => 'features_description',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
|
||||
],
|
||||
[
|
||||
'name' => 'feature_title_1',
|
||||
@@ -84,7 +84,7 @@ return [
|
||||
],
|
||||
[
|
||||
'name' => 'pricing_description',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
|
||||
],
|
||||
[
|
||||
'name' => 'get_started_title',
|
||||
@@ -92,7 +92,7 @@ return [
|
||||
],
|
||||
[
|
||||
'name' => 'get_started_description',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
|
||||
],
|
||||
[
|
||||
'name' => 'footer_content',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
return [
|
||||
|
||||
'version' => '1.7.6',
|
||||
'version' => '1.7.7',
|
||||
|
||||
// Define size of chunk uploaded by MB. E.g. integer 128 means chunk size will be 128MB.
|
||||
'chunk_size' => env('CHUNK_SIZE', '128'),
|
||||
|
||||
@@ -35,7 +35,7 @@ class ContentSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'name' => 'header_description',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
|
||||
],
|
||||
[
|
||||
'name' => 'features_title',
|
||||
@@ -43,7 +43,7 @@ class ContentSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'name' => 'features_description',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
|
||||
],
|
||||
[
|
||||
'name' => 'feature_title_1',
|
||||
@@ -75,7 +75,7 @@ class ContentSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'name' => 'pricing_description',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
|
||||
],
|
||||
[
|
||||
'name' => 'get_started_title',
|
||||
@@ -83,7 +83,7 @@ class ContentSeeder extends Seeder
|
||||
],
|
||||
[
|
||||
'name' => 'get_started_description',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
|
||||
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Truly freedom.',
|
||||
],
|
||||
[
|
||||
'name' => 'footer_content',
|
||||
|
||||
2
public/chunks/admin-account.js
vendored
2
public/chunks/admin-account.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/app-appearance.js
vendored
2
public/chunks/app-appearance.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/app-billings.js
vendored
2
public/chunks/app-billings.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/app-email.js
vendored
2
public/chunks/app-email.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/app-index.js
vendored
2
public/chunks/app-index.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/app-others.js
vendored
2
public/chunks/app-others.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/app-payments.js
vendored
2
public/chunks/app-payments.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/app-setup.js
vendored
2
public/chunks/app-setup.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/dashboard.js
vendored
2
public/chunks/dashboard.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
public/chunks/invoices.js
vendored
2
public/chunks/invoices.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/page-edit.js
vendored
2
public/chunks/page-edit.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/pages.js
vendored
2
public/chunks/pages.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/plan-delete.js
vendored
2
public/chunks/plan-delete.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/plan-settings.js
vendored
2
public/chunks/plan-settings.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/plan-subscribers.js
vendored
2
public/chunks/plan-subscribers.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/plans.js
vendored
2
public/chunks/plans.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/profile.js
vendored
2
public/chunks/profile.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
public/chunks/settings-invoices.js
vendored
2
public/chunks/settings-invoices.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/settings-password.js
vendored
2
public/chunks/settings-password.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/settings-payment-methods.js
vendored
2
public/chunks/settings-payment-methods.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/settings-storage.js
vendored
2
public/chunks/settings-storage.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/settings-subscription.js
vendored
2
public/chunks/settings-subscription.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/upgrade-billing.js
vendored
2
public/chunks/upgrade-billing.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/upgrade.js
vendored
2
public/chunks/upgrade.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/user-delete.js
vendored
2
public/chunks/user-delete.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/user-detail.js
vendored
2
public/chunks/user-detail.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/user-invoices.js
vendored
2
public/chunks/user-invoices.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/user-password.js
vendored
2
public/chunks/user-password.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/user-storage.js
vendored
2
public/chunks/user-storage.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/user-subscription.js
vendored
2
public/chunks/user-subscription.js
vendored
File diff suppressed because one or more lines are too long
2
public/chunks/users.js
vendored
2
public/chunks/users.js
vendored
File diff suppressed because one or more lines are too long
2
public/js/main.js
vendored
2
public/js/main.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<WidgetWrapper :icon="icon" :title="title">
|
||||
<DatatableWrapper v-if="users" :paginator="false" :columns="columns" :data="users" class="table table-users">
|
||||
<DatatableWrapper @init="isLoading = false" api="/api/dashboard/new-users" :paginator="false" :columns="columns" class="table table-users">
|
||||
<template slot-scope="{ row }">
|
||||
<tr>
|
||||
<td style="width: 300px">
|
||||
@@ -65,27 +65,26 @@
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
users: undefined,
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'data.attributes.name',
|
||||
sortable: true
|
||||
field: 'name',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.role'),
|
||||
field: 'data.attributes.role',
|
||||
sortable: true
|
||||
field: 'role',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_used'),
|
||||
field: 'relationships.storage.data.attributes.used',
|
||||
sortable: true
|
||||
field: 'used',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.created_at'),
|
||||
field: 'data.attributes.created_at_formatted',
|
||||
sortable: true
|
||||
field: 'created_at',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
@@ -107,13 +106,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/dashboard/new-users')
|
||||
.then(response => {
|
||||
this.users = response.data.data
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="page-tab">
|
||||
<div id="loader" v-if="isLoading">
|
||||
<div id="loader" v-show="isLoading">
|
||||
<Spinner></Spinner>
|
||||
</div>
|
||||
<slot v-if="! isLoading"></slot>
|
||||
<slot v-show="! isLoading"></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -4,410 +4,489 @@
|
||||
<thead class="table-header">
|
||||
<tr>
|
||||
<th
|
||||
v-for="(column, index) in columns"
|
||||
@click="sort(column.field, column.sortable, index)"
|
||||
:key="index"
|
||||
:class="{ sortable: column.sortable }"
|
||||
v-if="! column.hidden"
|
||||
v-for="(column, index) in columns"
|
||||
@click="sort(column.field, column.sortable)"
|
||||
:key="index"
|
||||
:class="{ 'sortable': column.sortable }"
|
||||
v-if="! column.hidden"
|
||||
>
|
||||
<span>{{ column.label }}</span>
|
||||
|
||||
<chevron-up-icon v-if="false" :class="{ 'arrow-down': filter.sort === 'ASC' }" size="14" class="filter-arrow"></chevron-up-icon>
|
||||
<chevron-up-icon v-if="column.sortable" :class="{ 'arrow-down': filter.sort === 'ASC' }" size="14" class="filter-arrow"></chevron-up-icon>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="table-body">
|
||||
<slot v-for="row in visibleData" :row="row">
|
||||
<slot v-for="row in data.data" :row="row">
|
||||
<DatatableCell :data="row" :key="row.id"/>
|
||||
</slot>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
<div v-if="hasData && paginator" class="paginator-wrapper">
|
||||
<ul v-if="chunks.length > 1" class="pagination">
|
||||
<li class="page-item">
|
||||
<a
|
||||
@click="goToPage(pageIndex - 1)"
|
||||
class="page-link"
|
||||
:class="{ disabled: pageIndex == 0 }"
|
||||
>
|
||||
|
||||
<slot v-if="! isLoading && ! hasData" name="empty-page"></slot>
|
||||
|
||||
<div v-if="paginator && hasData" class="paginator-wrapper">
|
||||
|
||||
<!--Show if there is only 6 pages-->
|
||||
<ul v-if="data.meta.total > 20 && data.meta.last_page <= 6" class="pagination">
|
||||
|
||||
<!--Go previous icon-->
|
||||
<li class="page-item previous">
|
||||
<a @click="goToPage(pageIndex - 1)" class="page-link" :class="{ disabled: pageIndex == 0 }">
|
||||
<chevron-left-icon size="14" class="icon"></chevron-left-icon>
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
v-for="(row, index) in chunks"
|
||||
:key="index"
|
||||
class="page-item"
|
||||
@click="goToPage(index)"
|
||||
>
|
||||
<a
|
||||
class="page-link"
|
||||
:class="{ active: pageIndex == index }">
|
||||
{{ index + 1 }}
|
||||
|
||||
<li v-for="(page, index) in 6" :key="index" class="page-item" @click="goToPage(page)">
|
||||
<a class="page-link" :class="{ active: pageIndex === page }">
|
||||
{{ page }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a
|
||||
@click="goToPage(pageIndex + 1)"
|
||||
class="page-link"
|
||||
:class="{ disabled: pageIndex + 1 == chunks.length }"
|
||||
>
|
||||
|
||||
<!--Go next icon-->
|
||||
<li class="page-item next">
|
||||
<a @click="goToPage(pageIndex + 1)" class="page-link" :class="{ disabled: pageIndex + 1 == data.meta.last_page }">
|
||||
<chevron-right-icon size="14" class="icon"></chevron-right-icon>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="paginator-info">{{ $t('datatable.paginate_info', {visible: visibleData.length, total: data.length}) }}</span>
|
||||
|
||||
<!--Show if there is more than 6 pages-->
|
||||
<ul v-if="data.meta.total > 20 && data.meta.last_page > 6" class="pagination">
|
||||
|
||||
<!--Go previous icon-->
|
||||
<li class="page-item previous">
|
||||
<a @click="goToPage(pageIndex - 1)" class="page-link" :class="{ disabled: pageIndex == 0 }">
|
||||
<chevron-left-icon size="14" class="icon"></chevron-left-icon>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!--Show first Page-->
|
||||
<li class="page-item" v-if="pageIndex >= 5" @click="goToPage(1)">
|
||||
<a class="page-link">
|
||||
1
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li v-if="pageIndex < 5" v-for="(page, index) in 5" :key="index" class="page-item" @click="goToPage(page)">
|
||||
<a class="page-link" :class="{ active: pageIndex === page }">
|
||||
{{ page }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="page-item" v-if="pageIndex >= 5">
|
||||
<a class="page-link">...</a>
|
||||
</li>
|
||||
|
||||
<!--Floated Pages-->
|
||||
<li v-if="pageIndex >= 5 && pageIndex < (data.meta.last_page - 3)" v-for="(page, index) in floatPages" :key="index" class="page-item" @click="goToPage(page)">
|
||||
<a class="page-link" :class="{ active: pageIndex === page }">
|
||||
{{ page }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="page-item" v-if="pageIndex < (data.meta.last_page - 3)">
|
||||
<a class="page-link">...</a>
|
||||
</li>
|
||||
|
||||
<li v-if="pageIndex > (data.meta.last_page - 4)" v-for="(page, index) in 5" :key="index" class="page-item" @click="goToPage(data.meta.last_page - (4 - index))">
|
||||
<a class="page-link" :class="{ active: pageIndex === (data.meta.last_page - (4 - index)) }">
|
||||
{{ data.meta.last_page - (4 - index) }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!--Show last page-->
|
||||
<li class="page-item" v-if="pageIndex < (data.meta.last_page - 3)" @click="goToPage(data.meta.last_page)">
|
||||
<a class="page-link">
|
||||
{{ data.meta.last_page }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!--Go next icon-->
|
||||
<li class="page-item next">
|
||||
<a @click="goToPage(pageIndex + 1)" class="page-link" :class="{ disabled: pageIndex + 1 == data.meta.last_page }">
|
||||
<chevron-right-icon size="14" class="icon"></chevron-right-icon>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<span class="paginator-info">{{ $t('datatable.paginate_info', {visible: data.meta.per_page, total: data.meta.total}) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ChevronUpIcon, ChevronLeftIcon, ChevronRightIcon } from 'vue-feather-icons'
|
||||
import DatatableCell from '@/components/Others/Tables/DatatableCell'
|
||||
import {chunk, sortBy} from 'lodash'
|
||||
import {ChevronUpIcon, ChevronLeftIcon, ChevronRightIcon} from 'vue-feather-icons'
|
||||
import DatatableCell from '@/components/Others/Tables/DatatableCell'
|
||||
import {chunk, sortBy} from 'lodash'
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
props: ['columns', 'data', 'scope', 'paginator'],
|
||||
components: {
|
||||
ChevronRightIcon,
|
||||
ChevronLeftIcon,
|
||||
DatatableCell,
|
||||
ChevronUpIcon,
|
||||
export default {
|
||||
name: 'DatatableWrapper',
|
||||
props: [
|
||||
'columns', 'scope', 'paginator', 'api', 'tableData'
|
||||
],
|
||||
components: {
|
||||
ChevronRightIcon,
|
||||
ChevronLeftIcon,
|
||||
DatatableCell,
|
||||
ChevronUpIcon,
|
||||
},
|
||||
computed: {
|
||||
hasData() {
|
||||
return this.data && this.data.data && this.data.data.length > 0
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
items_per_view: 20,
|
||||
pageIndex: 0,
|
||||
paginatorVisible: true,
|
||||
chunks: [],
|
||||
filter: {
|
||||
sort: 'DESC',
|
||||
field: undefined,
|
||||
index: undefined,
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToPage(index) {
|
||||
if (index == this.chunks.length || index == -1) return
|
||||
|
||||
// Update page index
|
||||
this.pageIndex = index
|
||||
},
|
||||
sort(field, sortable, index) {
|
||||
|
||||
// Prevent sortable if is disabled
|
||||
if (!sortable) return
|
||||
|
||||
// Set filter
|
||||
this.filter.field = field
|
||||
this.filter.index = index
|
||||
|
||||
// Set sorting direction
|
||||
if (this.filter.sort === 'DESC') {
|
||||
this.filter.sort = 'ASC'
|
||||
} else if (this.filter.sort === 'ASC') {
|
||||
this.filter.sort = 'DESC'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasData() {
|
||||
|
||||
return this.data.length > 0 ? true : false
|
||||
},
|
||||
visibleData() {
|
||||
|
||||
// Prefent errors when data is empty
|
||||
if (!this.hasData) return
|
||||
|
||||
// Reconfigure data
|
||||
if (this.filter.field) {
|
||||
|
||||
// Set chunks with sorting
|
||||
if (this.filter.sort === 'DESC') {
|
||||
|
||||
// DESC
|
||||
this.chunks = chunk(sortBy(this.data, this.filter.field), this.items_per_view)
|
||||
} else {
|
||||
|
||||
// ASC
|
||||
this.chunks = chunk(sortBy(this.data, this.filter.field).reverse(), this.items_per_view)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Get data to chunks
|
||||
this.chunks = chunk(this.data, this.items_per_view)
|
||||
}
|
||||
|
||||
// Return chunks
|
||||
return this.chunks[this.pageIndex]
|
||||
floatPages() {
|
||||
return [(this.pageIndex - 1), this.pageIndex, (this.pageIndex + 1)];
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
data: undefined,
|
||||
isLoading: true,
|
||||
pageIndex: 1,
|
||||
filter: {
|
||||
sort: 'DESC',
|
||||
field: undefined,
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToPage(index) {
|
||||
if (index > this.data.meta.last_page || index === 0) return
|
||||
|
||||
this.pageIndex = index
|
||||
|
||||
this.getPage(index)
|
||||
},
|
||||
sort(field, sortable) {
|
||||
|
||||
// Prevent sortable if is disabled
|
||||
if (!sortable) return
|
||||
|
||||
// Set filter
|
||||
this.filter.field = field
|
||||
|
||||
// Set sorting direction
|
||||
if (this.filter.sort === 'DESC') {
|
||||
this.filter.sort = 'ASC'
|
||||
} else if (this.filter.sort === 'ASC') {
|
||||
this.filter.sort = 'DESC'
|
||||
}
|
||||
|
||||
this.getPage(this.pageIndex)
|
||||
},
|
||||
getPage(page) {
|
||||
|
||||
// Get api URI
|
||||
this.URI = this.api;
|
||||
|
||||
// Set page index
|
||||
if (this.paginator)
|
||||
this.URI = this.URI + '?page=' + page
|
||||
|
||||
// Add filder URI if is defined sorting
|
||||
if (this.filter.field)
|
||||
|
||||
this.URI = this.URI + (this.paginator ? '&' : '?') + 'sort=' + this.filter.field + '&direction=' + this.filter.sort
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
// Get data
|
||||
axios.get(this.URI)
|
||||
.then(response => {
|
||||
this.data = response.data
|
||||
this.$emit('data', response.data)
|
||||
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
.finally(() => {
|
||||
this.$emit('init', true)
|
||||
this.isLoading = false
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.api)
|
||||
this.getPage(this.pageIndex)
|
||||
|
||||
if (this.tableData)
|
||||
this.data = this.tableData,
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@assets/vue-file-manager/_variables';
|
||||
@import '@assets/vue-file-manager/_mixins';
|
||||
@import '@assets/vue-file-manager/_variables';
|
||||
@import '@assets/vue-file-manager/_mixins';
|
||||
|
||||
.datatable {
|
||||
height: 100%;
|
||||
}
|
||||
.datatable {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
@include transition;
|
||||
}
|
||||
.table-row {
|
||||
@include transition;
|
||||
}
|
||||
|
||||
.table-row-enter,
|
||||
.table-row-leave-to {
|
||||
opacity: 0;
|
||||
@include transform(translateY(-100%));
|
||||
}
|
||||
.table-row-enter,
|
||||
.table-row-leave-to {
|
||||
opacity: 0;
|
||||
@include transform(translateY(-100%));
|
||||
}
|
||||
|
||||
.table-row-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
.table-row-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.table {
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
overflow-x: auto;
|
||||
|
||||
tr {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
overflow-x: auto;
|
||||
|
||||
td, th {
|
||||
&:first-child {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 15px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-header {
|
||||
margin-bottom: 10px;
|
||||
|
||||
tr {
|
||||
width: 100%;
|
||||
|
||||
td, th {
|
||||
&:first-child {
|
||||
padding-left: 15px;
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
|
||||
span {
|
||||
color: $theme;
|
||||
font-weight: 700;
|
||||
@include font-size(12);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&.sortable {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
.filter-arrow {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 15px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter-arrow {
|
||||
vertical-align: middle;
|
||||
margin-left: 8px;
|
||||
@include transition;
|
||||
opacity: 0;
|
||||
|
||||
path {
|
||||
fill: $text-muted;
|
||||
}
|
||||
|
||||
&.arrow-down {
|
||||
@include transform(rotate(180deg));
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 13px;
|
||||
color: $text-muted;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
tr {
|
||||
border-radius: 8px;
|
||||
//border-bottom: 1px solid #f5f5f5;
|
||||
|
||||
&:hover {
|
||||
background: $light_background;
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: 12px;
|
||||
|
||||
&:last-child {
|
||||
button {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span, a.page-link {
|
||||
@include font-size(15);
|
||||
font-weight: 700;
|
||||
padding: 10px 35px 10px 0;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
.page-item {
|
||||
padding: 3px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.page-link {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: block;
|
||||
color: $text;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
line-height: 2.4;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
@include transition(0.15s);
|
||||
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background: $light_background;
|
||||
color: $text;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $text;
|
||||
background: $light_background;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
|
||||
svg path {
|
||||
fill: $text-muted;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.paginator-wrapper {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 40px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.paginator-info {
|
||||
font-size: 13px;
|
||||
color: $text-muted;
|
||||
}
|
||||
}
|
||||
|
||||
.user-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 45px;
|
||||
margin-right: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 690px) {
|
||||
.paginator-wrapper {
|
||||
display: block;
|
||||
text-align: center;
|
||||
|
||||
.paginator-info {
|
||||
margin-top: 10px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
.table {
|
||||
|
||||
.table-header {
|
||||
margin-bottom: 10px;
|
||||
|
||||
tr {
|
||||
td, th {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
|
||||
span {
|
||||
color: $theme;
|
||||
font-weight: 700;
|
||||
@include font-size(12);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&.sortable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter-arrow {
|
||||
vertical-align: middle;
|
||||
margin-left: 8px;
|
||||
@include transition;
|
||||
|
||||
path {
|
||||
fill: $text-muted;
|
||||
}
|
||||
|
||||
&.arrow-down {
|
||||
@include transform(rotate(180deg));
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 13px;
|
||||
color: $text-muted;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
tr {
|
||||
border-radius: 8px;
|
||||
//border-bottom: 1px solid #f5f5f5;
|
||||
|
||||
tr, th {
|
||||
&:hover {
|
||||
background: $light_background;
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: 12px;
|
||||
|
||||
&:last-child {
|
||||
button {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span, a.page-link {
|
||||
@include font-size(15);
|
||||
font-weight: 700;
|
||||
padding: 10px 35px 10px 0;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
.page-item {
|
||||
padding: 3px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.page-link {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: block;
|
||||
color: $text;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
line-height: 2.4;
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
@include transition(0.15s);
|
||||
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
background: $light_background;
|
||||
color: $text;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $text;
|
||||
background: $light_background;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
|
||||
svg path {
|
||||
fill: $text-muted;
|
||||
background: $dark_mode_foreground;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.paginator-wrapper {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 40px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.paginator-info {
|
||||
font-size: 13px;
|
||||
color: $text-muted;
|
||||
color: $dark_mode_text_secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.user-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
.pagination {
|
||||
|
||||
img {
|
||||
width: 45px;
|
||||
margin-right: 22px;
|
||||
}
|
||||
}
|
||||
.page-link {
|
||||
color: $dark_mode_text_secondary;
|
||||
|
||||
@media only screen and (max-width: 690px) {
|
||||
.paginator-wrapper {
|
||||
display: block;
|
||||
text-align: center;
|
||||
|
||||
.paginator-info {
|
||||
margin-top: 10px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
|
||||
.table {
|
||||
|
||||
.table-header {
|
||||
|
||||
tr {
|
||||
td, th {
|
||||
|
||||
span {
|
||||
color: $theme;
|
||||
}
|
||||
}
|
||||
}
|
||||
svg polyline {
|
||||
stroke: $dark_mode_text_primary;
|
||||
}
|
||||
|
||||
.table-body {
|
||||
tr, th {
|
||||
&:hover {
|
||||
background: $dark_mode_foreground;
|
||||
}
|
||||
}
|
||||
&:hover:not(.disabled) {
|
||||
color: $theme;
|
||||
background: rgba($theme, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.paginator-wrapper {
|
||||
|
||||
.paginator-info {
|
||||
color: $dark_mode_text_secondary;
|
||||
&.active {
|
||||
color: $theme;
|
||||
background: rgba($theme, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
|
||||
.page-link {
|
||||
color: $dark_mode_text_secondary;
|
||||
&.disabled {
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
|
||||
svg polyline {
|
||||
stroke: $dark_mode_text_primary;
|
||||
}
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
color: $theme;
|
||||
background: rgba($theme, 0.1);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $theme;
|
||||
background: rgba($theme, 0.1);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
|
||||
svg polyline {
|
||||
stroke: $dark_mode_text_secondary;
|
||||
}
|
||||
stroke: $dark_mode_text_secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -135,9 +135,7 @@
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/settings/email', this.mail, {
|
||||
_method: 'put'
|
||||
})
|
||||
.post('/api/settings/email', this.mail)
|
||||
.then(() => {
|
||||
|
||||
events.$emit('toaster', {
|
||||
|
||||
@@ -710,9 +710,7 @@
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/settings/stripe', this.stripeCredentials, {
|
||||
_method: 'put'
|
||||
})
|
||||
.post('/api/settings/stripe', this.stripeCredentials)
|
||||
.then(() => {
|
||||
|
||||
// End loading
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
<div id="single-page">
|
||||
|
||||
<!--Page Content-->
|
||||
<div id="page-content" v-if="! isLoading && invoices.length > 0">
|
||||
<div id="page-content" v-show="! isLoading && config.stripe_public_key">
|
||||
<MobileHeader :title="$router.currentRoute.meta.title"/>
|
||||
<PageHeader :title="$router.currentRoute.meta.title"/>
|
||||
|
||||
<div class="content-page">
|
||||
<DatatableWrapper :paginator="true" :columns="columns" :data="invoices" class="table">
|
||||
<div class="content-page" v-if="config.stripe_public_key">
|
||||
<DatatableWrapper @data="invoices = $event" @init="isLoading = false" api="/api/invoices" :paginator="false" :columns="columns" class="table">
|
||||
<template slot-scope="{ row }">
|
||||
<tr>
|
||||
<td>
|
||||
@@ -126,27 +126,27 @@
|
||||
{
|
||||
label: this.$t('admin_page_invoices.table.number'),
|
||||
field: 'data.attributes.order',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_invoices.table.total'),
|
||||
field: 'data.attributes.bag.amount',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_invoices.table.plan'),
|
||||
field: 'data.attributes.bag.amount',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_invoices.table.payed'),
|
||||
field: 'data.attributes.created_at',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_invoices.table.user'),
|
||||
field: 'relationships.user.data.attributes.name',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
@@ -156,15 +156,8 @@
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.config.stripe_public_key) {
|
||||
axios.get('/api/invoices')
|
||||
.then(response => {
|
||||
this.invoices = response.data.data
|
||||
this.isLoading = false
|
||||
})
|
||||
} else {
|
||||
if (! this.config.stripe_public_key)
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div id="single-page">
|
||||
<div id="page-content" v-if="! isLoading && pages.length > 0">
|
||||
<div id="page-content" v-show="! isLoading">
|
||||
<MobileHeader :title="$router.currentRoute.meta.title"/>
|
||||
<PageHeader :title="$router.currentRoute.meta.title"/>
|
||||
|
||||
<div class="content-page">
|
||||
<DatatableWrapper :paginator="false" :columns="columns" :data="pages" class="table table-users">
|
||||
<DatatableWrapper @init="isLoading = false" api="/api/pages" :paginator="false" :columns="columns" class="table table-users">
|
||||
<template slot-scope="{ row }">
|
||||
<tr>
|
||||
<td class="name" style="min-width: 200px">
|
||||
@@ -75,21 +75,20 @@
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
pages: undefined,
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('admin_pages.table.page'),
|
||||
field: 'data.attributes.title',
|
||||
field: 'title',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_pages.table.slug'),
|
||||
field: 'data.attributes.slug',
|
||||
field: 'slug',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_pages.table.status'),
|
||||
field: 'data.attributes.visibility',
|
||||
field: 'visibility',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
@@ -104,13 +103,6 @@
|
||||
this.$updateText('/pages/' + slug, 'visibility', val)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/pages')
|
||||
.then(response => {
|
||||
this.pages = response.data.data
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div id="single-page">
|
||||
|
||||
<!--Page Content-->
|
||||
<div id="page-content" v-if="! isLoading && plans.length > 0">
|
||||
<!--Stripe plans-->
|
||||
<div id="page-content" v-show="stripeConfiguredWithPlans">
|
||||
<MobileHeader :title="$router.currentRoute.meta.title"/>
|
||||
<PageHeader :title="$router.currentRoute.meta.title"/>
|
||||
|
||||
<div class="content-page">
|
||||
<div class="content-page" v-if="config.stripe_public_key">
|
||||
<div class="table-tools">
|
||||
<div class="buttons">
|
||||
<router-link :to="{name: 'PlanCreate'}">
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<DatatableWrapper :paginator="false" :columns="columns" :data="plans" class="table table-users">
|
||||
<DatatableWrapper @data="plans = $event" @init="isLoading = false" api="/api/plans" :paginator="false" :columns="columns" class="table table-users">
|
||||
<template slot-scope="{ row }">
|
||||
<tr>
|
||||
<td style="max-width: 80px">
|
||||
@@ -64,9 +64,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Empty plans-->
|
||||
<!--Stripe configured but has empty plans-->
|
||||
<EmptyPageContent
|
||||
v-if="! isLoading && plans.length === 0 && config.stripe_public_key"
|
||||
v-if="isEmptyPlans"
|
||||
icon="file"
|
||||
:title="$t('admin_page_plans.empty.title')"
|
||||
:description="$t('admin_page_plans.empty.description')"
|
||||
@@ -76,9 +76,9 @@
|
||||
</router-link>
|
||||
</EmptyPageContent>
|
||||
|
||||
<!--Stripe Not Configured-->
|
||||
<!--Stripe is Not Configured-->
|
||||
<EmptyPageContent
|
||||
v-if="! config.stripe_public_key"
|
||||
v-if="stripeIsNotConfigured"
|
||||
icon="settings"
|
||||
:title="$t('activation.stripe.title')"
|
||||
:description="$t('activation.stripe.description')"
|
||||
@@ -126,6 +126,18 @@
|
||||
Edit2Icon,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
isEmptyPlans() {
|
||||
return ! this.isLoading && this.plans.length === 0 && this.config.stripe_public_key
|
||||
},
|
||||
stripeIsNotConfigured() {
|
||||
return ! this.config.stripe_public_key
|
||||
},
|
||||
stripeConfiguredWithPlans() {
|
||||
return ! this.isLoading && this.config.stripe_public_key
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
@@ -134,27 +146,27 @@
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.status'),
|
||||
field: 'data.attributes.status',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.name'),
|
||||
field: 'data.attributes.name',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.subscribers'),
|
||||
field: 'data.attributes.subscribers',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.price'),
|
||||
field: 'data.attributes.price',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.storage_capacity'),
|
||||
field: 'data.attributes.capacity',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
@@ -163,24 +175,14 @@
|
||||
],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
methods: {
|
||||
changeStatus(val, id) {
|
||||
this.$updateText('/plans/' + id + '/update', 'is_active', val)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.config.stripe_public_key) {
|
||||
axios.get('/api/plans')
|
||||
.then(response => {
|
||||
this.plans = response.data.data
|
||||
this.isLoading = false
|
||||
})
|
||||
} else {
|
||||
if (! this.config.stripe_public_key)
|
||||
this.isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<PageTabGroup v-if="subscribers && subscribers.length > 0">
|
||||
<DatatableWrapper :paginator="true" :columns="columns" :data="subscribers" class="table">
|
||||
<PageTabGroup>
|
||||
<DatatableWrapper @init="isLoading = false" :api="'/api/plans/' + this.$route.params.id + '/subscribers'" :paginator="false" :columns="columns" :data="subscribers" class="table">
|
||||
|
||||
<!--Table data content-->
|
||||
<template slot-scope="{ row }">
|
||||
<tr>
|
||||
<td>
|
||||
@@ -30,11 +32,15 @@
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<!--Empty page-->
|
||||
<template v-slot:empty-page>
|
||||
<InfoBox>
|
||||
<p>{{ $t('admin_page_plans.subscribers.empty') }}</p>
|
||||
</InfoBox>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</PageTabGroup>
|
||||
<InfoBox v-else>
|
||||
<p>{{ $t('admin_page_plans.subscribers.empty') }}</p>
|
||||
</InfoBox>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
@@ -62,17 +68,17 @@
|
||||
data() {
|
||||
return {
|
||||
subscribers: undefined,
|
||||
isLoading: false,
|
||||
isLoading: true,
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'data.attributes.name',
|
||||
field: 'name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_used'),
|
||||
field: 'data.relationships.storage.data.attributes.used',
|
||||
sortable: true
|
||||
field: 'used',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
@@ -81,13 +87,6 @@
|
||||
],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/plans/' + this.$route.params.id + '/subscribers')
|
||||
.then(response => {
|
||||
this.subscribers = response.data.data
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<div id="single-page">
|
||||
<div id="page-content" v-if="! isLoading">
|
||||
<div id="page-content">
|
||||
<MobileHeader :title="$router.currentRoute.meta.title"/>
|
||||
<PageHeader :title="$router.currentRoute.meta.title"/>
|
||||
|
||||
<div class="content-page">
|
||||
|
||||
<!--Table tools-->
|
||||
<div class="table-tools">
|
||||
<div class="buttons">
|
||||
<router-link :to="{name: 'UserCreate'}">
|
||||
@@ -13,11 +15,10 @@
|
||||
</MobileActionButton>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="searching">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<DatatableWrapper :paginator="true" :columns="columns" :data="users" class="table table-users">
|
||||
|
||||
<!--Datatable-->
|
||||
<DatatableWrapper @init="isLoading = false" api="/api/users" :paginator="true" :columns="columns" class="table table-users">
|
||||
<template slot-scope="{ row }">
|
||||
<tr>
|
||||
<td style="min-width: 320px">
|
||||
@@ -113,7 +114,6 @@
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
users: [],
|
||||
columns: undefined,
|
||||
}
|
||||
},
|
||||
@@ -133,34 +133,34 @@
|
||||
this.columns = [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'data.attributes.name',
|
||||
field: 'name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.role'),
|
||||
field: 'data.attributes.role',
|
||||
field: 'role',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.plan'),
|
||||
field: 'data.attributes.subscription',
|
||||
sortable: true,
|
||||
field: 'subscription',
|
||||
sortable: false,
|
||||
hidden: ! this.config.isSaaS,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_used'),
|
||||
field: 'relationships.storage.data.attributes.used',
|
||||
field: 'used',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_capacity'),
|
||||
field: 'relationships.storage.data.attributes.capacity',
|
||||
field: 'settings.storage_capacity',
|
||||
sortable: true,
|
||||
hidden: ! this.config.storageLimit,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.created_at'),
|
||||
field: 'data.attributes.created_at_formatted',
|
||||
field: 'created_at',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
@@ -169,12 +169,6 @@
|
||||
sortable: false
|
||||
},
|
||||
]
|
||||
|
||||
axios.get('/api/users')
|
||||
.then(response => {
|
||||
this.users = response.data.data
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
<template>
|
||||
<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">
|
||||
<PageTab :is-loading="isLoading">
|
||||
<PageTabGroup>
|
||||
<DatatableWrapper
|
||||
@init="isLoading = false"
|
||||
:api="'/api/users/' + this.$route.params.id + '/invoices'"
|
||||
:paginator="false"
|
||||
:columns="columns"
|
||||
class="table"
|
||||
>
|
||||
|
||||
<!--Table data content-->
|
||||
<template slot-scope="{ row }">
|
||||
<tr>
|
||||
<td>
|
||||
@@ -33,11 +41,15 @@
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<!--Empty page-->
|
||||
<template v-slot:empty-page>
|
||||
<InfoBox class="form-fixed-width">
|
||||
<p>{{ $t('admin_page_user.invoices.empty') }}</p>
|
||||
</InfoBox>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</PageTabGroup>
|
||||
<InfoBox v-else>
|
||||
<p>{{ $t('admin_page_user.invoices.empty') }}</p>
|
||||
</InfoBox>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
@@ -63,27 +75,26 @@
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
invoices: undefined,
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('admin_page_invoices.table.number'),
|
||||
field: 'data.attributes.order',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_invoices.table.total'),
|
||||
field: 'data.attributes.bag.amount',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_invoices.table.plan'),
|
||||
field: 'data.attributes.bag.amount',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_invoices.table.payed'),
|
||||
field: 'data.attributes.created_at',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
@@ -92,13 +103,6 @@
|
||||
],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/users/' + this.$route.params.id + '/invoices')
|
||||
.then(response => {
|
||||
this.invoices = response.data.data
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading" class="form-fixed-width">
|
||||
<PageTabGroup v-if="subscription">
|
||||
<PageTabGroup v-if="subscription && !isLoading">
|
||||
<FormLabel>
|
||||
{{ $t('user_subscription.title') }}
|
||||
</FormLabel>
|
||||
@@ -27,7 +27,7 @@
|
||||
</ListInfo>
|
||||
</div>
|
||||
</PageTabGroup>
|
||||
<PageTabGroup v-if="! subscription">
|
||||
<PageTabGroup v-if="! subscription && !isLoading">
|
||||
<InfoBox>
|
||||
<p>{{ $t('admin_page_user.subscription.empty') }}</p>
|
||||
</InfoBox>
|
||||
|
||||
@@ -358,6 +358,7 @@
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
// Show server error
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
@@ -452,16 +453,22 @@
|
||||
|
||||
// Get setup intent for stripe
|
||||
axios.get('/api/stripe/setup-intent')
|
||||
.then(response => this.clientSecret = response.data.client_secret)
|
||||
.then(response => {
|
||||
this.clientSecret = response.data.client_secret
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
|
||||
axios.get('/api/user/payments')
|
||||
.then(response => {
|
||||
|
||||
this.defaultPaymentMethod = response.data.default
|
||||
this.PaymentMethods = response.data.others
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<PageTabGroup v-if="invoices && invoices.length > 0">
|
||||
<PageTabGroup v-show="! isLoading">
|
||||
<FormLabel>{{ $t('user_invoices.title') }}</FormLabel>
|
||||
<DatatableWrapper :paginator="true" :columns="columns" :data="invoices" class="table">
|
||||
<DatatableWrapper @init="isLoading = false" api="/api/user/invoices" :paginator="false" :columns="columns" class="table">
|
||||
|
||||
<!--Table data content-->
|
||||
<template slot-scope="{ row }">
|
||||
<tr>
|
||||
<td>
|
||||
@@ -34,11 +36,15 @@
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<!--Empty page-->
|
||||
<template v-slot:empty-page>
|
||||
<InfoBox>
|
||||
<p>{{ $t('user_invoices.empty') }}</p>
|
||||
</InfoBox>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</PageTabGroup>
|
||||
<InfoBox v-else>
|
||||
<p>{{ $t('user_invoices.empty') }}</p>
|
||||
</InfoBox>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
@@ -69,22 +75,22 @@
|
||||
{
|
||||
label: this.$t('rows.invoice.number'),
|
||||
field: 'data.attributes.order',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('rows.invoice.total'),
|
||||
field: 'data.attributes.bag.amount',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('rows.invoice.plan'),
|
||||
field: 'data.attributes.bag.amount',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('rows.invoice.payed'),
|
||||
field: 'data.attributes.created_at',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
@@ -93,13 +99,6 @@
|
||||
],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/user/invoices')
|
||||
.then(response => {
|
||||
this.invoices = response.data.data
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<PageTabGroup v-if="PaymentMethods && PaymentMethods.length > 0">
|
||||
<PageTabGroup>
|
||||
|
||||
<!--Page title-->
|
||||
<FormLabel>{{ $t('user_payments.title') }}</FormLabel>
|
||||
<div class="page-actions">
|
||||
|
||||
<!--Add payment method button-->
|
||||
<div class="page-actions" v-if="PaymentMethods && PaymentMethods.length > 0">
|
||||
<router-link :to="{name: 'CreatePaymentMethod'}">
|
||||
<MobileActionButton icon="credit-card">
|
||||
{{ $t('user_payments.add_card') }}
|
||||
</MobileActionButton>
|
||||
</router-link>
|
||||
</div>
|
||||
<DatatableWrapper :paginator="false" :columns="columns" :data="PaymentMethods" class="table">
|
||||
|
||||
<!--Payment methods table-->
|
||||
<DatatableWrapper :table-data="{data: PaymentMethods}" :paginator="false" :columns="columns" class="table">
|
||||
|
||||
<!--Table data content-->
|
||||
<template slot-scope="{ row }">
|
||||
<tr :class="{'is-deleting': row.data.attributes.card_id === deletingID}">
|
||||
<td style="width: 300px">
|
||||
@@ -24,11 +32,6 @@
|
||||
</div>
|
||||
</span>
|
||||
</td>
|
||||
<!--<td>
|
||||
<span class="cell-item">
|
||||
<ColorLabel :color="getCardStatusColor(row.data.attributes.status)">{{ getCardStatus(row.data.attributes.status) }}</ColorLabel>
|
||||
</span>
|
||||
</td>-->
|
||||
<td>
|
||||
<span class="cell-item">
|
||||
{{ row.data.attributes.exp_month }} / {{ row.data.attributes.exp_year }}
|
||||
@@ -46,11 +49,15 @@
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<!--Empty page-->
|
||||
<template v-slot:empty-page>
|
||||
<InfoBox>
|
||||
<p>{{ $t('user_payments.empty') }} <router-link v-if="user.data.attributes.stripe_customer" :to="{name: 'CreatePaymentMethod'}">Add new payment method.</router-link> </p>
|
||||
</InfoBox>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</PageTabGroup>
|
||||
<InfoBox v-else>
|
||||
<p>{{ $t('user_payments.empty') }} <router-link v-if="user.data.attributes.stripe_customer" :to="{name: 'CreatePaymentMethod'}">Add new payment method.</router-link> </p>
|
||||
</InfoBox>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
@@ -92,17 +99,12 @@
|
||||
{
|
||||
label: this.$t('rows.card.number'),
|
||||
field: 'data.attributes.total',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
/*{
|
||||
label: this.$t('rows.card.status'),
|
||||
field: 'data.attributes.status',
|
||||
sortable: true
|
||||
},*/
|
||||
{
|
||||
label: this.$t('rows.card.expiration'),
|
||||
field: 'data.attributes.total',
|
||||
sortable: true
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
@@ -127,19 +129,6 @@
|
||||
break
|
||||
}
|
||||
},
|
||||
getCardStatus(status) {
|
||||
switch (status) {
|
||||
case 'active':
|
||||
return 'Active'
|
||||
break
|
||||
case 'card_declined':
|
||||
return 'Rejected'
|
||||
break
|
||||
case 'expired':
|
||||
return 'Expired'
|
||||
break
|
||||
}
|
||||
},
|
||||
setDefaultCard(card) {
|
||||
events.$emit('confirm:open', {
|
||||
title: this.$t('popup_set_card.title'),
|
||||
@@ -166,19 +155,19 @@
|
||||
.then(response => {
|
||||
|
||||
if (response.status == 204) {
|
||||
this.PaymentMethods = []
|
||||
this.PaymentMethods = {}
|
||||
}
|
||||
|
||||
if (response.status == 200) {
|
||||
|
||||
this.defaultPaymentCard = response.data.default
|
||||
|
||||
this.PaymentMethods = response.data.others.data
|
||||
this.PaymentMethods.push(response.data.default)
|
||||
}
|
||||
|
||||
}).finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<PageTabGroup v-if="subscription">
|
||||
<PageTabGroup v-if="subscription && !isLoading">
|
||||
<FormLabel>
|
||||
{{ $t('user_subscription.title') }}
|
||||
</FormLabel>
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</PageTabGroup>
|
||||
<InfoBox v-else>
|
||||
<InfoBox v-if="! subscription && !isLoading">
|
||||
<p>{{ $t('user_subscription.empty') }}</p>
|
||||
</InfoBox>
|
||||
</PageTab>
|
||||
|
||||
@@ -163,8 +163,8 @@ Route::group(['middleware' => ['auth:api', 'auth.master', 'auth.admin', 'scope:m
|
||||
Route::get('/invoices', 'Admin\InvoiceController@index');
|
||||
|
||||
// Settings
|
||||
Route::put('/settings/email', 'SettingController@set_email');
|
||||
Route::put('/settings/stripe', 'SettingController@set_stripe');
|
||||
Route::post('/settings/email', 'SettingController@set_email');
|
||||
Route::post('/settings/stripe', 'SettingController@set_stripe');
|
||||
Route::patch('/settings', 'SettingController@update');
|
||||
Route::get('/settings', 'SettingController@show');
|
||||
Route::get('/flush-cache', 'AppFunctionsController@flush_cache');
|
||||
|
||||
Reference in New Issue
Block a user