index options added

This commit is contained in:
carodej
2020-07-13 09:49:25 +02:00
parent a74c1c7b6e
commit 2ae60003d6
50 changed files with 1106 additions and 135 deletions

View File

@@ -60,7 +60,7 @@ class DashboardController extends Controller
public function new_registrations()
{
return new UsersCollection(
User::take(5)->orderByDesc('created_at')->get()
User::take(7)->orderByDesc('created_at')->get()
);
}
}

View File

@@ -45,9 +45,7 @@ class PagesController extends Controller
public function update(Request $request, $slug) {
$page = Page::where('slug', $slug)->first();
$page->update([
$request->name => $request->value
]);
$page->update(make_single_input($request));
return response('Done', 204);
}

View File

@@ -122,7 +122,9 @@ class UserController extends Controller
return new UserResource($user);
}
$user->update($request->input('attributes'));
// Update user role
$user->role = $request->input('attributes.role');
$user->save();
return new UserResource($user);
}
@@ -181,7 +183,7 @@ class UserController extends Controller
}
// Create user
$user = User::create([
$user = User::forceCreate([
'avatar' => $request->hasFile('avatar') ? $avatar : null,
'name' => $request->name,
'role' => $request->role,
@@ -190,7 +192,7 @@ class UserController extends Controller
]);
// Create settings
$settings = UserSettings::create([
$settings = UserSettings::forceCreate([
'user_id' => $user->id,
'storage_capacity' => $request->storage_capacity,
]);

View File

@@ -18,6 +18,33 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
class AppFunctionsController extends Controller
{
/**
* List of allowed settings to get from public request
*
* @var array
*/
private $whitelist = [
'footer_content',
'get_started_description',
'get_started_title',
'pricing_description',
'pricing_title',
'feature_description_3',
'feature_title_3',
'feature_description_2',
'feature_title_2',
'feature_description_1',
'feature_title_1',
'features_description',
'features_title',
'header_description',
'header_title',
'section_get_started',
'section_pricing_content',
'section_feature_boxes',
'section_features',
];
/**
* Show index page
*
@@ -31,6 +58,7 @@ class AppFunctionsController extends Controller
$connection = $this->get_setup_status();
$settings = json_decode(Setting::all()->pluck('value', 'name')->toJson());
$legal = Page::whereIn('slug', ['terms-of-service', 'privacy-policy', 'cookie-policy'])->get(['visibility', 'title', 'slug']);
} catch (PDOException $e) {
$connection = 'setup-database';
@@ -39,6 +67,7 @@ class AppFunctionsController extends Controller
return view("index")
->with('settings', $settings)
->with('legal', $legal)
->with('installation', $connection);
}
@@ -72,6 +101,32 @@ class AppFunctionsController extends Controller
);
}
/**
* Get selected settings from public route
*
* @param Request $request
* @return mixed
*/
public function get_settings(Request $request)
{
$column = $request->get('column');
if (strpos($column, '|') !== false) {
$columns = collect(explode('|', $column));
$columns->each(function ($column) {
if (! in_array($column, $this->whitelist)) abort(401);
});
return Setting::whereIn('name', $columns)->pluck('value', 'name');
}
if (! in_array($column, $this->whitelist)) abort(401);
return Setting::where('name', $column)->pluck('value', 'name');
}
/**
* Check if setup wizard was passed
*

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Auth;
use App\Http\Requests\Auth\CheckAccountRequest;
use App\Setting;
use App\User;
use App\UserSettings;
use Illuminate\Http\Request;
@@ -64,8 +65,10 @@ class AuthController extends Controller
*/
public function register(Request $request)
{
$settings = Setting::whereIn('name', ['storage_default', 'registration'])->pluck('value', 'name');
// Check if account registration is enabled
if (!config('vuefilemanager.registration')) abort(401);
if (! intval($settings['registration'])) abort(401);
// Validate request
$request->validate([
@@ -81,11 +84,12 @@ class AuthController extends Controller
'password' => Hash::make($request->password),
]);
$default_storage = Setting::where('name', 'storage_default')->first();
// Create settings
// TODO: set default storage capacity
$settings = UserSettings::create([
'user_id' => $user->id,
'storage_capacity' => 5,
'storage_capacity' => $settings['storage_default'],
]);
$response = Route::dispatch(self::make_login_request($request));

View File

@@ -569,7 +569,7 @@ class SetupWizardController extends Controller
$storage_capacity = Setting::where('name', 'storage_default')->first();
// Create settings
UserSettings::create([
UserSettings::forceCreate([
'user_id' => $user->id,
'storage_capacity' => $storage_capacity->value,
]);
@@ -592,9 +592,10 @@ class SetupWizardController extends Controller
'value' => $request->purchase_code,
]);
// Create legal pages
// Create legal pages and index content
if ($request->license === 'Extended') {
Artisan::call('db:seed --class=PageSeeder');
Artisan::call('db:seed --class=ContentSeeder');
}
// Retrieve access token

View File

@@ -99,7 +99,7 @@ class SettingController extends Controller
setEnvironmentValue($col['name'], $col['value']);
});
// Clear cache
// Clear config cache
Artisan::call('config:clear');
return response('Done', 204);

View File

@@ -81,9 +81,6 @@ class AccountController extends Controller
return Demo::response_204();
}
// Check role
if ($request->has('role')) abort(403);
// Update data
if ($request->hasFile('avatar')) {

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Setting;
use App\User;
use Illuminate\Http\Request;
@@ -12,15 +13,19 @@ class WebhookController extends CashierController
/**
* Handle a cancelled customer from a Stripe subscription.
*
* @param array $payload
* @param array $payload
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handleCustomerSubscriptionDeleted($payload) {
public function handleCustomerSubscriptionDeleted($payload)
{
// Get user
$user = User::where('stripe_id', $payload['data']['object']['customer'])->firstOrFail();
// TODO: set default capacity
$user->settings->update(['storage_capacity' => 1]);
// Get default storage capacity
$default_storage = Setting::where('name', 'storage_default')->first();
// Update storage capacity
$user->settings()->update(['storage_capacity' => $default_storage->value]);
return $this->successMethod();
}

View File

@@ -26,6 +26,7 @@ class UserResource extends JsonResource
'id' => (string)$this->id,
'type' => 'user',
'attributes' => [
'storage_capacity' => $this->settings->storage_capacity,
'subscription' => $this->subscribed('main'),
'stripe_customer' => is_null($this->stripe_id) ? false : true,
'name' => env('APP_DEMO') ? $faker->name : $this->name,

View File

@@ -80,13 +80,15 @@ class User extends Authenticatable
{
use HasApiTokens, Notifiable, Billable;
protected $guarded = ['id', 'role'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password', 'avatar', 'role',
'name', 'email', 'password', 'avatar',
];
/**

View File

@@ -8,5 +8,5 @@ class UserSettings extends Model
{
public $timestamps = false;
protected $guarded = ['id'];
protected $guarded = ['id', 'storage_capacity'];
}

View File

@@ -0,0 +1,98 @@
<?php
use App\Setting;
use Illuminate\Database\Seeder;
class ContentSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$columns = collect([
[
'name' => 'section_features',
'value' => '1',
],
[
'name' => 'section_feature_boxes',
'value' => '1',
],
[
'name' => 'section_pricing_content',
'value' => '1',
],
[
'name' => 'section_get_started',
'value' => '1',
],
[
'name' => 'header_title',
'value' => 'Simple <span style="color: #41B883">&</span> Powerfull Personal Cloud Storage',
],
[
'name' => 'header_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
],
[
'name' => 'features_title',
'value' => 'The Fastest Growing <span style="color: #41B883">File Manager</span> on the CodeCanyon Market',
],
[
'name' => 'features_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
],
[
'name' => 'feature_title_1',
'value' => 'Truly Freedom',
],
[
'name' => 'feature_description_1',
'value' => 'You have full control over VueFileManager, no third authorities will control your service or usage, only you.',
],
[
'name' => 'feature_title_2',
'value' => 'The Sky is the Limit',
],
[
'name' => 'feature_description_2',
'value' => 'VueFileManager is cloud storage software. You have to install and running application on your own server hosting.',
],
[
'name' => 'feature_title_3',
'value' => 'No Monthly Fees',
],
[
'name' => 'feature_description_3',
'value' => 'When you running VueFileManager on your own server hosting, anybody can\'t control your content or resell your user data. Your data is safe.',
],
[
'name' => 'pricing_title',
'value' => 'Pick the <span style="color: #41B883;">Best Plan</span> For Your Needs',
],
[
'name' => 'pricing_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
],
[
'name' => 'get_started_title',
'value' => 'Ready to Get <span style="color: #41B883">Started</span><br> With Us?',
],
[
'name' => 'get_started_description',
'value' => 'Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.',
],
[
'name' => 'footer_content',
'value' => '© 2020 Simple & Powerfull Personal Cloud Storage. Developed by <a href="https://hi5ve.digital" target="_blank">Hi5Ve.Digital</a>',
],
]);
$columns->each(function ($content) {
Setting::create($content);
});
}
}

View File

@@ -13,5 +13,6 @@ class DatabaseSeeder extends Seeder
{
$this->call(PageSeeder::class);
$this->call(SettingSeeder::class);
$this->call(ContentSeeder::class);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@@ -111,5 +111,113 @@
"/js/main.be531e9750e90ae0dcf2.hot-update.js": "/js/main.be531e9750e90ae0dcf2.hot-update.js",
"/js/main.efbab434181b2cd4b9d1.hot-update.js": "/js/main.efbab434181b2cd4b9d1.hot-update.js",
"/js/main.6fcb72ff8beccffd8b43.hot-update.js": "/js/main.6fcb72ff8beccffd8b43.hot-update.js",
"/js/main.6e970c831f11b919b087.hot-update.js": "/js/main.6e970c831f11b919b087.hot-update.js"
"/js/main.6e970c831f11b919b087.hot-update.js": "/js/main.6e970c831f11b919b087.hot-update.js",
"/js/main.900973c8fdae1deb912e.hot-update.js": "/js/main.900973c8fdae1deb912e.hot-update.js",
"/js/main.9c02d5878c37b825a3f7.hot-update.js": "/js/main.9c02d5878c37b825a3f7.hot-update.js",
"/js/main.484b9eb38a9b1a091214.hot-update.js": "/js/main.484b9eb38a9b1a091214.hot-update.js",
"/js/main.5c2b59defc71aa8a3472.hot-update.js": "/js/main.5c2b59defc71aa8a3472.hot-update.js",
"/js/main.1a44680d81a8ca81be5e.hot-update.js": "/js/main.1a44680d81a8ca81be5e.hot-update.js",
"/js/main.6a3a4b59af9ffd5d7f98.hot-update.js": "/js/main.6a3a4b59af9ffd5d7f98.hot-update.js",
"/js/main.a2e57a35e0274bf986f9.hot-update.js": "/js/main.a2e57a35e0274bf986f9.hot-update.js",
"/js/main.b010e29071d91defc959.hot-update.js": "/js/main.b010e29071d91defc959.hot-update.js",
"/js/main.3ce47d7ccf2e4488d12f.hot-update.js": "/js/main.3ce47d7ccf2e4488d12f.hot-update.js",
"/js/main.2cd87927a49da0eca20a.hot-update.js": "/js/main.2cd87927a49da0eca20a.hot-update.js",
"/js/main.3da742b1c38aa35a382a.hot-update.js": "/js/main.3da742b1c38aa35a382a.hot-update.js",
"/js/main.fb024d0fb0e14082d363.hot-update.js": "/js/main.fb024d0fb0e14082d363.hot-update.js",
"/js/main.4ff98fd60cc1e0d5a592.hot-update.js": "/js/main.4ff98fd60cc1e0d5a592.hot-update.js",
"/js/main.8fdf63dd356ad93080b1.hot-update.js": "/js/main.8fdf63dd356ad93080b1.hot-update.js",
"/js/main.b5591c59c87fad9cca94.hot-update.js": "/js/main.b5591c59c87fad9cca94.hot-update.js",
"/js/main.08d05327bc7bfbd790c0.hot-update.js": "/js/main.08d05327bc7bfbd790c0.hot-update.js",
"/js/main.7934b8d1da2ae502f1bf.hot-update.js": "/js/main.7934b8d1da2ae502f1bf.hot-update.js",
"/js/main.a6a9a6a295fc2327bc02.hot-update.js": "/js/main.a6a9a6a295fc2327bc02.hot-update.js",
"/js/main.c864056e484e54e7b643.hot-update.js": "/js/main.c864056e484e54e7b643.hot-update.js",
"/js/main.6d59cce872d383922b76.hot-update.js": "/js/main.6d59cce872d383922b76.hot-update.js",
"/js/main.9bce0320a11abbad3bce.hot-update.js": "/js/main.9bce0320a11abbad3bce.hot-update.js",
"/js/main.b5619dc73323576c0045.hot-update.js": "/js/main.b5619dc73323576c0045.hot-update.js",
"/js/main.19c8c40e8db35a850250.hot-update.js": "/js/main.19c8c40e8db35a850250.hot-update.js",
"/js/main.600f6d6180d72ea1d818.hot-update.js": "/js/main.600f6d6180d72ea1d818.hot-update.js",
"/js/main.a31da5ae60dfa2cf29c0.hot-update.js": "/js/main.a31da5ae60dfa2cf29c0.hot-update.js",
"/js/main.961d7f321faabba55c15.hot-update.js": "/js/main.961d7f321faabba55c15.hot-update.js",
"/js/main.ad41cd6115b5ee7ef584.hot-update.js": "/js/main.ad41cd6115b5ee7ef584.hot-update.js",
"/js/main.d84a1de4ce5b926b053c.hot-update.js": "/js/main.d84a1de4ce5b926b053c.hot-update.js",
"/js/main.89caa4f653b4f1ce25f5.hot-update.js": "/js/main.89caa4f653b4f1ce25f5.hot-update.js",
"/js/main.30e0507afe414470d88c.hot-update.js": "/js/main.30e0507afe414470d88c.hot-update.js",
"/js/main.ee5743617cf0d081fb26.hot-update.js": "/js/main.ee5743617cf0d081fb26.hot-update.js",
"/js/main.a4b5b1893a7e1c32f1b3.hot-update.js": "/js/main.a4b5b1893a7e1c32f1b3.hot-update.js",
"/js/main.24492944cd437dffe873.hot-update.js": "/js/main.24492944cd437dffe873.hot-update.js",
"/js/main.54f2b592ab7fa02e6a8b.hot-update.js": "/js/main.54f2b592ab7fa02e6a8b.hot-update.js",
"/js/main.b497bdf060b593fc8959.hot-update.js": "/js/main.b497bdf060b593fc8959.hot-update.js",
"/js/main.bec7b415cb9aedbd0b67.hot-update.js": "/js/main.bec7b415cb9aedbd0b67.hot-update.js",
"/js/main.6403093962e79ddf8901.hot-update.js": "/js/main.6403093962e79ddf8901.hot-update.js",
"/js/main.31c1e7310e5a62790d83.hot-update.js": "/js/main.31c1e7310e5a62790d83.hot-update.js",
"/js/main.3fd718afb0c481e0596a.hot-update.js": "/js/main.3fd718afb0c481e0596a.hot-update.js",
"/js/main.a17121aec9e7917a083f.hot-update.js": "/js/main.a17121aec9e7917a083f.hot-update.js",
"/js/main.fc80135c15c65e513c66.hot-update.js": "/js/main.fc80135c15c65e513c66.hot-update.js",
"/js/main.4ac617261847d252fbea.hot-update.js": "/js/main.4ac617261847d252fbea.hot-update.js",
"/js/main.a22e4185179d0be754aa.hot-update.js": "/js/main.a22e4185179d0be754aa.hot-update.js",
"/js/main.e3e1154efdca38dc206d.hot-update.js": "/js/main.e3e1154efdca38dc206d.hot-update.js",
"/js/main.2424fae6103265a590fe.hot-update.js": "/js/main.2424fae6103265a590fe.hot-update.js",
"/js/main.0d273ece089f84b64f8b.hot-update.js": "/js/main.0d273ece089f84b64f8b.hot-update.js",
"/js/main.d29cc5f3e992aada993a.hot-update.js": "/js/main.d29cc5f3e992aada993a.hot-update.js",
"/js/main.a5ede741aafb4c003659.hot-update.js": "/js/main.a5ede741aafb4c003659.hot-update.js",
"/js/main.cf9b7bb2b7ee80fb9073.hot-update.js": "/js/main.cf9b7bb2b7ee80fb9073.hot-update.js",
"/js/main.803ca40c8fd4bd6b217e.hot-update.js": "/js/main.803ca40c8fd4bd6b217e.hot-update.js",
"/js/main.11bce5213aea38a24836.hot-update.js": "/js/main.11bce5213aea38a24836.hot-update.js",
"/js/main.f11627cd1a4627090b4f.hot-update.js": "/js/main.f11627cd1a4627090b4f.hot-update.js",
"/js/main.1dd5c5dd12975040c0f5.hot-update.js": "/js/main.1dd5c5dd12975040c0f5.hot-update.js",
"/js/main.ad3454a7aa19a51814f5.hot-update.js": "/js/main.ad3454a7aa19a51814f5.hot-update.js",
"/js/main.9ae6092610a06ebb8f24.hot-update.js": "/js/main.9ae6092610a06ebb8f24.hot-update.js",
"/js/main.7934af3ff41800f298c3.hot-update.js": "/js/main.7934af3ff41800f298c3.hot-update.js",
"/js/main.337794316c2fb863f70c.hot-update.js": "/js/main.337794316c2fb863f70c.hot-update.js",
"/js/main.277e8e9d925fb8ca79cf.hot-update.js": "/js/main.277e8e9d925fb8ca79cf.hot-update.js",
"/js/main.2b57e0499c5d07820812.hot-update.js": "/js/main.2b57e0499c5d07820812.hot-update.js",
"/js/main.e0dbd2a3f588969a106b.hot-update.js": "/js/main.e0dbd2a3f588969a106b.hot-update.js",
"/js/main.103e1a04edb53245f4f1.hot-update.js": "/js/main.103e1a04edb53245f4f1.hot-update.js",
"/js/main.bbbb36b9e0969d21281e.hot-update.js": "/js/main.bbbb36b9e0969d21281e.hot-update.js",
"/js/main.feda55ea587760c2d231.hot-update.js": "/js/main.feda55ea587760c2d231.hot-update.js",
"/js/main.8d3606d8d5335db31aff.hot-update.js": "/js/main.8d3606d8d5335db31aff.hot-update.js",
"/js/main.58cbcd8123656aac6d5b.hot-update.js": "/js/main.58cbcd8123656aac6d5b.hot-update.js",
"/js/main.90c4e3b05a72213146cd.hot-update.js": "/js/main.90c4e3b05a72213146cd.hot-update.js",
"/js/main.804506283bc06ffe6acd.hot-update.js": "/js/main.804506283bc06ffe6acd.hot-update.js",
"/js/main.14a86a0b3c5f7b907cf2.hot-update.js": "/js/main.14a86a0b3c5f7b907cf2.hot-update.js",
"/js/main.858f60c2e8f66015c5eb.hot-update.js": "/js/main.858f60c2e8f66015c5eb.hot-update.js",
"/js/main.422421c6ff86cf233266.hot-update.js": "/js/main.422421c6ff86cf233266.hot-update.js",
"/js/main.29580a4fcdc8dcd731ac.hot-update.js": "/js/main.29580a4fcdc8dcd731ac.hot-update.js",
"/js/main.3b4f405a7ea2c82c246f.hot-update.js": "/js/main.3b4f405a7ea2c82c246f.hot-update.js",
"/js/main.2335c31760ef123dfa20.hot-update.js": "/js/main.2335c31760ef123dfa20.hot-update.js",
"/js/main.20f27e839b677741f742.hot-update.js": "/js/main.20f27e839b677741f742.hot-update.js",
"/js/main.850b8d97fa62b94cd330.hot-update.js": "/js/main.850b8d97fa62b94cd330.hot-update.js",
"/js/main.a795578521a6b1906bb8.hot-update.js": "/js/main.a795578521a6b1906bb8.hot-update.js",
"/js/main.5b8e4d1fdb1dd29c7a6c.hot-update.js": "/js/main.5b8e4d1fdb1dd29c7a6c.hot-update.js",
"/js/main.6803dbeae6b983dd318e.hot-update.js": "/js/main.6803dbeae6b983dd318e.hot-update.js",
"/js/main.03eaff4ebaf4d1dd2360.hot-update.js": "/js/main.03eaff4ebaf4d1dd2360.hot-update.js",
"/js/main.7d506e1683ac2193e72d.hot-update.js": "/js/main.7d506e1683ac2193e72d.hot-update.js",
"/js/main.f1e727482e972904c04a.hot-update.js": "/js/main.f1e727482e972904c04a.hot-update.js",
"/js/main.111939c4eab3de32c96f.hot-update.js": "/js/main.111939c4eab3de32c96f.hot-update.js",
"/js/main.2f0cadb1a363fc6a8e11.hot-update.js": "/js/main.2f0cadb1a363fc6a8e11.hot-update.js",
"/js/main.516670314128badfbe09.hot-update.js": "/js/main.516670314128badfbe09.hot-update.js",
"/js/main.5646a0464363571b34d9.hot-update.js": "/js/main.5646a0464363571b34d9.hot-update.js",
"/js/main.21e5cb04d3aa77bf36ac.hot-update.js": "/js/main.21e5cb04d3aa77bf36ac.hot-update.js",
"/js/main.3dce510c80e1a717ecf4.hot-update.js": "/js/main.3dce510c80e1a717ecf4.hot-update.js",
"/js/main.d32c227d8dc052624e15.hot-update.js": "/js/main.d32c227d8dc052624e15.hot-update.js",
"/js/main.4c9fc3515f34e96bf828.hot-update.js": "/js/main.4c9fc3515f34e96bf828.hot-update.js",
"/js/main.937f45c49aeaa67e280b.hot-update.js": "/js/main.937f45c49aeaa67e280b.hot-update.js",
"/js/main.e46867b81adee8249fee.hot-update.js": "/js/main.e46867b81adee8249fee.hot-update.js",
"/js/main.8131cc5de31772e83751.hot-update.js": "/js/main.8131cc5de31772e83751.hot-update.js",
"/js/main.028e2394f07905ab3beb.hot-update.js": "/js/main.028e2394f07905ab3beb.hot-update.js",
"/js/main.4750b981e20dc0485b74.hot-update.js": "/js/main.4750b981e20dc0485b74.hot-update.js",
"/js/main.4dd0cc38708d5af19bf2.hot-update.js": "/js/main.4dd0cc38708d5af19bf2.hot-update.js",
"/js/main.87bcc7919382d37fc1f5.hot-update.js": "/js/main.87bcc7919382d37fc1f5.hot-update.js",
"/js/main.fa895c92ac8dae881f7d.hot-update.js": "/js/main.fa895c92ac8dae881f7d.hot-update.js",
"/js/main.82f7f830b275f3f19bed.hot-update.js": "/js/main.82f7f830b275f3f19bed.hot-update.js",
"/js/main.d05696d9704ef46d4936.hot-update.js": "/js/main.d05696d9704ef46d4936.hot-update.js",
"/js/main.508c024a35ba9c0c12ea.hot-update.js": "/js/main.508c024a35ba9c0c12ea.hot-update.js",
"/js/main.31a8452dea94debec260.hot-update.js": "/js/main.31a8452dea94debec260.hot-update.js",
"/js/main.937b8cae970c37f8704b.hot-update.js": "/js/main.937b8cae970c37f8704b.hot-update.js",
"/js/main.f2a56b60a4ce2b27ae43.hot-update.js": "/js/main.f2a56b60a4ce2b27ae43.hot-update.js",
"/js/main.59e885c12131c7f2e8d2.hot-update.js": "/js/main.59e885c12131c7f2e8d2.hot-update.js",
"/js/main.1a22436c1925672f7fca.hot-update.js": "/js/main.1a22436c1925672f7fca.hot-update.js",
"/js/main.4c1813024db9709cc111.hot-update.js": "/js/main.4c1813024db9709cc111.hot-update.js",
"/js/main.ba274d333e8afccaaab0.hot-update.js": "/js/main.ba274d333e8afccaaab0.hot-update.js",
"/js/main.86cc21e4650e3c88d21d.hot-update.js": "/js/main.86cc21e4650e3c88d21d.hot-update.js"
}

View File

@@ -10,8 +10,8 @@
-->
<preset_collections/>
<framework>vue-json</framework>
<filename>langs.babel</filename>
<source_root_dir>../../</source_root_dir>
<filename>babel.babel</filename>
<source_root_dir></source_root_dir>
<folder_node>
<name></name>
<children>
@@ -5547,6 +5547,184 @@
</concept_node>
</children>
</folder_node>
<folder_node>
<name>page_index</name>
<children>
<concept_node>
<name>get_started_button</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<folder_node>
<name>menu</name>
<children>
<concept_node>
<name>contact_us</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>log_in</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>pricing</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>sign_in</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<concept_node>
<name>sign_feature_1</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>sign_feature_2</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>sign_up_button</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
<name>page_login</name>
<children>
@@ -5749,6 +5927,27 @@
<folder_node>
<name>page_registration</name>
<children>
<concept_node>
<name>agreement</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>sk-SK</language>
<approved>false</approved>
</translation>
<translation>
<language>zh-CHS</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>button_create_account</name>
<definition_loaded>false</definition_loaded>
@@ -10423,28 +10622,28 @@
<language>
<code>en-US</code>
<source_id></source_id>
<source_file>../js/i18n/lang/en.json</source_file>
<source_file>js/i18n/lang/en.json</source_file>
</language>
<language>
<code>sk-SK</code>
<source_id></source_id>
<source_file>../js/i18n/lang/sk.json</source_file>
<source_file>js/i18n/lang/sk.json</source_file>
</language>
<language>
<code>zh-CHS</code>
<source_id></source_id>
<source_file>../js/i18n/lang/cn.json</source_file>
<source_file>js/i18n/lang/cn.json</source_file>
</language>
</languages>
<translation_files>
<translation_file>
<file>../js/i18n/lang/en.json</file>
<file>js/i18n/lang/en.json</file>
</translation_file>
<translation_file>
<file>../js/i18n/lang/sk.json</file>
<file>js/i18n/lang/sk.json</file>
</translation_file>
<translation_file>
<file>../js/i18n/lang/cn.json</file>
<file>js/i18n/lang/cn.json</file>
</translation_file>
</translation_files>
<editor_configuration>

View File

@@ -11,11 +11,11 @@
</header>
<section class="plan-features">
<b class="storage-size">{{ plan.data.attributes.capacity_formatted }}</b>
<span class="storage-description">Of Storage Capacity</span>
<span class="storage-description">{{ $t('page_pricing_tables.storage_capacity') }}</span>
</section>
<footer class="plan-footer">
<b class="price">
{{ plan.data.attributes.price }}/Mo.
{{ plan.data.attributes.price }}/{{ $t('global.monthly_ac') }}
</b>
</footer>
</div>

View File

@@ -1,15 +1,15 @@
<template>
<div class="page-wrapper large get-started">
<div class="page-wrapper large get-started" v-if="index.section_get_started === '1'">
<PageTitle
class="page-title"
type="center"
title="Ready to Get <span style='color: #41B883'>Started</span><br> With Us?"
description="Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom."
:title="index.get_started_title"
:description="index.get_started_description"
></PageTitle>
<router-link tag="button" class="get-started-button" :to="{name: 'SignUp'}">
<span class="content">Get Started</span>
<span class="content">{{ $t('page_index.get_started_button') }}</span>
<chevron-right-icon size="22"></chevron-right-icon>
</router-link>
@@ -44,21 +44,22 @@
import PageTitle from '@/components/Index/Components/PageTitle'
import {
ChevronRightIcon,
UploadCloudIcon,
FolderPlusIcon,
HardDriveIcon,
SettingsIcon,
Trash2Icon,
SearchIcon,
ShareIcon,
CloudIcon,
ImageIcon,
InfoIcon,
GridIcon,
LinkIcon,
StarIcon,
EyeIcon,
} from 'vue-feather-icons'
import ShareIcon from "vue-feather-icons/icons/ShareIcon";
import UploadCloudIcon from "vue-feather-icons/icons/UploadCloudIcon";
import InfoIcon from "vue-feather-icons/icons/InfoIcon";
import { mapGetters } from 'vuex'
export default {
name: 'IndexGetStarted',
@@ -79,7 +80,10 @@
LinkIcon,
StarIcon,
EyeIcon,
}
},
computed: {
...mapGetters(['index']),
},
}
</script>

View File

@@ -1,7 +1,7 @@
<template>
<div class="page-wrapper large hero-screenshot">
<img class="hero-light" src="/assets/images/vuefilemanager-screenshot-light.png" alt="VueFileManager application">
<img class="hero-dark" src="/assets/images/vuefilemanager-screenshot-dark.png" alt="VueFileManager application">
<img class="hero-light" src="/assets/images/vuefilemanager-screenshot-light.png" :alt="config.app_name">
<img class="hero-dark" src="/assets/images/vuefilemanager-screenshot-dark.png" :alt="config.app_name">
<div class="icons">
<link-icon size="20" class="icon"></link-icon>
@@ -22,6 +22,7 @@
</template>
<script>
import { mapGetters } from 'vuex'
import {
FolderPlusIcon,
HardDriveIcon,
@@ -36,7 +37,7 @@
} from 'vue-feather-icons'
export default {
name: 'IndexNavigation',
name: 'IndexHeroScreenshot',
components: {
FolderPlusIcon,
HardDriveIcon,
@@ -48,7 +49,10 @@
LinkIcon,
StarIcon,
EyeIcon,
}
},
computed: {
...mapGetters(['config']),
},
}
</script>

View File

@@ -1,11 +1,12 @@
<template>
<section class="main-features page-wrapper medium">
<PageTitle
v-if="index.section_features === '1'"
type="center"
title="The Fastest Growing <span style='color: #41B883'>File Manager</span> on the CodeCanyon Market"
description="Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom."
:title="index.features_title"
:description="index.features_description"
></PageTitle>
<div class="content">
<div v-if="index.section_feature_boxes === '1'" class="content">
<div class="hero">
<img src="/assets/images/hero-Illustration.svg" alt="Hero">
</div>
@@ -15,10 +16,10 @@
<cloud-icon size="24"></cloud-icon>
</div>
<h3 class="title">
Truly Freedom
{{ index.feature_title_1 }}
</h3>
<p class="description">
You have full control over VueFileManager, no third authorities will control your service or usage, only you.
{{ index.feature_description_1 }}
</p>
</div>
<div class="feature">
@@ -26,10 +27,10 @@
<user-icon size="24"></user-icon>
</div>
<h3 class="title">
The Sky is the Limit
{{ index.feature_title_2 }}
</h3>
<p class="description">
VueFileManager is cloud storage software. You have to install and running application on your own server hosting.
{{ index.feature_description_2 }}
</p>
</div>
<div class="feature">
@@ -37,10 +38,10 @@
<hard-drive-icon size="24"></hard-drive-icon>
</div>
<h3 class="title">
No Monthly Fees
{{ index.feature_title_3 }}
</h3>
<p class="description">
When you running VueFileManager on your own server hosting, anybody can't control your content or resell your user data. Your data is safe.
{{ index.feature_description_3 }}
</p>
</div>
</div>
@@ -49,8 +50,9 @@
</template>
<script>
import PageTitle from '@/components/Index/Components/PageTitle'
import { UserIcon, CloudIcon, HardDriveIcon } from 'vue-feather-icons'
import PageTitle from '@/components/Index/Components/PageTitle'
import { mapGetters } from 'vuex'
export default {
name: 'IndexMainFeatures',
@@ -59,7 +61,10 @@
HardDriveIcon,
CloudIcon,
UserIcon,
}
},
computed: {
...mapGetters(['index']),
},
}
</script>

View File

@@ -1,37 +1,37 @@
<template>
<nav class="main-navigation">
<router-link :to="{name: 'SaaSLandingPage'}" tag="div" class="logo">
<img v-if="config.app_logo_horizontal" :src="config.app_logo_horizontal" :alt="config.app_name">
<img v-if="config.app_logo_horizontal" :src="$getImage(config.app_logo_horizontal)" :alt="config.app_name">
<b v-if="! config.app_logo_horizontal" class="logo-text">{{ config.app_name }}</b>
</router-link>
<div class="navigation">
<ul class="navigation-links">
<li>
<a href="/#pricing">
Pricing
{{ $t('page_index.menu.pricing') }}
</a>
</li>
<li>
<router-link :to="{name: 'ContactUs'}">
Contact Us
{{ $t('page_index.menu.contact_us') }}
</router-link>
</li>
</ul>
<ul class="navigation-links">
<li>
<router-link :to="{name: 'SignIn'}">
Log In
{{ $t('page_index.menu.log_in') }}
</router-link>
</li>
<li>
<router-link class="cta-button" :to="{name: 'SignUp'}">
Sign Up
{{ $t('page_index.menu.sign_in') }}
</router-link>
</li>
</ul>
</div>
<router-link class="cta-button log-in" :to="{name: 'SignIn'}">
Log In
{{ $t('page_index.menu.log_in') }}
</router-link>
</nav>
</template>

View File

@@ -1,41 +1,29 @@
<template>
<footer class="page-wrapper medium">
<router-link :to="{name: 'SaaSLandingPage'}" tag="div" class="logo">
<img v-if="config.app_logo_horizontal" :src="config.app_logo_horizontal" :alt="config.app_name">
<img v-if="config.app_logo_horizontal" :src="$getImage(config.app_logo_horizontal)" :alt="config.app_name">
<b v-if="! config.app_logo_horizontal" class="logo-text">{{ config.app_name }}</b>
</router-link>
<ul class="navigation-links">
<li>
<a href="/#pricing">
Pricing
{{ $t('page_index.menu.pricing') }}
</a>
</li>
<li>
<router-link :to="{name: 'ContactUs'}">
Contact Us
{{ $t('page_index.menu.contact_us') }}
</router-link>
</li>
</ul>
<ul class="navigation-links">
<li>
<router-link :to="{name: 'DynamicPage', params: {slug: 'terms-of-service'}}">
Terms of Service
</router-link>
</li>
<li>
<router-link :to="{name: 'DynamicPage', params: {slug: 'privacy-policy'}}">
Privacy Policy
</router-link>
</li>
<li>
<router-link :to="{name: 'DynamicPage', params: {slug: 'cookie-policy'}}">
Cookie Policy
<li v-if="legal.visibility" v-for="(legal, index) in config.legal" :key="index">
<router-link :to="{name: 'DynamicPage', params: {slug: legal.slug }}">
{{ legal.title }}
</router-link>
</li>
</ul>
<p class="copyright">
© 2020 {{ config.app_name }}. All rights reserved.
</p>
<p class="copyright" v-html="config.app_footer"></p>
</footer>
</template>
@@ -100,6 +88,11 @@
color: $text-muted;
padding-top: 50px;
padding-bottom: 20px;
/deep/ a {
color: $theme;
font-weight: 700;
}
}
@media only screen and (max-width: 960px) {

View File

@@ -1,22 +1,22 @@
<template>
<header class="main-header page-wrapper medium">
<PageTitle
title="Simple <span style='color: #41B883'>&</span> Powerfull Personal Cloud Storage"
description="Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom."
:title="index.header_title"
:description="index.header_description"
></PageTitle>
<router-link class="sign-up-button" :to="{name: 'SignUp'}">
<AuthButton class="button" icon="chevron-right" text="Sign Up Now" />
<AuthButton class="button" icon="chevron-right" :text="$t('page_index.sign_up_button')" />
</router-link>
<div class="features">
<div class="feature">
<credit-card-icon size="19" class="feature-icon"></credit-card-icon>
<b class="feature-title">No credit card required</b>
<b class="feature-title">{{ $t('page_index.sign_feature_1') }}</b>
</div>
<div class="feature">
<hard-drive-icon size="19" class="feature-icon"></hard-drive-icon>
<b class="feature-title">5GB Free storage space</b>
<b class="feature-title">{{ $t('page_index.sign_feature_2', {defaultSpace: config.storageDefaultSpace}) }}</b>
</div>
</div>
</header>
@@ -27,6 +27,7 @@
import PageTitle from '@/components/Index/Components/PageTitle'
import AuthButton from '@/components/Auth/AuthButton'
import { CreditCardIcon } from 'vue-feather-icons'
import { mapGetters } from 'vuex'
export default {
name: 'IndexPageHeader',
@@ -35,7 +36,10 @@
CreditCardIcon,
HardDriveIcon,
AuthButton,
}
},
computed: {
...mapGetters(['index', 'config']),
},
}
</script>

View File

@@ -1,19 +1,17 @@
<template>
<div class="page-wrapper medium pricing" v-if="! isEmpty">
<div class="page-wrapper medium pricing" v-if="! isEmpty && index.section_pricing_content === '1'">
<div id="pricing" class="page-title center">
<h1 class="title">
Pick the <span style="color: #41B883">Best Plan</span> For Your Needs
</h1>
<h1 class="title" v-html="index.pricing_title"></h1>
</div>
<PricingTables class="pricing-tables" @load="pricingLoaded"/>
<div class="page-title center">
<h2 class="description">
Your private cloud storage software build on Laravel & Vue.js. No limits & no monthly fees. Trully freedom.
{{ index.pricing_description }}
</h2>
<router-link class="sign-up-button" :to="{name: 'SignUp'}">
<AuthButton class="button" icon="chevron-right" text="Sign Up Now" />
<AuthButton class="button" icon="chevron-right" :text="$t('page_index.sign_up_button')" />
</router-link>
</div>
@@ -26,6 +24,7 @@
import PricingTables from '@/components/Index/Components/PricingTables'
import AuthButton from '@/components/Auth/AuthButton'
import { CloudIcon } from 'vue-feather-icons'
import { mapGetters } from 'vuex'
export default {
name: 'IndexPricingTables',
@@ -34,6 +33,9 @@
AuthButton,
CloudIcon,
},
computed: {
...mapGetters(['index']),
},
data() {
return {
isEmpty: false,
@@ -41,7 +43,6 @@
},
methods: {
pricingLoaded(pricing) {
if (pricing.length === 0)
this.isEmpty = true
}

View File

@@ -29,6 +29,7 @@
<script>
import ButtonBase from '@/components/FilesView/ButtonBase'
import {HardDriveIcon} from "vue-feather-icons"
import { mapGetters } from 'vuex'
import axios from 'axios'
export default {
@@ -42,6 +43,9 @@
plans: undefined,
}
},
computed: {
...mapGetters(['user']),
},
methods: {
selectPlan(plan) {
this.$emit('selected-plan', plan)
@@ -51,7 +55,9 @@
created() {
axios.get('/api/public/pricing')
.then(response => {
this.plans = response.data
this.plans = response.data.filter(plan => {
return plan.data.attributes.capacity > this.user.data.attributes.storage_capacity
})
this.$emit('load', false)
})
}

View File

@@ -347,6 +347,18 @@
"subtitle": "通过邮箱获得重置链接:",
"title": "忘记密码?"
},
"page_index": {
"get_started_button": "立即注册",
"menu": {
"contact_us": "联系我们",
"log_in": "登录",
"pricing": "价钱",
"sign_in": "注册"
},
"sign_feature_1": "无需信用卡",
"sign_feature_2": "{defaultSpace} 可用存储空间",
"sign_up_button": "立即注册"
},
"page_login": {
"button_next": "下一步",
"placeholder_email": "键入您的邮箱",
@@ -361,6 +373,7 @@
"title": "选择您的计划"
},
"page_registration": {
"agreement": "通过单击“创建帐户”按钮,我同意 {0} 和 {1}。",
"button_create_account": "创建账户",
"have_an_account": "您之前有过账户了么?",
"label_confirm_pass": "确认密码:",

View File

@@ -51,7 +51,7 @@
"admin_page_plans": {
"create_plan_button": "Create Plan",
"delete_plan_button": "Delete Plan",
"disclaimer_delete_plan": "You can delete plan, but, pay attention!",
"disclaimer_delete_plan": "You can delete this plan, but, pay attention! Your plan will be deleted, but users who are subscribed with this plan, will be still charged unless they cancel subscription.",
"disclaimer_edit_price": "Price change for your plan is not available due to Stripe service design. If you wish change your price plan, please, create new plan.",
"empty": {
"button": "Create New Plan",
@@ -347,6 +347,18 @@
"subtitle": "Get reset link with your email:",
"title": "Forgotten Password?"
},
"page_index": {
"get_started_button": "Sign Up Now",
"menu": {
"contact_us": "Contact Us",
"log_in": "Log In",
"pricing": "Pricing",
"sign_in": "Sign Up"
},
"sign_feature_1": "No credit card required",
"sign_feature_2": "{defaultSpace} Free storage space",
"sign_up_button": "Sign Up Now"
},
"page_login": {
"button_next": "Next Step",
"placeholder_email": "Type your E-mail",
@@ -361,6 +373,7 @@
"title": "Choose Your Plan"
},
"page_registration": {
"agreement": "By clicking on 'Create Account' button I agree to the {0} and {1}.",
"button_create_account": "Create Account",
"have_an_account": "Do you have an account?",
"label_confirm_pass": "Confirm password:",

View File

@@ -347,6 +347,18 @@
"subtitle": "Získajte resetovací link pre Váš účet:",
"title": "Zabudnuté heslo?"
},
"page_index": {
"get_started_button": "Zaregistrovať sa teraz",
"menu": {
"contact_us": "Kontaktuj nás",
"log_in": "Prihlásiť sa",
"pricing": "Plány",
"sign_in": "Zaregistrovať sa"
},
"sign_feature_1": "Nevyžaduje sa žiadna kreditná karta",
"sign_feature_2": "{defaultSpace} Kapacita úložiska zadarmo",
"sign_up_button": "Zaregistrovať sa teraz"
},
"page_login": {
"button_next": "Ďalší krok",
"placeholder_email": "Napíšte svoj E-mail",
@@ -361,6 +373,7 @@
"title": "Vyberte si svoj plán"
},
"page_registration": {
"agreement": "Kliknutím na tlačidlo Vytvoriť účet súhlasím s {0} a {1}.",
"button_create_account": "Vytvoriť účet",
"have_an_account": "Máš už účet?",
"label_confirm_pass": "Potvrďte heslo:",
@@ -408,7 +421,7 @@
"section_summary": "Zhrnutie objednávky",
"summary": {
"period": "Účtované mesačne",
"submit_button": "Plaťte kreditnou kartou",
"submit_button": "Zaplatiť kreditnou kartou",
"submit_disclaimer": "Odoslaním formulára súhlasíte s uložením spôsobu platby a fakturačných údajov vo svojom účte {app}."
},
"title": "Vyberte si metódu platby"

View File

@@ -38,6 +38,7 @@ import PageEdit from './views/Admin/Pages/PageEdit'
// App Settings
import AppEmail from './views/Admin/AppSettings/AppSettingsTabs/Email'
import AppIndex from './views/Admin/AppSettings/AppSettingsTabs/Index'
import AppOthers from './views/Admin/AppSettings/AppSettingsTabs/Others'
import AppBillings from './views/Admin/AppSettings/AppSettingsTabs/Billings'
import AppPayments from './views/Admin/AppSettings/AppSettingsTabs/Payments'
@@ -146,8 +147,6 @@ const routesAdmin = [
title: i18n.t('routes_title.users_list')
},
},
// Create Pages
{
name: 'UserCreate',
path: '/admin/user/create',
@@ -166,8 +165,6 @@ const routesAdmin = [
title: i18n.t('routes_title.plan_create')
},
},
// Single pages
{
name: 'User',
path: '/admin/user/:id',
@@ -289,6 +286,15 @@ const routesAdmin = [
title: i18n.t('routes_title.appearance')
},
},
{
name: 'AppIndex',
path: '/admin/settings/index',
component: AppIndex,
meta: {
requiresAuth: true,
title: 'Index'
},
},
{
name: 'AppBillings',
path: '/admin/settings/billings',

View File

@@ -4,6 +4,7 @@ const defaultState = {
fileInfoPanelVisible: localStorage.getItem('file_info_visibility') == 'true' || false,
FilePreviewType: localStorage.getItem('preview_type') || 'list',
config: undefined,
index: undefined,
authorized: undefined,
homeDirectory: undefined,
requestedPlan: undefined,
@@ -55,6 +56,9 @@ const mutations = {
SET_AUTHORIZED(state, data) {
state.authorized = data
},
SET_INDEX_CONTENT(state, data) {
state.index = data
},
CHANGE_PREVIEW(state, type) {
state.FilePreviewType = type
},
@@ -69,6 +73,7 @@ const getters = {
requestedPlan: state => state.requestedPlan,
api: state => state.config.api,
config: state => state.config,
index: state => state.index,
roles: state => state.roles,
}

View File

@@ -39,7 +39,7 @@ const actions = {
let route = getters.sharedDetail.protected
? '/api/folders/' + payload.folder.unique_id + '/private'
: '/api/folders/' + payload.folder.unique_id + '/public/' + router.currentRoute.params.token +'/'
: '/api/folders/' + payload.folder.unique_id + '/public/' + router.currentRoute.params.token
return new Promise((resolve, reject) => {
axios

View File

@@ -18,6 +18,15 @@
</div>
</router-link>
<router-link replace :to="{name: 'AppIndex'}" class="menu-list-item link">
<div class="icon">
<book-icon size="17"></book-icon>
</div>
<div class="label">
Index
</div>
</router-link>
<router-link v-if="config.isSaaS" replace :to="{name: 'AppBillings'}"
class="menu-list-item link">
<div class="icon">
@@ -67,15 +76,16 @@
</template>
<script>
import {UsersIcon, SettingsIcon, Trash2Icon, EyeIcon, FileTextIcon, CodeIcon, MailIcon, CreditCardIcon} from 'vue-feather-icons'
import {UsersIcon, SettingsIcon, Trash2Icon, EyeIcon, FileTextIcon, CodeIcon, MailIcon, CreditCardIcon, BookIcon} from 'vue-feather-icons'
import MobileHeader from '@/components/Mobile/MobileHeader'
import SectionTitle from '@/components/Others/SectionTitle'
import PageHeader from '@/components/Others/PageHeader'
import { mapGetters } from 'vuex'
import {mapGetters} from 'vuex'
export default {
name: 'AppSettings',
components: {
BookIcon,
CreditCardIcon,
CodeIcon,
MailIcon,

View File

@@ -0,0 +1,401 @@
<template>
<PageTab :is-loading="isLoading" class="form-fixed-width">
<PageTabGroup>
<div class="form block-form">
<!--Header-->
<div>
<FormLabel>Header Title</FormLabel>
<div class="block-wrapper">
<img src="/assets/images/admin/main-header.jpg" alt="Main Header" class="page-image">
</div>
<div class="block-wrapper">
<label>Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<input @input="$updateText('/settings', 'header_title', header_title)" v-model="header_title"
type="text"
:class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
<textarea @input="$updateText('/settings', 'header_description', header_description)" rows="2" v-model="header_description"
:class="{'is-error': errors[0]}"></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
<!--Features title-->
<div>
<FormLabel class="mt-70">Features Title</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">
Show section:
</label>
</div>
<SwitchInput
@input="$updateText('/settings', 'section_features', section_features)"
v-model="section_features"
class="switch"
:state="section_features"
/>
</div>
</div>
</div>
<div v-if="section_features">
<div class="block-wrapper">
<img src="/assets/images/admin/main-features.jpg" alt="Main Features" class="page-image">
</div>
<div class="block-wrapper">
<label>Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<input @input="$updateText('/settings', 'features_title', features_title)" v-model="features_title"
type="text"
:class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
<textarea @input="$updateText('/settings', 'features_description', features_description)" rows="2" v-model="features_description"
:class="{'is-error': errors[0]}"></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
</div>
<!--Feature boxes-->
<div>
<FormLabel class="mt-70">Feature Boxes</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">
Show section:
</label>
</div>
<SwitchInput
@input="$updateText('/settings', 'section_feature_boxes', section_feature_boxes)"
v-model="section_feature_boxes"
class="switch"
:state="section_feature_boxes"
/>
</div>
</div>
</div>
<div v-if="section_feature_boxes">
<div class="block-wrapper">
<img src="/assets/images/admin/feature-boxes.jpg" alt="Main Features" class="page-image">
</div>
<div class="block-wrapper">
<label>First Box Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Title 1" rules="required" v-slot="{ errors }">
<input @input="$updateText('/settings', 'feature_title_1', feature_title_1)" v-model="feature_title_1"
type="text"
:class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>First Box Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Description 1" rules="required" v-slot="{ errors }">
<textarea @input="$updateText('/settings', 'feature_description_1', feature_description_1)" rows="2" v-model="feature_description_1"
:class="{'is-error': errors[0]}"></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Second Box Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Title 2" rules="required" v-slot="{ errors }">
<input @input="$updateText('/settings', 'feature_title_2', feature_title_2)" v-model="feature_title_2"
type="text"
:class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Second Box Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Description 2" rules="required" v-slot="{ errors }">
<textarea @input="$updateText('/settings', 'feature_description_2', feature_description_2)" rows="2" v-model="feature_description_2"
:class="{'is-error': errors[0]}"></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Third Box Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Title 3" rules="required" v-slot="{ errors }">
<input @input="$updateText('/settings', 'feature_title_3', feature_title_3)" v-model="feature_title_3"
type="text"
:class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Third Box Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Description 3" rules="required" v-slot="{ errors }">
<textarea @input="$updateText('/settings', 'feature_description_3', feature_description_3)" rows="2" v-model="feature_description_3"
:class="{'is-error': errors[0]}"></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
</div>
<!--Pricing Content-->
<div>
<FormLabel class="mt-70">Pricing Content</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">
Show section:
</label>
</div>
<SwitchInput
@input="$updateText('/settings', 'section_pricing_content', section_pricing_content)"
v-model="section_pricing_content"
class="switch"
:state="section_pricing_content"
/>
</div>
</div>
</div>
<div v-if="section_pricing_content">
<div class="block-wrapper">
<img src="/assets/images/admin/pricing-content.jpg" alt="Main Features" class="page-image">
</div>
<div class="block-wrapper">
<label>Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<input @input="$updateText('/settings', 'pricing_title', pricing_title)" v-model="pricing_title"
type="text"
:class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
<textarea @input="$updateText('/settings', 'pricing_description', pricing_description)" rows="2" v-model="pricing_description"
:class="{'is-error': errors[0]}"></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
</div>
<!--Get Started-->
<div>
<FormLabel class="mt-70">Get Started Content</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label">
Show section:
</label>
</div>
<SwitchInput
@input="$updateText('/settings', 'section_get_started', section_get_started)"
v-model="section_get_started"
class="switch"
:state="section_get_started"
/>
</div>
</div>
</div>
<div v-if="section_get_started">
<div class="block-wrapper">
<img src="/assets/images/admin/get-started-content.jpg" alt="Main Features" class="page-image">
</div>
<div class="block-wrapper">
<label>Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<input @input="$updateText('/settings', 'get_started_title', get_started_title)" v-model="get_started_title"
type="text"
:class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
<textarea @input="$updateText('/settings', 'get_started_description', get_started_description)" rows="2" v-model="get_started_description"
:class="{'is-error': errors[0]}"></textarea>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
</div>
<!--Footer-->
<div>
<FormLabel class="mt-70">Footer</FormLabel>
<div class="block-wrapper">
<label>Footer content:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<input @input="$updateText('/settings', 'footer_content', footer_content)" v-model="footer_content"
type="text"
:class="{'is-error': errors[0]}"/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
</div>
</PageTabGroup>
</PageTab>
</template>
<script>
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
import StorageItemDetail from '@/components/Others/StorageItemDetail'
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import SelectInput from '@/components/Others/Forms/SelectInput'
import SwitchInput from '@/components/Others/Forms/SwitchInput'
import ImageInput from '@/components/Others/Forms/ImageInput'
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'
import axios from 'axios'
export default {
name: 'AppIndex',
components: {
ValidationObserver,
ValidationProvider,
StorageItemDetail,
PageTabGroup,
SwitchInput,
SelectInput,
ImageInput,
ButtonBase,
FormLabel,
SetupBox,
required,
PageTab,
InfoBox,
},
data() {
return {
isLoading: true,
section_features: 1,
section_feature_boxes: 1,
section_pricing_content: 1,
section_get_started: 1,
header_title: '',
header_description: '',
features_title: '',
features_description: '',
feature_title_1: '',
feature_description_1: '',
feature_title_2: '',
feature_description_2: '',
feature_title_3: '',
feature_description_3: '',
pricing_title: '',
pricing_description: '',
get_started_title: '',
get_started_description: '',
footer_content: '',
}
},
mounted() {
axios.get('/api/settings', {
params: {
column: 'footer_content|get_started_description|get_started_title|pricing_description|pricing_title|feature_description_3|feature_title_3|feature_description_2|feature_title_2|feature_description_1|feature_title_1|features_description|features_title|header_description|header_title|section_get_started|section_pricing_content|section_feature_boxes|section_features'
}
})
.then(response => {
this.section_features = parseInt(response.data.section_features)
this.section_feature_boxes = parseInt(response.data.section_feature_boxes)
this.section_pricing_content = parseInt(response.data.section_pricing_content)
this.section_get_started = parseInt(response.data.section_get_started)
this.header_title = response.data.header_title
this.header_description = response.data.header_description
this.features_title = response.data.features_title
this.features_description = response.data.features_description
this.feature_title_1 = response.data.feature_title_1
this.feature_description_1 = response.data.feature_description_1
this.feature_title_2 = response.data.feature_title_2
this.feature_description_2 = response.data.feature_description_2
this.feature_title_3 = response.data.feature_title_3
this.feature_description_3 = response.data.feature_description_3
this.pricing_title = response.data.pricing_title
this.pricing_description = response.data.pricing_description
this.get_started_title = response.data.get_started_title
this.get_started_description = response.data.get_started_description
this.footer_content = response.data.footer_content
})
.finally(() => {
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/_forms';
.block-form {
max-width: 100%;
}
.page-image {
width: 100%;
margin: 0 auto;
display: block;
border-radius: 8px;
box-shadow: 0 7px 25px rgba(25, 54, 60, 0.1);
}
</style>

View File

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

View File

@@ -53,12 +53,10 @@
</div>
<div>
<p class="legal-agreement">
By clicking on 'Create Account' button I agree to the
<i18n path="page_registration.agreement" tag="p" class="legal-agreement">
<router-link :to="{name: 'DynamicPage', params: {slug: 'terms-of-service'}}" target="_blank">Terms of Service</router-link>
and
<router-link :to="{name: 'DynamicPage', params: {slug: 'privacy-policy'}}" target="_blank">Privacy Policy</router-link>.
</p>
<router-link :to="{name: 'DynamicPage', params: {slug: 'privacy-policy'}}" target="_blank">Privacy Policy</router-link>
</i18n>
<AuthButton icon="chevron-right" :text="$t('page_registration.button_create_account')" :loading="isLoading" :disabled="isLoading"/>
</div>
</ValidationObserver>

View File

@@ -1,25 +1,30 @@
<template>
<div class="landing-page">
<!--Navigation-->
<Navigation class="page-wrapper medium" />
<div v-if="! isLoading">
<!--Navigation-->
<Navigation class="page-wrapper medium" />
<!--Header-->
<PageHeader />
<!--Header-->
<PageHeader />
<!--VueFileManager ScreenShot-->
<HeroScreenshot />
<!--VueFileManager ScreenShot-->
<HeroScreenshot />
<!--Main Features-->
<MainFeatures />
<!--Main Features-->
<MainFeatures />
<!--Pricing Tables-->
<PricingTables />
<!--Pricing Tables-->
<PricingTables />
<!--Get Started Call To Action-->
<GetStarted />
<!--Get Started Call To Action-->
<GetStarted />
<!--Footer-->
<PageFooter />
<!--Footer-->
<PageFooter />
</div>
<div v-if="isLoading">
<Spinner></Spinner>
</div>
</div>
</template>
@@ -31,6 +36,7 @@
import PageHeader from '@/components/Index/IndexPageHeader'
import GetStarted from '@/components/Index/IndexGetStarted'
import PageFooter from '@/components/Index/IndexPageFooter'
import Spinner from '@/components/FilesView/Spinner'
import { mapGetters } from 'vuex'
import axios from 'axios'
@@ -44,13 +50,14 @@
Navigation,
PageHeader,
PageFooter,
Spinner,
},
computed: {
...mapGetters(['config']),
},
data() {
return {
isLoading: false,
isLoading: true,
}
},
beforeMount() {
@@ -58,6 +65,20 @@
this.$router.push({name: 'SignIn'})
}
},
mounted() {
// Get page content
axios.get('/api/content', {
params: {
column: 'footer_content|get_started_description|get_started_title|pricing_description|pricing_title|feature_description_3|feature_title_3|feature_description_2|feature_title_2|feature_description_1|feature_title_1|features_description|features_title|header_description|header_title|section_get_started|section_pricing_content|section_feature_boxes|section_features'
}
})
.then(response => {
this.$store.commit('SET_INDEX_CONTENT', response.data)
})
.finally(() => {
this.isLoading = false
})
},
created() {
this.$scrollTop()
}

View File

@@ -20,7 +20,7 @@
<!-- Pay by new credit card -->
<div class="register-card" v-show="! defaultPaymentMethod || payByNewCard">
<p class="payment-demo-disclaimer">
For test your payment please use <b>4242 4242 4242 4242</b> as a card number, <b>11/22</b>
For test your payment please use <b>4242 4242 4242 4242</b> or <b>5555555555554444</b> as a card number, <b>11/22</b>
as the expiration date and <b>123</b> as CVC number and ZIP <b>12345</b>.
</p>

View File

@@ -29,27 +29,32 @@
<script>
let config = {
host: '{{ url('/') }}',
api: '{{ url('/api') }}',
locale: '{{ \Illuminate\Support\Facades\App::getLocale() }}',
app_name: '{{ isset($settings->app_title) && $settings->app_title ? $settings->app_title : 'VueFileManager' }}',
app_description: '{{ isset($settings->app_description) && $settings->app_description ? $settings->app_description : 'Your self-hosted storage cloud software powered by Laravel and Vue' }}',
app_footer: '{!! isset($settings->footer_content) && $settings->footer_content ? $settings->footer_content : null !!}',
app_logo: '{{ isset($settings->app_logo) && $settings->app_logo ? $settings->app_logo : null }}',
app_logo_horizontal: '{{ isset($settings->app_logo_horizontal) && $settings->app_logo_horizontal ? $settings->app_logo_horizontal : null }}',
app_payments_active: {{ isset($settings->payments_active) ? $settings->payments_active : 0 }},
host: '{{ url('/') }}',
api: '{{ url('/api') }}',
stripe_public_key: '{{ config('cashier.key') ? config('cashier.key') : null }}',
userRegistration: {{ isset($settings->registration) ? $settings->registration : 1 }},
storageLimit: {{ isset($settings->storage_limitation) ? $settings->storage_limitation : 1 }},
storageDefaultSpace: '{{ isset($settings->storage_default) ? format_gigabytes($settings->storage_default) : 5 }}',
hasAuthCookie: {{ Cookie::has('token') ? 1 : 0 }},
isSaaS: {{ isset($settings->license) && $settings->license === 'Extended' ? 1 : 0 }},
isDemo: {{ env('APP_DEMO') ? 1 : 0 }},
legal: {!! $legal !!},
installation: '{{ $installation }}',
}
</script>

View File

@@ -65,6 +65,7 @@ Route::group(['middleware' => ['api']], function () {
// Pages
Route::post('/contact', 'AppFunctionsController@contact_form');
Route::get('/page/{slug}', 'AppFunctionsController@get_page');
Route::get('/content', 'AppFunctionsController@get_settings');
});
// User master Routes

View File

@@ -1 +0,0 @@
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

@@ -1 +1 @@
1594538596i:1594538596;
1594625474i:1594625474;

View File

@@ -1 +0,0 @@
9999999999a:2:{s:4:"plan";a:20:{s:2:"id";s:9:"uber-pack";s:6:"object";s:4:"plan";s:6:"active";b:0;s:15:"aggregate_usage";N;s:6:"amount";i:9990;s:14:"amount_decimal";s:4:"9990";s:14:"billing_scheme";s:8:"per_unit";s:7:"created";i:1594221277;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_HbskYkFaOAiNik";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_HbskYkFaOAiNik";s:6:"object";s:7:"product";s:6:"active";b:1;s:10:"attributes";a:0:{}s:7:"created";i:1594221277;s:11:"description";s:19:"For your best needs";s:6:"images";a:0:{}s:8:"livemode";b:0;s:8:"metadata";a:1:{s:8:"capacity";s:5:"10000";}s:4:"name";s:9:"Uber Pack";s:20:"statement_descriptor";N;s:4:"type";s:7:"service";s:10:"unit_label";N;s:7:"updated";i:1594221277;}}

View File

@@ -1 +1 @@
1594538596i:1;
1594625474i:1;

View File

@@ -1 +0,0 @@
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;}}